mDNSMacOSX/*.xcodeproj/project.xcworkspace
mDNSMacOSX/*.xcodeproj/xcuserdata
.svn
+.DS_Store
build
+objects
*~.m
*~.c
*~.h
+*~
+++ /dev/null
-/* -*- 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.
- */
-
-#include "CDNSSDService.h"
-#include "nsThreadUtils.h"
-#include "nsIEventTarget.h"
-#include "private/pprio.h"
-#include <string>
-#include <stdio.h>
-
-
-NS_IMPL_ISUPPORTS2(CDNSSDService, IDNSSDService, nsIRunnable)
-
-CDNSSDService::CDNSSDService()
-:
- m_master( 1 ),
- m_threadPool( NULL ),
- m_mainRef( NULL ),
- m_subRef( NULL ),
- m_listener( NULL ),
- m_fileDesc( NULL ),
- m_job( NULL )
-{
- nsresult err;
-
- if ( DNSServiceCreateConnection( &m_mainRef ) != kDNSServiceErr_NoError )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- if ( ( m_fileDesc = PR_ImportTCPSocket( DNSServiceRefSockFD( m_mainRef ) ) ) == NULL )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- if ( ( m_threadPool = PR_CreateThreadPool( 1, 1, 8192 ) ) == NULL )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- err = SetupNotifications();
-
-exit:
-
- if ( err != NS_OK )
- {
- Cleanup();
- }
-}
-
-
-CDNSSDService::CDNSSDService( DNSServiceRef ref, nsISupports * listener )
-:
- m_master( 0 ),
- m_threadPool( NULL ),
- m_mainRef( ref ),
- m_subRef( ref ),
- m_listener( listener ),
- m_fileDesc( NULL ),
- m_job( NULL )
-{
-}
-
-
-CDNSSDService::~CDNSSDService()
-{
- Cleanup();
-}
-
-
-void
-CDNSSDService::Cleanup()
-{
- if ( m_master )
- {
- if ( m_job )
- {
- PR_CancelJob( m_job );
- m_job = NULL;
- }
-
- if ( m_threadPool != NULL )
- {
- PR_ShutdownThreadPool( m_threadPool );
- m_threadPool = NULL;
- }
-
- if ( m_fileDesc != NULL )
- {
- PR_Close( m_fileDesc );
- m_fileDesc = NULL;
- }
-
- if ( m_mainRef )
- {
- DNSServiceRefDeallocate( m_mainRef );
- m_mainRef = NULL;
- }
- }
- else
- {
- if ( m_subRef )
- {
- DNSServiceRefDeallocate( m_subRef );
- m_subRef = NULL;
- }
- }
-}
-
-
-nsresult
-CDNSSDService::SetupNotifications()
-{
- NS_PRECONDITION( m_threadPool != NULL, "m_threadPool is NULL" );
- NS_PRECONDITION( m_fileDesc != NULL, "m_fileDesc is NULL" );
- NS_PRECONDITION( m_job == NULL, "m_job is not NULL" );
-
- m_iod.socket = m_fileDesc;
- m_iod.timeout = PR_INTERVAL_MAX;
- m_job = PR_QueueJob_Read( m_threadPool, &m_iod, Read, this, PR_FALSE );
- return ( m_job ) ? NS_OK : NS_ERROR_FAILURE;
-}
-
-
-/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
-NS_IMETHODIMP
-CDNSSDService::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
- CDNSSDService * service = NULL;
- DNSServiceErrorType dnsErr = 0;
- nsresult err = 0;
-
- *_retval = NULL;
-
- if ( !m_mainRef )
- {
- err = NS_ERROR_NOT_AVAILABLE;
- goto exit;
- }
-
- try
- {
- service = new CDNSSDService( m_mainRef, listener );
- }
- catch ( ... )
- {
- service = NULL;
- }
-
- if ( service == NULL )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- dnsErr = DNSServiceBrowse( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceBrowseReply ) BrowseReply, service );
-
- if ( dnsErr != kDNSServiceErr_NoError )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- listener->AddRef();
- service->AddRef();
- *_retval = service;
- err = NS_OK;
-
-exit:
-
- if ( err && service )
- {
- delete service;
- service = NULL;
- }
-
- return err;
-}
-
-
-/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
-NS_IMETHODIMP
-CDNSSDService::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
- CDNSSDService * service;
- DNSServiceErrorType dnsErr;
- nsresult err;
-
- *_retval = NULL;
-
- if ( !m_mainRef )
- {
- err = NS_ERROR_NOT_AVAILABLE;
- goto exit;
- }
-
- try
- {
- service = new CDNSSDService( m_mainRef, listener );
- }
- catch ( ... )
- {
- service = NULL;
- }
-
- if ( service == NULL )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- dnsErr = DNSServiceResolve( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( name ).get(), NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceResolveReply ) ResolveReply, service );
-
- if ( dnsErr != kDNSServiceErr_NoError )
- {
- err = NS_ERROR_FAILURE;
- goto exit;
- }
-
- listener->AddRef();
- service->AddRef();
- *_retval = service;
- err = NS_OK;
-
-exit:
-
- if ( err && service )
- {
- delete service;
- service = NULL;
- }
-
- return err;
-}
-
-
-/* void stop (); */
-NS_IMETHODIMP
-CDNSSDService::Stop()
-{
- if ( m_subRef )
- {
- DNSServiceRefDeallocate( m_subRef );
- m_subRef = NULL;
- }
-
- return NS_OK;
-}
-
-
-void
-CDNSSDService::Read( void * arg )
-{
- NS_PRECONDITION( arg != NULL, "arg is NULL" );
-
- NS_DispatchToMainThread( ( CDNSSDService* ) arg );
-}
-
-
-NS_IMETHODIMP
-CDNSSDService::Run()
-{
- nsresult err = NS_OK;
-
- NS_PRECONDITION( m_mainRef != NULL, "m_mainRef is NULL" );
-
- m_job = NULL;
-
- if ( PR_Available( m_fileDesc ) > 0 )
- {
- if ( DNSServiceProcessResult( m_mainRef ) != kDNSServiceErr_NoError )
- {
- err = NS_ERROR_FAILURE;
- }
- }
-
- if ( !err )
- {
- err = SetupNotifications();
- }
-
- return err;
-}
-
-
-void DNSSD_API
-CDNSSDService::BrowseReply
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * serviceName,
- const char * regtype,
- const char * replyDomain,
- void * context
- )
-{
- CDNSSDService * self = ( CDNSSDService* ) context;
-
- // This should never be NULL, but let's be defensive.
-
- if ( self != NULL )
- {
- IDNSSDBrowseListener * listener = ( IDNSSDBrowseListener* ) self->m_listener;
-
- // Same for this
-
- if ( listener != NULL )
- {
- listener->OnBrowse( self, ( flags & kDNSServiceFlagsAdd ) ? PR_TRUE : PR_FALSE, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( serviceName ), NS_ConvertUTF8toUTF16( regtype ), NS_ConvertUTF8toUTF16( replyDomain ) );
- }
- }
-}
-
-
-void DNSSD_API
-CDNSSDService::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
- )
-{
- CDNSSDService * self = ( CDNSSDService* ) context;
-
- // This should never be NULL, but let's be defensive.
-
- if ( self != NULL )
- {
- IDNSSDResolveListener * listener = ( IDNSSDResolveListener* ) self->m_listener;
-
- // Same for this
-
- if ( listener != NULL )
- {
- std::string path = "";
- const void * value = NULL;
- uint8_t valueLen = 0;
-
- value = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen );
-
- if ( value && valueLen )
- {
- char * temp;
-
- temp = new char[ valueLen + 2 ];
-
- if ( temp )
- {
- char * dst = temp;
-
- memset( temp, 0, valueLen + 2 );
-
- if ( ( ( char* ) value )[ 0 ] != '/' )
- {
- *dst++ = '/';
- }
-
- memcpy( dst, value, valueLen );
- path = temp;
- delete [] temp;
- }
- }
-
- listener->OnResolve( self, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( fullname ), NS_ConvertUTF8toUTF16( hosttarget ) , ntohs( port ), NS_ConvertUTF8toUTF16( path.c_str() ) );
- }
- }
-}
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-#ifndef _CDNSSDSERVICE_H
-#define _CDNSSDSERVICE_H
-
-#include "IDNSSDService.h"
-#include "nsCOMPtr.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIThread.h"
-#include "nsIRunnable.h"
-#include "prtpool.h"
-#include <dns_sd.h>
-#include <stdio.h>
-#include <string>
-
-
-#define CDNSSDSERVICE_CONTRACTID "@apple.com/DNSSDService;1"
-#define CDNSSDSERVICE_CLASSNAME "CDNSSDService"
-#define CDNSSDSERVICE_CID { 0x944ED267, 0x465A, 0x4989, { 0x82, 0x72, 0x7E, 0xE9, 0x28, 0x6C, 0x99, 0xA5 } }
-
-
-/* Header file */
-class CDNSSDService : public IDNSSDService, nsIRunnable
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDSERVICE
-NS_DECL_NSIRUNNABLE
-
-CDNSSDService();
-CDNSSDService( DNSServiceRef mainRef, nsISupports * listener );
-
-virtual ~CDNSSDService();
-
-private:
-
-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
-Read
-(
- void * arg
-);
-
-nsresult
-SetupNotifications();
-
-void
-Cleanup();
-
-char m_master;
-PRThreadPool * m_threadPool;
-DNSServiceRef m_mainRef;
-DNSServiceRef m_subRef;
-nsISupports * m_listener;
-PRFileDesc * m_fileDesc;
-PRJobIoDesc m_iod;
-PRJob * m_job;
-};
-
-
-#endif
+++ /dev/null
-/* -*- 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.
- */
-
-#include "nsIGenericFactory.h"
-#include "CDNSSDService.h"
-
-NS_COM_GLUE nsresult
-NS_NewGenericModule2(nsModuleInfo const *info, nsIModule* *result);
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(CDNSSDService)
-
-static nsModuleComponentInfo components[] =
-{
- {
- CDNSSDSERVICE_CLASSNAME,
- CDNSSDSERVICE_CID,
- CDNSSDSERVICE_CONTRACTID,
- CDNSSDServiceConstructor,
- }
-};
-
-NS_IMPL_NSGETMODULE("CDNSSDServiceModule", components)
-
+++ /dev/null
-\r
-Microsoft Visual Studio Solution File, Format Version 9.00\r
-# Visual Studio 2005\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DNSSDService", "DNSSDService.vcproj", "{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
-EndProject\r
-Global\r
- GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
- Debug|Win32 = Debug|Win32\r
- Release|Win32 = Release|Win32\r
- EndGlobalSection\r
- GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
- {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.ActiveCfg = Debug|Win32\r
- {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.Build.0 = Debug|Win32\r
- {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.ActiveCfg = Release|Win32\r
- {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.Build.0 = Release|Win32\r
- EndGlobalSection\r
- GlobalSection(SolutionProperties) = preSolution\r
- HideSolutionNode = FALSE\r
- EndGlobalSection\r
-EndGlobal\r
+++ /dev/null
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.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 ""afxres.h""\r\n"
- "#include ""WinVersRes.h""\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", MASTER_COMPANY_NAME
- VALUE "FileDescription", "Firefox Extension Library"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "DNSSDService.dll"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "DNSSDService.dll"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="FirefoxExtension"\r
- ProjectGUID="{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"\r
- UseOfMFC="0"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="1"\r
- TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"\r
- HeaderFileName=""\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="1"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;"$(SRCROOT)\AppleInternal\XULRunner\include\xpcom";"$(SRCROOT)\AppleInternal\XULRunner\include\nspr";"$(SRCROOT)\AppleInternal\XULRunner\include\string";"$(SRCROOT)\AppleInternal\XULRunner\include\pref";"$(SRCROOT)\AppleInternal\XULRunner\sdk\include""\r
- PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"\r
- StringPooling="true"\r
- RuntimeLibrary="0"\r
- EnableFunctionLevelLinking="true"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="3"\r
- SuppressStartupBanner="true"\r
- ForcedIncludeFiles=""\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../../mDNSWindows"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
- OutputFile="$(OutDir)\DNSSDService.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- AdditionalLibraryDirectories=""\r
- ProgramDatabaseFile=".\$(OutDir)/DNSSDService.pdb"\r
- ImportLibrary=".\$(OutDir)/DNSSDService.lib"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- SuppressStartupBanner="true"\r
- OutputFile=".\$(OutDir)\DNSSDService.bsc"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components
if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension"
xcopy /E/I/Y "extension" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"\r
- UseOfMFC="0"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="1"\r
- TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"\r
- HeaderFileName=""\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;"$(SRCROOT)\AppleInternal\XULRunner\include\xpcom";"$(SRCROOT)\AppleInternal\XULRunner\include\nspr";"$(SRCROOT)\AppleInternal\XULRunner\include\string";"$(SRCROOT)\AppleInternal\XULRunner\include\pref";"$(SRCROOT)\AppleInternal\XULRunner\sdk\include""\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="3"\r
- SuppressStartupBanner="true"\r
- DebugInformationFormat="3"\r
- ForcedIncludeFiles=""\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../../mDNSWindows"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
- OutputFile="$(OutDir)\DNSSDService.dll"\r
- LinkIncremental="2"\r
- SuppressStartupBanner="true"\r
- AdditionalLibraryDirectories=""\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile=".\$(OutDir)\DNSSDService.pdb"\r
- ImportLibrary=".\$(OutDir)/DNSSDService.lib"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- SuppressStartupBanner="true"\r
- OutputFile=".\$(OutDir)\DNSSDService.bsc"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
- >\r
- <File\r
- RelativePath=".\CDNSSDService.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\CDNSSDServiceModule.cpp"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl"\r
- >\r
- <File\r
- RelativePath=".\CDNSSDService.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\IDNSSDService.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="IDL"\r
- Filter="idl"\r
- >\r
- <File\r
- RelativePath=".\IDNSSDService.idl"\r
- >\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
- >\r
- <File\r
- RelativePath=".\FirefoxExtension.rc"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{7826EA27-D4CC-4FAA-AD23-DF813823227B}</ProjectGuid>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>false</UseOfMfc>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>false</UseOfMfc>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">DNSSDService</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">DNSSDService</TargetName>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <TypeLibraryName>.\$(OutDir)DNSSDService.tlb</TypeLibraryName>\r
- <HeaderFileName>\r
- </HeaderFileName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom;$(SRCROOT)\AppleInternal\XULRunner\include\nspr;$(SRCROOT)\AppleInternal\XULRunner\include\string;$(SRCROOT)\AppleInternal\XULRunner\include\pref;$(SRCROOT)\AppleInternal\XULRunner\sdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <FunctionLevelLinking>true</FunctionLevelLinking>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ObjectFileName>$(IntDir)</ObjectFileName>\r
- <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level3</WarningLevel>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>../../mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib;ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)DNSSDService.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
- <ProgramDatabaseFile>.\$(OutDir)DNSSDService.pdb</ProgramDatabaseFile>\r
- <ImportLibrary>.\$(OutDir)DNSSDService.lib</ImportLibrary>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- <Bscmake>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <OutputFile>.\$(OutDir)DNSSDService.bsc</OutputFile>\r
- </Bscmake>\r
- <PostBuildEvent>\r
- <Command>xcopy /I/Y $(Platform)\$(Configuration)\DNSSDService.dll extension\platform\WINNT\components\r
-if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\FirefoxExtension" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\FirefoxExtension"\r
-xcopy /E/I/Y "extension" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\FirefoxExtension"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <TypeLibraryName>.\$(OutDir)DNSSDService.tlb</TypeLibraryName>\r
- <HeaderFileName>\r
- </HeaderFileName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom;$(SRCROOT)\AppleInternal\XULRunner\include\nspr;$(SRCROOT)\AppleInternal\XULRunner\include\string;$(SRCROOT)\AppleInternal\XULRunner\include\pref;$(SRCROOT)\AppleInternal\XULRunner\sdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ObjectFileName>$(IntDir)</ObjectFileName>\r
- <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level3</WarningLevel>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>../../mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib;ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)DNSSDService.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>.\$(OutDir)DNSSDService.pdb</ProgramDatabaseFile>\r
- <ImportLibrary>.\$(OutDir)DNSSDService.lib</ImportLibrary>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- <Bscmake>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <OutputFile>.\$(OutDir)DNSSDService.bsc</OutputFile>\r
- </Bscmake>\r
- <PostBuildEvent>\r
- <Command>xcopy /I/Y $(Platform)\$(Configuration)\DNSSDService.dll extension\platform\WINNT\components</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="CDNSSDService.cpp" />\r
- <ClCompile Include="CDNSSDServiceModule.cpp" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="CDNSSDService.h" />\r
- <ClInclude Include="IDNSSDService.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <CustomBuildStep Include="IDNSSDService.idl" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="FirefoxExtension.rc" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ProjectReference Include="..\..\mDNSWindows\DLLStub\DLLStub.vcxproj">\r
- <Project>{3a2b6325-3053-4236-84bd-aa9be2e323e5}</Project>\r
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
- </ProjectReference>\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{89e57cc2-d6b1-4e68-ad57-71223df12d28}</UniqueIdentifier>\r
- <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{4d103fe8-9737-47c7-9190-6f7b5666ecf5}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl</Extensions>\r
- </Filter>\r
- <Filter Include="IDL">\r
- <UniqueIdentifier>{4dae44a8-3da8-43c0-a749-2d1e0610c66f}</UniqueIdentifier>\r
- <Extensions>idl</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{ac7dbdd1-2fe3-416d-9cab-2d663c05f252}</UniqueIdentifier>\r
- <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="CDNSSDService.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="CDNSSDServiceModule.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="CDNSSDService.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="IDNSSDService.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="FirefoxExtension.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <CustomBuildStep Include="IDNSSDService.idl">\r
- <Filter>IDL</Filter>\r
- </CustomBuildStep>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-/*
- * DO NOT EDIT. THIS FILE IS GENERATED FROM IDNSSDService.idl
- */
-
-#ifndef __gen_IDNSSDService_h__
-#define __gen_IDNSSDService_h__
-
-
-#ifndef __gen_nsISupports_h__
-#include "nsISupports.h"
-#endif
-
-/* For IDL files that don't want to include root IDL files. */
-#ifndef NS_NO_VTABLE
-#define NS_NO_VTABLE
-#endif
-class IDNSSDService; /* forward declaration */
-
-
-/* starting interface: IDNSSDBrowseListener */
-#define IDNSSDBROWSELISTENER_IID_STR "27346495-a1ed-458a-a5bc-587df9a26b4f"
-
-#define IDNSSDBROWSELISTENER_IID \
- {0x27346495, 0xa1ed, 0x458a, \
- { 0xa5, 0xbc, 0x58, 0x7d, 0xf9, 0xa2, 0x6b, 0x4f }}
-
-class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDBrowseListener : public nsISupports {
-public:
-
-NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDBROWSELISTENER_IID)
-
-/* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */
-NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain) = 0;
-
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDBrowseListener, IDNSSDBROWSELISTENER_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_IDNSSDBROWSELISTENER \
- NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString &serviceName, const nsAString ®type, const nsAString &domain);
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object. */
-#define NS_FORWARD_IDNSSDBROWSELISTENER(_to) \
- NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString &serviceName, const nsAString ®type, const nsAString &domain) { return _to OnBrowse(service, add, interfaceIndex, error, serviceName, regtype, domain); }
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
-#define NS_FORWARD_SAFE_IDNSSDBROWSELISTENER(_to) \
- NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString &serviceName, const nsAString ®type, const nsAString &domain) { return !_to ? NS_ERROR_NULL_POINTER : _to->OnBrowse(service, add, interfaceIndex, error, serviceName, regtype, domain); }
-
-#if 0
-/* Use the code below as a template for the implementation class for this interface. */
-
-/* Header file */
-class _MYCLASS_ : public IDNSSDBrowseListener
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDBROWSELISTENER
-
-_MYCLASS_();
-
-private:
-~_MYCLASS_();
-
-protected:
-/* additional members */
-};
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDBrowseListener)
-
-_MYCLASS_::_MYCLASS_()
-{
- /* member initializers and constructor code */
-}
-
-_MYCLASS_::~_MYCLASS_()
-{
- /* destructor code */
-}
-
-/* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */
-NS_IMETHODIMP _MYCLASS_::OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain)
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* End of implementation class template. */
-#endif
-
-
-/* starting interface: IDNSSDResolveListener */
-#define IDNSSDRESOLVELISTENER_IID_STR "6620e18f-47f3-47c6-941f-126a5fd4fcf7"
-
-#define IDNSSDRESOLVELISTENER_IID \
- {0x6620e18f, 0x47f3, 0x47c6, \
- { 0x94, 0x1f, 0x12, 0x6a, 0x5f, 0xd4, 0xfc, 0xf7 }}
-
-class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDResolveListener : public nsISupports {
-public:
-
-NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDRESOLVELISTENER_IID)
-
-/* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */
-NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path) = 0;
-
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDResolveListener, IDNSSDRESOLVELISTENER_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_IDNSSDRESOLVELISTENER \
- NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString &fullname, const nsAString &host, PRInt16 port, const nsAString &path);
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object. */
-#define NS_FORWARD_IDNSSDRESOLVELISTENER(_to) \
- NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString &fullname, const nsAString &host, PRInt16 port, const nsAString &path) { return _to OnResolve(service, interfaceIndex, error, fullname, host, port, path); }
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
-#define NS_FORWARD_SAFE_IDNSSDRESOLVELISTENER(_to) \
- NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString &fullname, const nsAString &host, PRInt16 port, const nsAString &path) { return !_to ? NS_ERROR_NULL_POINTER : _to->OnResolve(service, interfaceIndex, error, fullname, host, port, path); }
-
-#if 0
-/* Use the code below as a template for the implementation class for this interface. */
-
-/* Header file */
-class _MYCLASS_ : public IDNSSDResolveListener
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDRESOLVELISTENER
-
-_MYCLASS_();
-
-private:
-~_MYCLASS_();
-
-protected:
-/* additional members */
-};
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDResolveListener)
-
-_MYCLASS_::_MYCLASS_()
-{
- /* member initializers and constructor code */
-}
-
-_MYCLASS_::~_MYCLASS_()
-{
- /* destructor code */
-}
-
-/* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */
-NS_IMETHODIMP _MYCLASS_::OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path)
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* End of implementation class template. */
-#endif
-
-
-/* starting interface: IDNSSDService */
-#define IDNSSDSERVICE_IID_STR "3a3539ff-f8d8-40b4-8d02-5ea73c51fa12"
-
-#define IDNSSDSERVICE_IID \
- {0x3a3539ff, 0xf8d8, 0x40b4, \
- { 0x8d, 0x02, 0x5e, 0xa7, 0x3c, 0x51, 0xfa, 0x12 }}
-
-class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDService : public nsISupports {
-public:
-
-NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDSERVICE_IID)
-
-/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
-NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;
-
-/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
-NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;
-
-/* void stop (); */
-NS_SCRIPTABLE NS_IMETHOD Stop(void) = 0;
-
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDService, IDNSSDSERVICE_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_IDNSSDSERVICE \
- NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString ®type, const nsAString &domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM); \
- NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString &name, const nsAString ®type, const nsAString &domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM); \
- NS_SCRIPTABLE NS_IMETHOD Stop(void);
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object. */
-#define NS_FORWARD_IDNSSDSERVICE(_to) \
- NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString ®type, const nsAString &domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return _to Browse(interfaceIndex, regtype, domain, listener, _retval); } \
- NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString &name, const nsAString ®type, const nsAString &domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return _to Resolve(interfaceIndex, name, regtype, domain, listener, _retval); } \
- NS_SCRIPTABLE NS_IMETHOD Stop(void) { return _to Stop(); }
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
-#define NS_FORWARD_SAFE_IDNSSDSERVICE(_to) \
- NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString ®type, const nsAString &domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to->Browse(interfaceIndex, regtype, domain, listener, _retval); } \
- NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString &name, const nsAString ®type, const nsAString &domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to->Resolve(interfaceIndex, name, regtype, domain, listener, _retval); } \
- NS_SCRIPTABLE NS_IMETHOD Stop(void) { return !_to ? NS_ERROR_NULL_POINTER : _to->Stop(); }
-
-#if 0
-/* Use the code below as a template for the implementation class for this interface. */
-
-/* Header file */
-class _MYCLASS_ : public IDNSSDService
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDSERVICE
-
-_MYCLASS_();
-
-private:
-~_MYCLASS_();
-
-protected:
-/* additional members */
-};
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDService)
-
-_MYCLASS_::_MYCLASS_()
-{
- /* member initializers and constructor code */
-}
-
-_MYCLASS_::~_MYCLASS_()
-{
- /* destructor code */
-}
-
-/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
-NS_IMETHODIMP _MYCLASS_::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
-NS_IMETHODIMP _MYCLASS_::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* void stop (); */
-NS_IMETHODIMP _MYCLASS_::Stop()
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* End of implementation class template. */
-#endif
-
-
-#endif /* __gen_IDNSSDService_h__ */
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-\r
- *\r
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-#include "nsISupports.idl"\r
-\r
-interface IDNSSDService;\r
-\r
-\r
-[scriptable, function, uuid(27346495-A1ED-458A-A5BC-587DF9A26B4F)]\r
-interface IDNSSDBrowseListener : nsISupports\r
-{\r
- void\r
- onBrowse( in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain );\r
-};\r
-\r
-\r
-[scriptable, function, uuid(6620E18F-47F3-47C6-941F-126A5FD4FCF7)]\r
-interface IDNSSDResolveListener : nsISupports\r
-{\r
- void\r
- onResolve( in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path );\r
-};\r
-\r
-\r
-[scriptable, uuid(3A3539FF-F8D8-40B4-8D02-5EA73C51FA12)]\r
-interface IDNSSDService : nsISupports\r
-{\r
- IDNSSDService\r
- browse( in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener );\r
-\r
- IDNSSDService\r
- resolve( in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener );\r
-\r
- void\r
- stop();\r
-};\r
+++ /dev/null
-content bonjour4firefox content/
-locale bonjour4firefox en-US locale/en-US/
-skin bonjour4firefox classic/1.0 skin/
-skin bonjour4firefox classic/1.0 skin-darwin/ os=darwin
-overlay chrome://browser/content/browser.xul chrome://bonjour4firefox/content/browserOverlay.xul
-style chrome://global/content/customizeToolbar.xul chrome://bonjour4firefox/skin/overlay.css
+++ /dev/null
-tree.sidebar-placesTree treechildren::-moz-tree-row(selected)
-{
- background-color: #6f81a9;
- background-image: url("chrome://browser/skin/places/selected-gradient.png");
- background-repeat: repeat-x;
- background-position: bottom left;
- border-top: 1px solid #979797;
-}
-
-
-tree.sidebar-placesTree treechildren::-moz-tree-separator
-{
- border-top: 1px solid #505d6d;
- margin: 0 10px;
-}
-
+++ /dev/null
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
-<?xml-stylesheet href="browseList.css"?>
-<!DOCTYPE page SYSTEM "chrome://bonjour4firefox/locale/bonjour4firefox.dtd">
- <page
- orient="vertical"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- style="background-color: transparent !important; -moz-appearance: none !important;"
- onload="BonjourBrowser.init()"
- onunload="BonjourBrowser.cleanup()">
-
-
- <menupopup id="targetmenu">
- <menuitem label="&bonjour4firefoxSidebarOpenDefault.label;" value="current"/>
- <menuitem label="&bonjour4firefoxSidebarOpenTab.label;" value="tab"/>
- <menuitem label="&bonjour4firefoxSidebarOpenWindow.label;" value="window"/>
- </menupopup>
-
- <tree id="treeBrowseList" flex="1" class="sidebar-placesTree" hidecolumnpicker="true">
- <treecols hide="true">
- <treecol id="title" flex="1" primary="true" hideheader="true"/>
- </treecols>
-
- <treechildren class="sidebar-placesTreechildren" context="targetmenu" flex="1" id="treeChildrenBrowseList">
- <treeitem>
- <treerow>
- <treecell src="chrome://bonjour4firefox/content/_internal_bonjour4firefox.png" label="About Bonjour"/>
- </treerow>
- </treeitem>
- </treechildren>
- </tree>
-
- <script><![CDATA[
-
- var BonjourBrowser =
- {
- Service: null,
- Browse: null,
- BrowseListener: null,
- Resolve: null,
- ResolveListener: null,
-
- init: function()
- {
- document.getElementById("treeChildrenBrowseList").addEventListener( "click", this.listListener, false );
-
- try
- {
- netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
- const cid = "@apple.com/DNSSDService;1";
- Service = Components.classes[cid].createInstance();
- Service = Service.QueryInterface(Components.interfaces.IDNSSDService);
- }
- catch (err)
- {
- alert(err);
- return;
- }
-
- BrowseListener = this.browseListener;
- ResolveListener = this.resolveListener;
-
- try
- {
- Browse = Service.browse(0, "_http._tcp", "", BrowseListener );
- }
- catch ( err )
- {
- alert( err );
- return;
- }
- },
-
- cleanup: function()
- {
- if ( Browse != null )
- {
- Browse.stop();
- Browse = null;
- }
- },
-
-
- browseListener: function( service, add, interfaceIndex, error, serviceName, regtype, domain )
- {
- if ( error == 0 )
- {
- // First see if we can look this guy up
-
- var treeView = document.getElementById( 'treeChildrenBrowseList' );
- var treeItem = null;
-
- for ( i = 1; i < treeView.childNodes.length; i++ )
- {
- var ti = treeView.childNodes[ i ];
- var tr = ti.childNodes[ 0 ];
- var tc = tr.childNodes[ 0 ];
-
- if ( tc.getAttribute( 'label' ) == serviceName )
- {
- treeItem = ti;
- break;
- }
- }
-
- if ( add )
- {
- // If we've already seen this guy, then bump up his reference count
-
- if ( treeItem )
- {
- var refcnt = treeItem.getUserData( 'refcnt' );
- refcnt++;
- }
- else
- {
- var newTreeItem = document.createElement('treeitem');
- var newTreeRow = document.createElement('treerow');
- newTreeRow.setAttribute( 'properties', 'bonjourRow' );
- var newTreeCell = document.createElement('treecell');
- newTreeCell.setAttribute( 'label', serviceName );
- newTreeCell.setAttribute( 'src', 'chrome://bonjour4firefox/content/_internal_bonjour4firefox.png' );
-
- newTreeItem.appendChild( newTreeRow );
- newTreeRow.appendChild( newTreeCell );
- newTreeItem.setUserData( 'interfaceIndex', interfaceIndex, null );
- newTreeItem.setUserData( 'serviceName', serviceName, null );
- newTreeItem.setUserData( 'regtype', regtype, null );
- newTreeItem.setUserData( 'domain', domain, null );
- newTreeItem.setUserData( 'refcnt', 1, null );
-
- // Insert in alphabetical order
-
- var insertBefore = null;
-
- for ( i = 1; i < treeView.childNodes.length; i++ )
- {
- var ti = treeView.childNodes[ i ];
- var tr = ti.childNodes[ 0 ];
- var tc = tr.childNodes[ 0 ];
-
- if ( serviceName.toLowerCase() < tc.getAttribute( 'label' ).toLowerCase() )
- {
- insertBefore = ti;
- break;
- }
- }
-
- if ( insertBefore != null )
- {
- treeView.insertBefore( newTreeItem, insertBefore );
- }
- else
- {
- treeView.appendChild( newTreeItem );
- }
- }
- }
- else if ( treeItem )
- {
- var refcnt = treeItem.getUserData( 'refcnt' );
-
- if ( --refcnt == 0 )
- {
- treeView.removeChild( treeItem );
- }
- }
- }
- else
- {
- alert( 'There was an error browsing for websites: ' + error );
- }
- },
-
- listListener: function( event )
- {
- var treeBrowseList = document.getElementById( 'treeBrowseList' );
-
- if ( treeBrowseList.currentIndex == 0 )
- {
- window._content.location="http://www.apple.com/macosx/features/bonjour";
- }
- else
- {
- var item = treeBrowseList.view.getItemAtIndex(treeBrowseList.currentIndex);
-
- var interfaceIndex = item.getUserData("interfaceIndex");
- var serviceName = item.getUserData("serviceName");
- var regtype = item.getUserData("regtype");
- var domain = item.getUserData("domain");
-
- try
- {
- Resolve = Service.resolve( interfaceIndex, serviceName, regtype, domain, ResolveListener );
- }
- catch ( err )
- {
- alert( err );
- return;
- }
- }
- },
-
- resolveListener: function( service, interfaceIndex, error, fullname, host, port, path )
- {
- if ( error == 0 )
- {
- window._content.location='http://' + host + ':' + port + path;
- }
- else
- {
- alert( 'There was an error resolving ' + fullname );
- }
-
- Resolve.stop();
- },
- };
-
- ]]></script>
-</page>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://bonjour4firefox/skin/overlay.css" type="text/css"?>
-<!DOCTYPE overlay SYSTEM "chrome://bonjour4firefox/locale/bonjour4firefox.dtd">
-<overlay id="bonjour4firefox-overlay"
- xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
- <script src="overlay.js"/>
- <stringbundleset id="stringbundleset">
- <stringbundle id="bonjour4firefox-strings" src="chrome://bonjour4firefox/locale/bonjour4firefox.properties"/>
- </stringbundleset>
-
- <menupopup id="viewSidebarMenu">
- <menuitem observes="viewBonjour4FirefoxSidebar"/>
- </menupopup>
-
- <toolbarpalette id="BrowserToolbarPalette">
- <toolbarbutton id="bonjour4firefox-toolbar-button"
- label="&bonjour4firefoxToolbar.label;"
- tooltiptext="&bonjour4firefoxToolbar.tooltip;"
- oncommand="toggleSidebar('viewBonjour4FirefoxSidebar');"
- class="toolbarbutton-1 chromeclass-toolbar-additional"/>
- </toolbarpalette>
-
- <broadcasterset id="mainBroadcasterSet">
- <broadcaster id="viewBonjour4FirefoxSidebar"
- autoCheck="false"
- label="Bonjour"
- type="checkbox" group="sidebar"
- sidebarurl="chrome://bonjour4firefox/content/bonjour4firefox.xul"
- sidebartitle="&bonjour4firefox.label;"
- oncommand="toggleSidebar('viewBonjour4FirefoxSidebar');"/>
- </broadcasterset>
-</overlay>
+++ /dev/null
-var bonjour4firefox =
-{
- onLoad: function()
- {
- // initialization code
- this.initialized = true;
- this.strings = document.getElementById("bonjour4firefox-strings");
- },
- onMenuItemCommand: function(e)
- {
- var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
- promptService.alert(window, this.strings.getString("helloMessageTitle"), this.strings.getString("helloMessage"));
- },
- onToolbarButtonCommand: function(e)
- {
- // just reuse the function above. you can change this, obviously!
- bonjour4firefox.onMenuItemCommand(e);
- }
-};
-
-window.addEventListener("load", function(e) { bonjour4firefox.onLoad(e); }, false);
+++ /dev/null
-// See http://kb.mozillazine.org/Localize_extension_descriptions
-pref("extensions.bonjour4firefox@apple.com.description", "chrome://bonjour4firefox/locale/bonjour4firefox.properties");
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:em="http://www.mozilla.org/2004/em-rdf#">
- <Description about="urn:mozilla:install-manifest">
- <em:id>bonjour4firefox@apple.com</em:id>
- <em:name>Bonjour Extension for Firefox</em:name>
- <em:version>1.0</em:version>
- <em:creator>Apple Inc.</em:creator>
- <em:description>Bonjour Browsing Extension for Firefox</em:description>
- <em:iconURL>chrome://bonjour4firefox/content/_internal_bonjour4firefox.png</em:iconURL>
- <em:targetApplication>
- <Description>
- <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->
- <em:minVersion>3.5</em:minVersion>
- <em:maxVersion>3.6.*</em:maxVersion>
- </Description>
- </em:targetApplication>
- </Description>
-</RDF>
+++ /dev/null
-<!ENTITY bonjour4firefox.label "Bonjour">
-<!ENTITY bonjour4firefoxToolbar.label "Bonjour">
-<!ENTITY bonjour4firefoxToolbar.tooltip "Display Bonjour enabled websites">
-<!ENTITY bonjour4firefoxSidebarOpenDefault.label "Open in current window">
-<!ENTITY bonjour4firefoxSidebarOpenTab.label "Open in new tab">
-<!ENTITY bonjour4firefoxSidebarOpenWindow.label "Open in new window">
+++ /dev/null
-helloMessage=Hello World!
-helloMessageTitle=Hello
-prefMessage=Int Pref Value: %d
-extensions.bonjour4firefox.description=Bonjour Browsing Extension for Firefox
+++ /dev/null
-This extension was generated by the Extension Wizard at
-http://ted.mielczarek.org/code/mozilla/extensionwiz/ .
-This extension is compatible only with Firefox 1.5 and
-above. Most of the files in this package are based on
-the 'helloworld' extension from the Mozillazine Knowledge Base.
-
-You can build an XPI for installation by running the
-build.sh script located in this folder. For development
-you should do the following:
- 1. Unzip the entire contents of this package to somewhere,
- e.g, c:\dev or /home/user/dev
- 2. Put the full path to the folder (e.g. c:\dev\bonjour4firefox on
- Windows, /home/user/dev/bonjour4firefox on Linux) in a file named
- bonjour4firefox@apple.com and copy that file to
- [your profile folder]\extensions\
- 3. Restart Firefox.
-
-For more information, see the Mozillazine Knowledge Base:
-http://kb.mozillazine.org/Getting_started_with_extension_development
-
--Ted Mielczarek <ted.mielczarek@gmail.com>
+++ /dev/null
-#bonjour4firefox-hello
-{
- color: red ! important;
-}
-#bonjour4firefox-toolbar-button
-{
- list-style-image: url("chrome://bonjour4firefox/skin/_internal_toolbar-button.png");
- -moz-image-region: rect(0px 36px 23px 0px);
-}
-#bonjour4firefox-toolbar-button[disabled="true"]
-{
- -moz-image-region: rect(23px 36px 46px 0px);
-}
-#bonjour4firefox-toolbar-button:hover:active
-{
- -moz-image-region: rect(46px 36px 69px 0px);
-}
+++ /dev/null
-#bonjour4firefox-hello
-{
- color: black ! important;
-}
-#bonjour4firefox-toolbar-button
-{
- list-style-image: url("chrome://bonjour4firefox/skin/_internal_toolbar-button.png");
- -moz-image-region: rect(0px 24px 24px 0px);
-}
-#bonjour4firefox-toolbar-button:hover
-{
- -moz-image-region: rect(24px 24px 48px 0px);
-}
-[iconsize="small"] #bonjour4firefox-toolbar-button
-{
- -moz-image-region: rect( 0px 40px 16px 24px);
-}
-[iconsize="small"] #bonjour4firefox-toolbar-button:hover
-{
- -moz-image-region: rect(24px 40px 40px 24px);
-}
+++ /dev/null
-Building the Bonjour Firefox Extension on Windows
-
-There is a Visual Studio 2005 project file that will build the extension correctly as long as the Visual Studio environment is setup correctly. This code was built against the 1.9 version of the XULRunner SDK. The Visual Studio environment should be modified to add the include and lib paths of the XULRunner SDK. Specifically, the following include paths should be added to VC++ include directories:
-
-…\xulrunner-sdk\include\xpcom
-…\xulrunner-sdk\include\nspr
-…\xulrunner-sdk\include\string
-…\xulrunner-sdk\include\pref
-…\xulrunner-sdk\sdk\include
-
-The following path should be added to VC++ lib directories:
-
-…\xulrunner-sdk\lib
-
-After the code has been built, it can be installed like any other Firefox extension. Please consult Firefox extension documentation for more information on how to package and install Firefox extensions.
-
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by FirefoxExtension.rc
-//
-#define IDS_PROJNAME 100
-#define IDR_WMDMLOGGER 101
-#define IDS_LOG_SEV_INFO 201
-#define IDS_LOG_SEV_WARN 202
-#define IDS_LOG_SEV_ERROR 203
-#define IDS_LOG_DATETIME 204
-#define IDS_LOG_SRCNAME 205
-#define IDS_DEF_LOGFILE 301
-#define IDS_DEF_MAXSIZE 302
-#define IDS_DEF_SHRINKTOSIZE 303
-#define IDS_DEF_LOGENABLED 304
-#define IDS_MUTEX_TIMEOUT 401
-
-// 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 101
-#endif
-#endif
# On OS X the dns_sd library functions are included in libSystem, which is implicitly linked with every executable
# If /usr/lib/libSystem.dylib exists, then we're on OS X, so we don't need also to link the "dns_sd" shared library
+ifeq "$(DEBUG)" "1"
+DEBUGFLAGS = -g
+BUILDDIR = build/debug
+else
+DEBUGFLAGS = -Os
+BUILDDIR = build/prod
+endif
+
ifneq "$(wildcard /usr/lib/libSystem.dylib)" ""
TARGETS = build/dns-sd build/dns-sd64
LIBS =
else
TARGETS = build/dns-sd
-LIBS = -L../mDNSPosix/build/prod/ -ldns_sd
+LIBS = -L../mDNSPosix/$(BUILDDIR)/ -ldns_sd
endif
all: $(TARGETS)
mkdir build
build/dns-sd: build dns-sd.c ClientCommon.c
- $(CC) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
+ $(CC) $(SUPMAKE_CFLAGS) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
build/dns-sd64: build dns-sd.c ClientCommon.c
- $(CC) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
+ $(CC) $(SUPMAKE_CFLAGS) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
# Note, we can make a 'fat' version of dns-sd using 'lipo', as shown below, but we
# don't, because we don't want or need a 'fat' version of dns-sd, because it will
#include <errno.h> // For errno, EINTR
#include <time.h>
#include <sys/types.h> // For u_char
+#ifdef APPLE_OSX_mDNSResponder
+#include <inttypes.h> // For PRId64
+#endif // APPLE_OSX_mDNSResponder
+
+#if APPLE_OSX_mDNSResponder
+#include <xpc/xpc.h>
+#include "xpc_clients.h"
+#endif
#ifdef _WIN32
#include <winsock2.h>
#include "dns_sd_internal.h"
#include "ClientCommon.h"
+
#if TEST_NEW_CLIENTSTUB
#include "../mDNSShared/dnssd_ipc.c"
#include "../mDNSShared/dnssd_clientlib.c"
static void print_usage(const char *arg0, int print_all)
{
// Print the commonly used command line options. These are listed in "the order they have been in historically".
- fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", arg0);
- fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", arg0);
- fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", arg0);
- fprintf(stderr, "%s -B <Type> <Domain> (Browse for service instances)\n", arg0);
- fprintf(stderr, "%s -L <Name> <Type> <Domain> (Resolve a service instance)\n", arg0);
- fprintf(stderr, "%s -Q <name> <rrtype> <rrclass> (Generic query for any record type)\n", arg0);
- fprintf(stderr, "%s -Z <Type> <Domain> (Output results in Zone File format)\n", arg0);
- fprintf(stderr, "%s -G v4/v6/v4v6 <name> (Get address information for hostname)\n", arg0);
- fprintf(stderr, "%s -H (Print usage for complete command list)\n", arg0);
- fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", arg0);
+ fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", arg0);
+ fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", arg0);
+ fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", arg0);
+ fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Register Proxy)\n", arg0);
+ fprintf(stderr, "%s -B <Type> <Domain> (Browse for service instances)\n", arg0);
+ fprintf(stderr, "%s -Z <Type> <Domain> (Output results in Zone File format)\n", arg0);
+ fprintf(stderr, "%s -L <Name> <Type> <Domain> (Resolve (‘lookup’) a service instance)\n", arg0);
+ fprintf(stderr, "%s -Q <name> <rrtype> <rrclass> (Generic query for any record type)\n", arg0);
+ fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Generic query, using SuppressUnusable)\n", arg0);
+ fprintf(stderr, "%s -G v4/v6/v4v6 <hostname> (Get address information for hostname)\n", arg0);
+ fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL> (NAT Port Mapping)\n", arg0);
+ fprintf(stderr, "%s -H (Print usage for complete command list)\n", arg0);
+ fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", arg0);
+#ifdef APPLE_OSX_mDNSResponder
+ fprintf(stderr, "%s -O [-compress|-stdout](Dump the state of mDNSResponder to file / STDOUT)\n", arg0);
+#endif // APPLE_OSX_mDNSResponder
if (print_all) // Print all available options for dns-sd tool. Keep these in alphabetical order for easier maintenance.
{
fprintf(stderr, "\n");
- fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", arg0);
- fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass> (Query; reconfirming each result)\n", arg0);
- fprintf(stderr, "%s -D <name> <rrtype> <rrclass>(Validate query for any record type with DNSSEC)\n", arg0);
- fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0);
- fprintf(stderr, "%s -N (Test adding a large NULL record)\n", arg0);
- fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", arg0);
- fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Proxy)\n", arg0);
- fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", arg0);
- fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0);
- fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0);
- fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL> (NAT Port Mapping)\n", arg0);
- fprintf(stderr, "%s -ble (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
- fprintf(stderr, "%s -g v4/v6/v4v6 <name> (Validate address info for hostname with DNSSEC)\n", arg0);
- fprintf(stderr, "%s -i <Interface> (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
- fprintf(stderr, "%s -includep2p (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
- fprintf(stderr, "%s -includeAWDL (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
- fprintf(stderr, "%s -intermediates (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
- fprintf(stderr, "%s -ku (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
- fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0);
- fprintf(stderr, "%s -optional (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
- fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
- fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Equivalent to -Q with kDNSServiceFlagsSuppressUnusable set)\n", arg0);
- fprintf(stderr, "%s -tc (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
- fprintf(stderr, "%s -test (Run basic API input range tests)\n", arg0);
- fprintf(stderr, "%s -t1 (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
- fprintf(stderr, "%s -tFinder (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
- fprintf(stderr, "%s -timeout (Set kDNSServiceFlagsTimeout flag)\n", arg0);
- fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
- fprintf(stderr, "%s -autoTrigger (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
+ fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", arg0);
+ fprintf(stderr, "%s -C <name> <rrtype> <rrclass> (Query; reconfirming each result)\n", arg0);
+ fprintf(stderr, "%s -D <name> <rrtype> <rrclass> (Validate query with DNSSEC)\n", arg0);
+ fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0);
+ fprintf(stderr, "%s -N (Test adding a large NULL record)\n", arg0);
+ fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", arg0);
+ fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", arg0);
+ fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0);
+ fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0);
+ fprintf(stderr, "%s -ble (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
+ fprintf(stderr, "%s -g v4/v6/v4v6 <hostname> (Validate address info with DNSSEC)\n", arg0);
+ fprintf(stderr, "%s -i <Interface> (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
+ fprintf(stderr, "%s -includep2p (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
+ fprintf(stderr, "%s -includeAWDL (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
+ fprintf(stderr, "%s -intermediates (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
+ fprintf(stderr, "%s -ku (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
+ fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0);
+ fprintf(stderr, "%s -optional (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
+ fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
+ fprintf(stderr, "%s -tc (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
+ fprintf(stderr, "%s -test (Run basic API input range tests)\n", arg0);
+ fprintf(stderr, "%s -t1 (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
+ fprintf(stderr, "%s -tFinder (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
+ fprintf(stderr, "%s -timeout (Set kDNSServiceFlagsTimeout flag)\n", arg0);
+ fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
+ fprintf(stderr, "%s -autoTrigger (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
}
}
int unknowntype = 0;
char dnssec_status[15] = "Unknown";
char rr_type[RR_TYPE_SIZE];
- char rr_class[3];
+ char rr_class[6];
DNSServiceFlags check_flags = flags;//local flags for dnssec status checking
(void)sdref; // Unused
const unsigned char *b = (const unsigned char * )&s6->sin6_addr;
if (!if_indextoname(s6->sin6_scope_id, if_name))
snprintf(if_name, sizeof(if_name), "<%d>", s6->sin6_scope_id);
- snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
+ snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF], if_name);
}
#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
+#define MAXTXTRecordSize 8900
static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv, DNSServiceFlags flags)
{
uint16_t PortAsNumber = atoi(port);
Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
- unsigned char txt[2048] = "";
+ unsigned char txt[MAXTXTRecordSize];
+ txt[0] = '\0';
unsigned char *ptr = txt;
int i;
for (i = 0; i < argc; i++)
{
const char *p = argv[i];
+ if (ptr >= txt + sizeof(txt))
+ return kDNSServiceErr_BadParam;
*ptr = 0;
- while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
+ while (*p && *ptr < 255)
{
+ if (ptr + 1 + *ptr >= txt + sizeof(txt))
+ return kDNSServiceErr_BadParam;
if (p[0] != '\\' || p[1] == 0) { ptr[++*ptr] = *p; p+=1; }
else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; }
else { ptr[++*ptr] = p[1]; p+=2; }
return 0;
}
+#ifdef APPLE_OSX_mDNSResponder
+static void handle_state_dump_request(uint8_t if_compress_state_dump, uint8_t if_dump_to_stdout);
+#endif // APPLE_OSX_mDNSResponder
int main(int argc, char **argv)
{
DNSServiceErrorType err;
else printf("Currently running daemon (system service) is version %d.%d.%d\n", v / 10000, v / 100 % 100, v % 100);
exit(0);
}
+#ifdef APPLE_OSX_mDNSResponder
+ case 'O': {
+ // check if the user specifies the flag "-compress"
+ uint8_t if_compress_state_dump = 0;
+ uint8_t if_dump_to_stdout = 0;
+
+ if (argc > opi+1) {
+ printf("dns-sd: illegal option count\n");
+ goto Fail;
+ }
+
+ if (argc == opi+1) {
+ const char *param = argv[opi];
+ if (strcasecmp("-compress", param) == 0) {
+ if_compress_state_dump = 1;
+ } else if (strcasecmp("-stdout", param) == 0) {
+ if_dump_to_stdout = 1;
+ } else {
+ printf("dns-sd: illegal option %s \n", param);
+ goto Fail;
+ }
+ }
+ handle_state_dump_request(if_compress_state_dump, if_dump_to_stdout);
+ err = kDNSServiceErr_NoError;
+ break;
+ }
+#endif // APPLE_OSX_mDNSResponder
case 'H': goto Fail;
default: goto Fail;
}
+#ifdef APPLE_OSX_mDNSResponder
+ // state dump does not need to create DNSServiceRef, so we can return directly here without cleaning up.
+ if (operation == 'O')
+ return 0;
+#endif // APPLE_OSX_mDNSResponder
if (!client || err != kDNSServiceErr_NoError)
{
if (operation == 'H') print_usage(a0,1);
else print_usage(a0,0);
return 0;
+}
+
+#ifdef APPLE_OSX_mDNSResponder
+/*
+ * if_compress_state_dump and if_dump_to_stdout cannot be set at the same time.
+ */
+static void handle_state_dump_request(uint8_t if_compress_state_dump, uint8_t if_dump_to_stdout)
+{
+ // create xpc connection to the xpc server for log utility
+ xpc_connection_t log_utility_connection = xpc_connection_create_mach_service(kDNSLogUtilityService, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+ xpc_connection_set_event_handler(log_utility_connection, ^(xpc_object_t event){
+ printf("Connecting to %s, status: %s\n", kDNSLogUtilityService, xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ });
+ xpc_connection_resume(log_utility_connection);
+
+ // set option for the state dump
+ xpc_object_t xpc_dict = xpc_dictionary_create(NULL, NULL, 0);
+ uint64_t dump_option;
+ if (if_compress_state_dump) {
+ dump_option = full_state_with_compression;
+ }
+ else if (if_dump_to_stdout) {
+ // we pass the stdout directly to xpc server
+ dump_option = full_state_to_stdout;
+ xpc_dictionary_set_fd(xpc_dict, kDNSStateDumpFD, STDOUT_FILENO);
+ }
+ else {
+ dump_option = full_state;
+ }
+
+ xpc_dictionary_set_uint64(xpc_dict, kDNSStateDump, dump_option);
+
+ // send the request and handle the response from xpc server
+ xpc_connection_send_message_with_reply(log_utility_connection, xpc_dict, dispatch_get_main_queue(), ^(xpc_object_t recv_msg){
+ xpc_type_t msg_type = xpc_get_type(recv_msg);
+ if (msg_type != XPC_TYPE_DICTIONARY) {
+ printf("Received unexpected reply from daemon, error: \"%s\"\nUnexpected reply Contents:\n%s\n",
+ xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION), xpc_copy_description(recv_msg));
+ exit(1);
+ }
+
+ // get the response dictionary
+ uint32_t return_code = (uint32_t)xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply);
+ if (return_code != kDNSMsg_NoError) {
+ const char *error_description = xpc_dictionary_get_string(recv_msg, kDNSErrorDescription);
+ printf("XPC service returns error, description: %s\n", error_description);
+ exit(1);
+ }
+
+ // print the state information returned from the XPC server
+ if (dump_option != full_state_to_stdout) {
+ const char *path = xpc_dictionary_get_string(recv_msg, kDNSDumpFilePath);
+ printf("State Dump Is Saved to: %s\n", path);
+ }
+
+ int64_t time_used = xpc_dictionary_get_int64(recv_msg, kDNSStateDumpTimeUsed);
+ printf(" Time Used: %" PRId64 " ms\n", time_used);
+
+ xpc_release(xpc_dict);
+ exit(0);
+ });
+
+ dispatch_main();
}
+#endif // APPLE_OSX_mDNSResponder
// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
- *
- * dnsctl.c
- * Command-line tool using libdns_services.dylib
- *
- * To build only this tool, copy and paste the following on the command line:
- * On Apple 64bit Platforms ONLY OSX/iOS:
- * clang -Wall dnsctl.c /usr/lib/libdns_services.dylib -o dnsctl
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <net/if.h> // if_nametoindex()
-
-#include "dns_services.h"
-#include <xpc/xpc.h>
-#include "dns_xpc.h"
-
-//*************************************************************************************************************
-// Globals:
-//*************************************************************************************************************
-
-static const char kFilePathSep = '/';
-
-static DNSXConnRef ClientRef = NULL;
-
-static xpc_connection_t dnsctl_conn = NULL;
-
-//*************************************************************************************************************
-// Utility Funcs:
-//*************************************************************************************************************
-
-static void printtimestamp(void)
-{
- struct tm tm;
- int ms;
- static char date[16];
- static char new_date[16];
- struct timeval tv;
- gettimeofday(&tv, NULL);
- localtime_r((time_t*)&tv.tv_sec, &tm);
- ms = tv.tv_usec/1000;
- strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
- //display date only if it has changed
- if (strncmp(date, new_date, sizeof(new_date)))
- {
- printf("DATE: ---%s---\n", new_date);
- strlcpy(date, new_date, sizeof(date));
- }
- printf("%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
-}
-
-static void print_usage(const char *arg0)
-{
- fprintf(stderr, "%s USAGE: \n", arg0);
- fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters \n", arg0);
- fprintf(stderr, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy \n", arg0);
- fprintf(stderr, "%s -L [1/2/3/4] Change mDNSResponder Logging Level \n", arg0);
- fprintf(stderr, "%s -I Print mDNSResponder STATE INFO \n", arg0);
-}
-
-
-static bool DebugEnabled()
-{
- return true; // keep this true to debug the XPC msgs
-}
-
-static void DebugLog(const char *prefix, xpc_object_t o)
-{
- if (!DebugEnabled())
- return;
-
- char *desc = xpc_copy_description(o);
- printf("%s: %s \n", prefix, desc);
- free(desc);
-}
-
-//*************************************************************************************************************
-// CallBack Funcs:
-//*************************************************************************************************************
-
-
-// DNSXEnableProxy Callback from the Daemon
-static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
-{
- (void) connRef;
- printtimestamp();
- switch (errCode)
- {
- case kDNSX_NoError : printf(" SUCCESS \n");
- break;
- case kDNSX_DaemonNotRunning : printf(" NO DAEMON \n");
- DNSXRefDeAlloc(ClientRef); break;
- case kDNSX_BadParam : printf(" BAD PARAMETER \n");
- DNSXRefDeAlloc(ClientRef); break;
- case kDNSX_Busy : printf(" BUSY \n");
- DNSXRefDeAlloc(ClientRef); break;
- case kDNSX_UnknownErr :
- default : printf(" UNKNOWN ERR \n");
- DNSXRefDeAlloc(ClientRef); break;
- }
- fflush(NULL);
-
-}
-
-//*************************************************************************************************************
-// XPC Funcs:
-//*************************************************************************************************************
-
-static void Init_Connection(const char *servname)
-{
- dnsctl_conn = xpc_connection_create_mach_service(servname, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
-
- xpc_connection_set_event_handler(dnsctl_conn, ^(xpc_object_t event)
- {
- printf("InitConnection: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
- });
-
- xpc_connection_resume(dnsctl_conn);
-}
-
-static void SendDictToServer(xpc_object_t msg)
-{
-
- DebugLog("SendDictToServer Sending msg to Daemon", msg);
-
- xpc_connection_send_message_with_reply(dnsctl_conn, msg, dispatch_get_main_queue(), ^(xpc_object_t recv_msg)
- {
- xpc_type_t type = xpc_get_type(recv_msg);
-
- if (type == XPC_TYPE_DICTIONARY)
- {
- DebugLog("SendDictToServer Received reply msg from Daemon", recv_msg);
- /*
- // If we ever want to do something based on the reply of the daemon
- switch (daemon_status)
- {
- default:
- break;
- }
- */
- }
- else
- {
- printf("SendDictToServer Received unexpected reply from daemon [%s]",
- xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION));
- DebugLog("SendDictToServer Unexpected Reply contents", recv_msg);
- }
- exit(1);
- });
-}
-
-//*************************************************************************************************************
-
-int main(int argc, char **argv)
-{
- // Extract program name from argv[0], which by convention contains the path to this executable
- const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
- if (a0 == (const char *)1)
- a0 = argv[0];
-
- // Must run as root
- if (0 != geteuid())
- {
- fprintf(stderr, "%s MUST run as root!!\n", a0);
- exit(-1);
- }
- if ((sizeof(argv) == 8))
- printf("dnsctl running in 64-bit mode\n");
- else if ((sizeof(argv) == 4))
- printf("dnsctl running in 32-bit mode\n");
-
- // expects atleast one argument
- if (argc < 2)
- goto Usage;
-
- printtimestamp();
- if (!strcasecmp(argv[1], "-DP"))
- {
- DNSXErrorType err;
- // Default i/p intf is lo0 and o/p intf is primary interface
- IfIndex Ipintfs[MaxInputIf] = {1, 0, 0, 0, 0};
- IfIndex Opintf = kDNSIfindexAny;
-
- if (argc == 2)
- {
- dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
- err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
- if (err)
- fprintf(stderr, "DNSXEnableProxy returned %d\n", err);
- }
- else if (argc > 2)
- {
- argc--;
- argv++;
- if (!strcmp(argv[1], "-o"))
- {
- Opintf = if_nametoindex(argv[2]);
- if (!Opintf)
- Opintf = atoi(argv[2]);
- if (!Opintf)
- {
- fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]);
- Opintf = kDNSIfindexAny;
- }
- argc -= 2;
- argv += 2;
- }
- if (argc > 2 && !strcmp(argv[1], "-i"))
- {
- int i;
- argc--;
- argv++;
- for (i = 0; i < MaxInputIf && argc > 1; i++)
- {
- Ipintfs[i] = if_nametoindex(argv[1]);
- if (!Ipintfs[i])
- Ipintfs[i] = atoi(argv[1]);
- if (!Ipintfs[i])
- {
- fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]);
- Ipintfs[i] = 1;
- }
- argc--;
- argv++;
- }
- }
- printf("Enabling DNSProxy on mDNSResponder \n");
- dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
- err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
- if (err)
- fprintf(stderr, "DNSXEnableProxy returned %d\n", err);
- }
- }
- else if (!strcasecmp(argv[1], "-l"))
- {
- printf("Changing loglevel of mDNSResponder \n");
- Init_Connection(kDNSCTLService);
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-
- if (argc == 2)
- {
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1);
-
- SendDictToServer(dict);
- xpc_release(dict);
- dict = NULL;
- }
- else if (argc > 2)
- {
- argc--;
- argv++;
- switch (atoi(argv[1]))
- {
- case log_level1:
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1);
- break;
-
- case log_level2:
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2);
- break;
-
- case log_level3:
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level3);
- break;
-
- case log_level4:
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level4);
- break;
-
- default:
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1);
- break;
- }
- SendDictToServer(dict);
- xpc_release(dict);
- dict = NULL;
- }
- }
- else if(!strcasecmp(argv[1], "-i"))
- {
- printf("Get STATE INFO of mDNSResponder \n");
- Init_Connection(kDNSCTLService);
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- xpc_dictionary_set_uint64(dict, kDNSStateInfo, full_state);
- SendDictToServer(dict);
- xpc_release(dict);
- dict = NULL;
- }
- else if(!strcasecmp(argv[1], "-th"))
- {
- printf("Sending Test message to mDNSResponder to forward to mDNSResponderHelper\n");
- Init_Connection(kDNSCTLService);
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- xpc_dictionary_set_uint64(dict, kmDNSResponderTests, test_helper_ipc);
- SendDictToServer(dict);
- xpc_release(dict);
- dict = NULL;
- }
- else if(!strcasecmp(argv[1], "-tl"))
- {
- printf("Testing mDNSResponder Logging\n");
- Init_Connection(kDNSCTLService);
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- xpc_dictionary_set_uint64(dict, kmDNSResponderTests, test_mDNS_log);
- SendDictToServer(dict);
- xpc_release(dict);
- dict = NULL;
- }
- else
- {
- goto Usage;
- }
-
- dispatch_main();
-
-Usage:
- print_usage(a0);
- return 0;
-}
-
-/*
-
-#include <getopt.h>
-
-static int operation;
-
-static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
-{
- // Return the recognized option in optstr and the option index of the next arg.
- int o = getopt(argc, (char *const *)argv, optstr);
- *pOptInd = optind;
- return o;
-}
-
-int opindex;
-operation = getfirstoption(argc, argv, "lLDdPp", &opindex);
-if (operation == -1)
- goto Usage;
-
-
-
-switch (operation)
-{
- case 'L':
- case 'l':
- {
- printtimestamp();
- printf("Change Verbosity Level of mDNSResponder\n");
-
- Init_Connection(kDNSCTLService);
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- if (dict == NULL)
- printf("could not create the Msg Dict To Send! \n");
- xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2);
-
- SendDictToServer(dict);
-
- xpc_release(dict);
- dict = NULL;
- break;
- }
- // exit(1);
-
-}
-
-*/
-
+++ /dev/null
-/*
- Copyright (c) 2016-2018 Apple Inc. All rights reserved.
-
- dnssdutil is a command-line utility for testing the DNS-SD API.
-*/
-
-#include <CoreUtils/CommonServices.h> // Include early.
-#include <CoreUtils/AsyncConnection.h>
-#include <CoreUtils/AtomicUtils.h>
-#include <CoreUtils/CFUtils.h>
-#include <CoreUtils/CommandLineUtils.h>
-#include <CoreUtils/DataBufferUtils.h>
-#include <CoreUtils/DebugServices.h>
-#include <CoreUtils/HTTPUtils.h>
-#include <CoreUtils/JSONUtils.h>
-#include <CoreUtils/LogUtils.h>
-#include <CoreUtils/MiscUtils.h>
-#include <CoreUtils/NetUtils.h>
-#include <CoreUtils/PrintFUtils.h>
-#include <CoreUtils/RandomNumberUtils.h>
-#include <CoreUtils/SoftLinking.h>
-#include <CoreUtils/StringUtils.h>
-#include <CoreUtils/TickUtils.h>
-#include <CoreUtils/TimeUtils.h>
-#include <dns_sd.h>
-#include <dns_sd_private.h>
-
-#include CF_RUNTIME_HEADER
-
-#if( TARGET_OS_DARWIN )
- #include <CFNetwork/CFHost.h>
- #include <CoreFoundation/CoreFoundation.h>
- #include <SystemConfiguration/SCPrivate.h>
- #include <dnsinfo.h>
- #include <libproc.h>
- #include <netdb.h>
- #include <pcap.h>
- #include <spawn.h>
- #include <sys/proc_info.h>
-#endif
-
-#if( TARGET_OS_POSIX )
- #include <sys/resource.h>
-#endif
-
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
- #include "tweetnacl.h" // TweetNaCl from <https://tweetnacl.cr.yp.to/software.html>.
-#endif
-
-//===========================================================================================================================
-// Versioning
-//===========================================================================================================================
-
-#define kDNSSDUtilNumVersion NumVersionBuild( 2, 0, 0, kVersionStageBeta, 0 )
-
-#if( !MDNSRESPONDER_PROJECT && !defined( DNSSDUTIL_SOURCE_VERSION ) )
- #define DNSSDUTIL_SOURCE_VERSION "0.0.0"
-#endif
-
-//===========================================================================================================================
-// DNS-SD
-//===========================================================================================================================
-
-// DNS-SD API flag descriptors
-
-#define kDNSServiceFlagsDescriptors \
- "\x00" "AutoTrigger\0" \
- "\x01" "Add\0" \
- "\x02" "Default\0" \
- "\x03" "NoAutoRename\0" \
- "\x04" "Shared\0" \
- "\x05" "Unique\0" \
- "\x06" "BrowseDomains\0" \
- "\x07" "RegistrationDomains\0" \
- "\x08" "LongLivedQuery\0" \
- "\x09" "AllowRemoteQuery\0" \
- "\x0A" "ForceMulticast\0" \
- "\x0B" "KnownUnique\0" \
- "\x0C" "ReturnIntermediates\0" \
- "\x0D" "NonBrowsable\0" \
- "\x0E" "ShareConnection\0" \
- "\x0F" "SuppressUnusable\0" \
- "\x10" "Timeout\0" \
- "\x11" "IncludeP2P\0" \
- "\x12" "WakeOnResolve\0" \
- "\x13" "BackgroundTrafficClass\0" \
- "\x14" "IncludeAWDL\0" \
- "\x15" "Validate\0" \
- "\x16" "UnicastResponse\0" \
- "\x17" "ValidateOptional\0" \
- "\x18" "WakeOnlyService\0" \
- "\x19" "ThresholdOne\0" \
- "\x1A" "ThresholdFinder\0" \
- "\x1B" "DenyCellular\0" \
- "\x1C" "ServiceIndex\0" \
- "\x1D" "DenyExpensive\0" \
- "\x1E" "PathEvaluationDone\0" \
- "\x1F" "AllowExpiredAnswers\0" \
- "\x00"
-
-#define kDNSServiceProtocolDescriptors \
- "\x00" "IPv4\0" \
- "\x01" "IPv6\0" \
- "\x04" "UDP\0" \
- "\x05" "TCP\0" \
- "\x00"
-
-#define kBadDNSServiceRef ( (DNSServiceRef)(intptr_t) -1 )
-
-//===========================================================================================================================
-// DNS
-//===========================================================================================================================
-
-#define kDNSPort 53
-#define kDNSMaxUDPMessageSize 512
-#define kDNSMaxTCPMessageSize UINT16_MAX
-
-#define kDomainLabelLengthMax 63
-#define kDomainNameLengthMax 256
-
-#define kDNSRecordDataLengthMax UINT16_MAX
-
-typedef struct
-{
- uint8_t id[ 2 ];
- uint8_t flags[ 2 ];
- uint8_t questionCount[ 2 ];
- uint8_t answerCount[ 2 ];
- uint8_t authorityCount[ 2 ];
- uint8_t additionalCount[ 2 ];
-
-} DNSHeader;
-
-#define kDNSHeaderLength 12
-check_compile_time( sizeof( DNSHeader ) == kDNSHeaderLength );
-
-#define DNSHeaderGetID( HDR ) ReadBig16( ( HDR )->id )
-#define DNSHeaderGetFlags( HDR ) ReadBig16( ( HDR )->flags )
-#define DNSHeaderGetQuestionCount( HDR ) ReadBig16( ( HDR )->questionCount )
-#define DNSHeaderGetAnswerCount( HDR ) ReadBig16( ( HDR )->answerCount )
-#define DNSHeaderGetAuthorityCount( HDR ) ReadBig16( ( HDR )->authorityCount )
-#define DNSHeaderGetAdditionalCount( HDR ) ReadBig16( ( HDR )->additionalCount )
-
-#define DNSHeaderSetID( HDR, X ) WriteBig16( ( HDR )->id, (X) )
-#define DNSHeaderSetFlags( HDR, X ) WriteBig16( ( HDR )->flags, (X) )
-#define DNSHeaderSetQuestionCount( HDR, X ) WriteBig16( ( HDR )->questionCount, (X) )
-#define DNSHeaderSetAnswerCount( HDR, X ) WriteBig16( ( HDR )->answerCount, (X) )
-#define DNSHeaderSetAuthorityCount( HDR, X ) WriteBig16( ( HDR )->authorityCount, (X) )
-#define DNSHeaderSetAdditionalCount( HDR, X ) WriteBig16( ( HDR )->additionalCount, (X) )
-
-// Single-bit DNS header fields
-
-#define kDNSHeaderFlag_Response ( 1 << 15 ) // QR (bit 15), Query (0)/Response (1)
-#define kDNSHeaderFlag_AuthAnswer ( 1 << 10 ) // AA (bit 10), Authoritative Answer
-#define kDNSHeaderFlag_Truncation ( 1 << 9 ) // TC (bit 9), TrunCation
-#define kDNSHeaderFlag_RecursionDesired ( 1 << 8 ) // RD (bit 8), Recursion Desired
-#define kDNSHeaderFlag_RecursionAvailable ( 1 << 7 ) // RA (bit 7), Recursion Available
-#define kDNSHeaderFlag_Z ( 1 << 6 ) // Z (bit 6), Reserved (must be zero)
-#define kDNSHeaderFlag_AuthenticData ( 1 << 5 ) // AD (bit 5), Authentic Data (RFC 2535, Section 6)
-#define kDNSHeaderFlag_CheckingDisabled ( 1 << 4 ) // CD (bit 4), Checking Disabled (RFC 2535, Section 6)
-
-// OPCODE (bits 14-11), Operation Code
-
-#define DNSFlagsGetOpCode( FLAGS ) ( ( (FLAGS) >> 11 ) & 0x0FU )
-#define DNSFlagsSetOpCode( FLAGS, OPCODE ) \
- do{ (FLAGS) = ( (FLAGS) & ~0x7800U ) | ( ( (OPCODE) & 0x0FU ) << 11 ); } while( 0 )
-
-#define kDNSOpCode_Query 0 // QUERY (standard query)
-#define kDNSOpCode_InverseQuery 1 // IQUERY (inverse query)
-#define kDNSOpCode_Status 2 // STATUS
-#define kDNSOpCode_Notify 4 // NOTIFY
-#define kDNSOpCode_Update 5 // UPDATE
-
-// RCODE (bits 3-0), Response Code
-
-#define DNSFlagsGetRCode( FLAGS ) ( (FLAGS) & 0x0FU )
-#define DNSFlagsSetRCode( FLAGS, RCODE ) \
- do{ (FLAGS) = ( (FLAGS) & ~0x000FU ) | ( (RCODE) & 0x0FU ); } while( 0 )
-
-#define kDNSRCode_NoError 0
-#define kDNSRCode_FormatError 1
-#define kDNSRCode_ServerFailure 2
-#define kDNSRCode_NXDomain 3
-#define kDNSRCode_NotImplemented 4
-#define kDNSRCode_Refused 5
-
-typedef struct
-{
- uint8_t type[ 2 ];
- uint8_t class[ 2 ];
-
-} DNSQuestionFixedFields;
-
-check_compile_time( sizeof( DNSQuestionFixedFields ) == 4 );
-
-#define DNSQuestionFixedFieldsInit( FIELDS, QTYPE, QCLASS ) \
- do { WriteBig16( (FIELDS)->type, QTYPE ); WriteBig16( (FIELDS)->class, QCLASS ); } while( 0 )
-
-#define DNSQuestionFixedFieldsGetType( FIELDS ) ReadBig16( (FIELDS)->type )
-#define DNSQuestionFixedFieldsGetClass( FIELDS ) ReadBig16( (FIELDS)->class )
-
-typedef struct
-{
- uint8_t type[ 2 ];
- uint8_t class[ 2 ];
- uint8_t ttl[ 4 ];
- uint8_t rdlength[ 2 ];
-
-} DNSRecordFixedFields;
-
-check_compile_time( sizeof( DNSRecordFixedFields ) == 10 );
-
-// SRV RDATA fixed-length fields. See <https://tools.ietf.org/html/rfc2782>.
-
-typedef struct
-{
- uint8_t priority[ 2 ];
- uint8_t weight[ 2 ];
- uint8_t port[ 2 ];
-
-} SRVRecordDataFixedFields;
-
-check_compile_time( sizeof( SRVRecordDataFixedFields ) == 6 );
-
-// SOA RDATA fixed-length fields. See <https://tools.ietf.org/html/rfc1035#section-3.3.13>.
-
-typedef struct
-{
- uint8_t serial[ 4 ];
- uint8_t refresh[ 4 ];
- uint8_t retry[ 4 ];
- uint8_t expire[ 4 ];
- uint8_t minimum[ 4 ];
-
-} SOARecordDataFixedFields;
-
-check_compile_time( sizeof( SOARecordDataFixedFields ) == 20 );
-
-// DNS message compression. See <https://tools.ietf.org/html/rfc1035#section-4.1.4>.
-
-#define kDNSCompressionOffsetMax 0x3FFF
-
-#define IsCompressionByte( X ) ( ( ( X ) & 0xC0 ) == 0xC0 )
-#define WriteDNSCompressionPtr( PTR, OFFSET ) \
- do \
- { \
- ( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( ( ( (OFFSET) >> 8 ) & 0x3F ) | 0xC0 ); \
- ( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)( (OFFSET) & 0xFF ); \
- \
- } while( 0 )
-
-#define NextLabel( LABEL ) ( ( (LABEL)[ 0 ] == 0 ) ? NULL : ( (LABEL) + 1 + (LABEL)[ 0 ] ) )
-
-//===========================================================================================================================
-// mDNS
-//===========================================================================================================================
-
-#define kMDNSPort 5353
-
-#define kDefaultMDNSMessageID 0
-#define kDefaultMDNSQueryFlags 0
-
-#define kQClassUnicastResponseBit ( 1U << 15 )
-#define kRRClassCacheFlushBit ( 1U << 15 )
-
-// Recommended Resource Record TTL values. See <https://tools.ietf.org/html/rfc6762#section-10>.
-
-#define kMDNSRecordTTL_Host 120 // TTL for resource records related to a host name, e.g., A, AAAA, SRV, etc.
-#define kMDNSRecordTTL_Other 4500 // TTL for other resource records.
-
-// Maximum mDNS Message Size. See <https://tools.ietf.org/html/rfc6762#section-17>.
-
-#define kMDNSMessageSizeMax 8952 // 9000 B (Ethernet jumbo frame max size) - 40 B (IPv6 header) - 8 B (UDP header)
-
-#define kLocalStr "\x05" "local"
-#define kLocalName ( (const uint8_t *) kLocalStr )
-#define kLocalNameLen sizeof( kLocalStr )
-
-//===========================================================================================================================
-// Test Address Blocks
-//===========================================================================================================================
-
-// IPv4 address block 203.0.113.0/24 (TEST-NET-3) is reserved for documentation. See <https://tools.ietf.org/html/rfc5737>.
-
-#define kDNSServerBaseAddrV4 UINT32_C( 0xCB007100 ) // 203.0.113.0/24
-
-// IPv6 address block 2001:db8::/32 is reserved for documentation. See <https://tools.ietf.org/html/rfc3849>.
-
-static const uint8_t kDNSServerBaseAddrV6[] =
-{
- 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 2001:db8:1::/120
-};
-
-static const uint8_t kMDNSReplierBaseAddrV6[] =
-{
- 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 2001:db8:2::/96
-};
-
-check_compile_time( sizeof( kDNSServerBaseAddrV6 ) == 16 );
-check_compile_time( sizeof( kMDNSReplierBaseAddrV6 ) == 16 );
-
-// Bad IPv4 and IPv6 Address Blocks
-// Used by the DNS server when it needs to respond with intentionally "bad" A/AAAA record data, i.e., IP addresses neither
-// in 203.0.113.0/24 nor 2001:db8:1::/120.
-
-#define kDNSServerBadBaseAddrV4 UINT32_C( 0x00000000 ) // 0.0.0.0/24
-
-static const uint8_t kDNSServerBadBaseAddrV6[] =
-{
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 // ::ffff:0:0/120
-};
-
-check_compile_time( sizeof( kDNSServerBadBaseAddrV6 ) == 16 );
-
-//===========================================================================================================================
-// Misc.
-//===========================================================================================================================
-
-#define kLowerAlphaNumericCharSet "abcdefghijklmnopqrstuvwxyz0123456789"
-#define kLowerAlphaNumericCharSetSize sizeof_string( kLowerAlphaNumericCharSet )
-
-// Note: strcpy_literal() appears in CoreUtils code, but isn't currently defined in framework headers.
-
-#if( !defined( strcpy_literal ) )
- #define strcpy_literal( DST, SRC ) memcpy( DST, SRC, sizeof( SRC ) )
-#endif
-
-#define _RandomStringExact( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, OUT_STRING ) \
- RandomString( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, CHAR_COUNT, OUT_STRING )
-
-#define kNoSuchRecordStr "No Such Record"
-#define kNoSuchRecordAStr "No Such Record (A)"
-#define kNoSuchRecordAAAAStr "No Such Record (AAAA)"
-
-#define kRootLabel ( (const uint8_t *) "" )
-
-//===========================================================================================================================
-// Gerneral Command Options
-//===========================================================================================================================
-
-// Command option macros
-
-#define Command( NAME, CALLBACK, SUB_OPTIONS, SHORT_HELP, IS_NOTCOMMON ) \
- CLI_COMMAND_EX( NAME, CALLBACK, SUB_OPTIONS, (IS_NOTCOMMON) ? kCLIOptionFlags_NotCommon : kCLIOptionFlags_None, \
- (SHORT_HELP), NULL )
-
-#define kRequiredOptionSuffix " [REQUIRED]"
-
-#define MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
- CLI_OPTION_MULTI_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, \
- (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
- (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
-
-#define MultiStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
- MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
-
-#define IntegerOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
- CLI_OPTION_INTEGER_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
- (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
- (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
-
-#define DoubleOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
- CLI_OPTION_DOUBLE_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
- (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
- (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
-
-#define BooleanOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP ) \
- CLI_OPTION_BOOLEAN( (SHORT_CHAR), (LONG_NAME), (VAL_PTR), (SHORT_HELP), NULL )
-
-#define StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
- CLI_OPTION_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
- (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
- (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
-
-#define StringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
- StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
-
-#define CFStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
- CLI_OPTION_CFSTRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
- (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
- (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
-
-// DNS-SD API flag options
-
-static int gDNSSDFlags = 0;
-static int gDNSSDFlag_AllowExpiredAnswers = false;
-static int gDNSSDFlag_BrowseDomains = false;
-static int gDNSSDFlag_DenyCellular = false;
-static int gDNSSDFlag_DenyExpensive = false;
-static int gDNSSDFlag_ForceMulticast = false;
-static int gDNSSDFlag_IncludeAWDL = false;
-static int gDNSSDFlag_NoAutoRename = false;
-static int gDNSSDFlag_PathEvaluationDone = false;
-static int gDNSSDFlag_RegistrationDomains = false;
-static int gDNSSDFlag_ReturnIntermediates = false;
-static int gDNSSDFlag_Shared = false;
-static int gDNSSDFlag_SuppressUnusable = false;
-static int gDNSSDFlag_Timeout = false;
-static int gDNSSDFlag_UnicastResponse = false;
-static int gDNSSDFlag_Unique = false;
-static int gDNSSDFlag_WakeOnResolve = false;
-
-#define DNSSDFlagsOption() \
- IntegerOption( 'f', "flags", &gDNSSDFlags, "flags", \
- "DNSServiceFlags as an integer. This value is bitwise ORed with other single flag options.", false )
-
-#define DNSSDFlagOption( SHORT_CHAR, FLAG_NAME ) \
- BooleanOption( SHORT_CHAR, # FLAG_NAME, &gDNSSDFlag_ ## FLAG_NAME, "Use kDNSServiceFlags" # FLAG_NAME "." )
-
-#define DNSSDFlagsOption_AllowExpiredAnswers() DNSSDFlagOption( 'X', AllowExpiredAnswers )
-#define DNSSDFlagsOption_DenyCellular() DNSSDFlagOption( 'C', DenyCellular )
-#define DNSSDFlagsOption_DenyExpensive() DNSSDFlagOption( 'E', DenyExpensive )
-#define DNSSDFlagsOption_ForceMulticast() DNSSDFlagOption( 'M', ForceMulticast )
-#define DNSSDFlagsOption_IncludeAWDL() DNSSDFlagOption( 'A', IncludeAWDL )
-#define DNSSDFlagsOption_NoAutoRename() DNSSDFlagOption( 'N', NoAutoRename )
-#define DNSSDFlagsOption_PathEvalDone() DNSSDFlagOption( 'P', PathEvaluationDone )
-#define DNSSDFlagsOption_ReturnIntermediates() DNSSDFlagOption( 'I', ReturnIntermediates )
-#define DNSSDFlagsOption_Shared() DNSSDFlagOption( 'S', Shared )
-#define DNSSDFlagsOption_SuppressUnusable() DNSSDFlagOption( 'S', SuppressUnusable )
-#define DNSSDFlagsOption_Timeout() DNSSDFlagOption( 'T', Timeout )
-#define DNSSDFlagsOption_UnicastResponse() DNSSDFlagOption( 'U', UnicastResponse )
-#define DNSSDFlagsOption_Unique() DNSSDFlagOption( 'U', Unique )
-#define DNSSDFlagsOption_WakeOnResolve() DNSSDFlagOption( 'W', WakeOnResolve )
-
-// Interface option
-
-static const char * gInterface = NULL;
-
-#define InterfaceOption() \
- StringOption( 'i', "interface", &gInterface, "interface", \
- "Network interface by name or index. Use index -1 for local-only.", false )
-
-// Connection options
-
-#define kConnectionArg_Normal ""
-#define kConnectionArgPrefix_PID "pid:"
-#define kConnectionArgPrefix_UUID "uuid:"
-
-static const char * gConnectionOpt = kConnectionArg_Normal;
-
-#define ConnectionOptions() \
- { kCLIOptionType_String, 0, "connection", &gConnectionOpt, NULL, (intptr_t) kConnectionArg_Normal, "type", \
- kCLIOptionFlags_OptionalArgument, NULL, NULL, NULL, NULL, \
- "Specifies the type of main connection to use. See " kConnectionSection_Name " below.", NULL }
-
-#define kConnectionSection_Name "Connection Option"
-#define kConnectionSection_Text \
- "The default behavior is to create a main connection with DNSServiceCreateConnection() and perform operations on\n" \
- "the main connection using the kDNSServiceFlagsShareConnection flag. This behavior can be explicitly invoked by\n" \
- "specifying the connection option without an argument, i.e.,\n" \
- "\n" \
- " --connection\n" \
- "\n" \
- "To instead use a delegate connection created with DNSServiceCreateDelegateConnection(), use\n" \
- "\n" \
- " --connection=pid:<PID>\n" \
- "\n" \
- "to specify the delegator by PID, or use\n" \
- "\n" \
- " --connection=uuid:<UUID>\n" \
- "\n" \
- "to specify the delegator by UUID.\n" \
- "\n" \
- "To not use a main connection at all, but instead perform operations on their own implicit connections, use\n" \
- "\n" \
- " --no-connection\n"
-
-#define ConnectionSection() CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
-
-// Help text for record data options
-
-#define kRDataArgPrefix_Domain "domain:"
-#define kRDataArgPrefix_File "file:"
-#define kRDataArgPrefix_HexString "hex:"
-#define kRDataArgPrefix_IPv4 "ipv4:"
-#define kRDataArgPrefix_IPv6 "ipv6:"
-#define kRDataArgPrefix_SRV "srv:"
-#define kRDataArgPrefix_String "string:"
-#define kRDataArgPrefix_TXT "txt:"
-
-#define kRecordDataSection_Name "Record Data Arguments"
-#define kRecordDataSection_Text \
- "A record data argument is specified in one of the following formats:\n" \
- "\n" \
- "Format Syntax Example\n" \
- "Domain name domain:<domain name> domain:demo._test._tcp.local\n" \
- "File containing record data file:<file path> file:/path/to/rdata.bin\n" \
- "Hexadecimal string hex:<hex string> hex:c0000201 or hex:'C0 00 02 01'\n" \
- "IPv4 address ipv4:<IPv4 address> ipv4:192.0.2.1\n" \
- "IPv6 address ipv6:<IPv6 address> ipv6:2001:db8::1\n" \
- "SRV record srv:<priority>,<weight>,<port>,<target> srv:0,0,64206,example.local\n" \
- "String (w/escaped hex bytes) string:<string> string:'\\x09color=red'\n" \
- "TXT record keys and values txt:<comma-delimited keys and values> txt:'vers=1.0,lang=en\\,es\\,fr,passreq'\n"
-
-#define RecordDataSection() CLI_SECTION( kRecordDataSection_Name, kRecordDataSection_Text )
-
-//===========================================================================================================================
-// Output Formatting
-//===========================================================================================================================
-
-#define kOutputFormatStr_JSON "json"
-#define kOutputFormatStr_XML "xml"
-#define kOutputFormatStr_Binary "binary"
-
-typedef enum
-{
- kOutputFormatType_Invalid = 0,
- kOutputFormatType_JSON = 1,
- kOutputFormatType_XML = 2,
- kOutputFormatType_Binary = 3
-
-} OutputFormatType;
-
-#define FormatOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP, IS_REQUIRED ) \
- StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, "format", SHORT_HELP, IS_REQUIRED, \
- "\n" \
- "Use '" kOutputFormatStr_JSON "' for JavaScript Object Notation (JSON).\n" \
- "Use '" kOutputFormatStr_XML "' for property list XML version 1.0.\n" \
- "Use '" kOutputFormatStr_Binary "' for property list binary version 1.0.\n" \
- "\n" \
- )
-
-//===========================================================================================================================
-// Browse Command Options
-//===========================================================================================================================
-
-static char ** gBrowse_ServiceTypes = NULL;
-static size_t gBrowse_ServiceTypesCount = 0;
-static const char * gBrowse_Domain = NULL;
-static int gBrowse_DoResolve = false;
-static int gBrowse_QueryTXT = false;
-static int gBrowse_TimeLimitSecs = 0;
-
-static CLIOption kBrowseOpts[] =
-{
- InterfaceOption(),
- MultiStringOption( 't', "type", &gBrowse_ServiceTypes, &gBrowse_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\".", true ),
- StringOption( 'd', "domain", &gBrowse_Domain, "domain", "Domain in which to browse for the service type(s).", false ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_IncludeAWDL(),
-
- CLI_OPTION_GROUP( "Operation" ),
- ConnectionOptions(),
- BooleanOption( 0 , "resolve", &gBrowse_DoResolve, "Resolve service instances." ),
- BooleanOption( 0 , "queryTXT", &gBrowse_QueryTXT, "Query TXT records of service instances." ),
- IntegerOption( 'l', "timeLimit", &gBrowse_TimeLimitSecs, "seconds", "Specifies the max duration of the browse operation. Use '0' for no time limit.", false ),
-
- ConnectionSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// GetAddrInfo Command Options
-//===========================================================================================================================
-
-static const char * gGetAddrInfo_Name = NULL;
-static int gGetAddrInfo_ProtocolIPv4 = false;
-static int gGetAddrInfo_ProtocolIPv6 = false;
-static int gGetAddrInfo_OneShot = false;
-static int gGetAddrInfo_TimeLimitSecs = 0;
-
-static CLIOption kGetAddrInfoOpts[] =
-{
- InterfaceOption(),
- StringOption( 'n', "name", &gGetAddrInfo_Name, "domain name", "Domain name to resolve.", true ),
- BooleanOption( 0 , "ipv4", &gGetAddrInfo_ProtocolIPv4, "Use kDNSServiceProtocol_IPv4." ),
- BooleanOption( 0 , "ipv6", &gGetAddrInfo_ProtocolIPv6, "Use kDNSServiceProtocol_IPv6." ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_AllowExpiredAnswers(),
- DNSSDFlagsOption_DenyCellular(),
- DNSSDFlagsOption_DenyExpensive(),
- DNSSDFlagsOption_PathEvalDone(),
- DNSSDFlagsOption_ReturnIntermediates(),
- DNSSDFlagsOption_SuppressUnusable(),
- DNSSDFlagsOption_Timeout(),
-
- CLI_OPTION_GROUP( "Operation" ),
- ConnectionOptions(),
- BooleanOption( 'o', "oneshot", &gGetAddrInfo_OneShot, "Finish after first set of results." ),
- IntegerOption( 'l', "timeLimit", &gGetAddrInfo_TimeLimitSecs, "seconds", "Maximum duration of the GetAddrInfo operation. Use '0' for no time limit.", false ),
-
- ConnectionSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// QueryRecord Command Options
-//===========================================================================================================================
-
-static const char * gQueryRecord_Name = NULL;
-static const char * gQueryRecord_Type = NULL;
-static int gQueryRecord_OneShot = false;
-static int gQueryRecord_TimeLimitSecs = 0;
-static int gQueryRecord_RawRData = false;
-
-static CLIOption kQueryRecordOpts[] =
-{
- InterfaceOption(),
- StringOption( 'n', "name", &gQueryRecord_Name, "domain name", "Full domain name of record to query.", true ),
- StringOption( 't', "type", &gQueryRecord_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_AllowExpiredAnswers(),
- DNSSDFlagsOption_DenyCellular(),
- DNSSDFlagsOption_DenyExpensive(),
- DNSSDFlagsOption_ForceMulticast(),
- DNSSDFlagsOption_IncludeAWDL(),
- DNSSDFlagsOption_PathEvalDone(),
- DNSSDFlagsOption_ReturnIntermediates(),
- DNSSDFlagsOption_SuppressUnusable(),
- DNSSDFlagsOption_Timeout(),
- DNSSDFlagsOption_UnicastResponse(),
-
- CLI_OPTION_GROUP( "Operation" ),
- ConnectionOptions(),
- BooleanOption( 'o', "oneshot", &gQueryRecord_OneShot, "Finish after first set of results." ),
- IntegerOption( 'l', "timeLimit", &gQueryRecord_TimeLimitSecs, "seconds", "Maximum duration of the query record operation. Use '0' for no time limit.", false ),
- BooleanOption( 0 , "raw", &gQueryRecord_RawRData, "Show record data as a hexdump." ),
-
- ConnectionSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// Register Command Options
-//===========================================================================================================================
-
-static const char * gRegister_Name = NULL;
-static const char * gRegister_Type = NULL;
-static const char * gRegister_Domain = NULL;
-static int gRegister_Port = 0;
-static const char * gRegister_TXT = NULL;
-static int gRegister_LifetimeMs = -1;
-static const char ** gAddRecord_Types = NULL;
-static size_t gAddRecord_TypesCount = 0;
-static const char ** gAddRecord_Data = NULL;
-static size_t gAddRecord_DataCount = 0;
-static const char ** gAddRecord_TTLs = NULL;
-static size_t gAddRecord_TTLsCount = 0;
-static const char * gUpdateRecord_Data = NULL;
-static int gUpdateRecord_DelayMs = 0;
-static int gUpdateRecord_TTL = 0;
-
-static CLIOption kRegisterOpts[] =
-{
- InterfaceOption(),
- StringOption( 'n', "name", &gRegister_Name, "service name", "Name of service.", false ),
- StringOption( 't', "type", &gRegister_Type, "service type", "Service type, e.g., \"_ssh._tcp\".", true ),
- StringOption( 'd', "domain", &gRegister_Domain, "domain", "Domain in which to advertise the service.", false ),
- IntegerOption( 'p', "port", &gRegister_Port, "port number", "Service's port number.", true ),
- StringOption( 0 , "txt", &gRegister_TXT, "record data", "The TXT record data. See " kRecordDataSection_Name " below.", false ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_IncludeAWDL(),
- DNSSDFlagsOption_NoAutoRename(),
-
- CLI_OPTION_GROUP( "Operation" ),
- IntegerOption( 'l', "lifetime", &gRegister_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
-
- CLI_OPTION_GROUP( "Options for updating the registered service's primary TXT record with DNSServiceUpdateRecord()\n" ),
- StringOption( 0 , "updateData", &gUpdateRecord_Data, "record data", "Record data for the record update. See " kRecordDataSection_Name " below.", false ),
- IntegerOption( 0 , "updateDelay", &gUpdateRecord_DelayMs, "ms", "Number of milliseconds after registration to wait before record update.", false ),
- IntegerOption( 0 , "updateTTL", &gUpdateRecord_TTL, "seconds", "Time-to-live of the updated record.", false ),
-
- CLI_OPTION_GROUP( "Options for adding extra record(s) to the registered service with DNSServiceAddRecord()\n" ),
- MultiStringOption( 0 , "addType", &gAddRecord_Types, &gAddRecord_TypesCount, "record type", "Type of additional record by name (e.g., TXT, SRV, etc.) or number.", false ),
- MultiStringOptionEx( 0 , "addData", &gAddRecord_Data, &gAddRecord_DataCount, "record data", "Additional record's data. See " kRecordDataSection_Name " below.", false, NULL ),
- MultiStringOption( 0 , "addTTL", &gAddRecord_TTLs, &gAddRecord_TTLsCount, "seconds", "Time-to-live of additional record in seconds. Use '0' for default.", false ),
-
- RecordDataSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// RegisterRecord Command Options
-//===========================================================================================================================
-
-static const char * gRegisterRecord_Name = NULL;
-static const char * gRegisterRecord_Type = NULL;
-static const char * gRegisterRecord_Data = NULL;
-static int gRegisterRecord_TTL = 0;
-static int gRegisterRecord_LifetimeMs = -1;
-static const char * gRegisterRecord_UpdateData = NULL;
-static int gRegisterRecord_UpdateDelayMs = 0;
-static int gRegisterRecord_UpdateTTL = 0;
-
-static CLIOption kRegisterRecordOpts[] =
-{
- InterfaceOption(),
- StringOption( 'n', "name", &gRegisterRecord_Name, "record name", "Fully qualified domain name of record.", true ),
- StringOption( 't', "type", &gRegisterRecord_Type, "record type", "Record type by name (e.g., TXT, PTR, A) or number.", true ),
- StringOption( 'd', "data", &gRegisterRecord_Data, "record data", "The record data. See " kRecordDataSection_Name " below.", false ),
- IntegerOption( 0 , "ttl", &gRegisterRecord_TTL, "seconds", "Time-to-live in seconds. Use '0' for default.", false ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_IncludeAWDL(),
- DNSSDFlagsOption_Shared(),
- DNSSDFlagsOption_Unique(),
-
- CLI_OPTION_GROUP( "Operation" ),
- IntegerOption( 'l', "lifetime", &gRegisterRecord_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
-
- CLI_OPTION_GROUP( "Options for updating the registered record with DNSServiceUpdateRecord()\n" ),
- StringOption( 0 , "updateData", &gRegisterRecord_UpdateData, "record data", "Record data for the record update.", false ),
- IntegerOption( 0 , "updateDelay", &gRegisterRecord_UpdateDelayMs, "ms", "Number of milliseconds after registration to wait before record update.", false ),
- IntegerOption( 0 , "updateTTL", &gRegisterRecord_UpdateTTL, "seconds", "Time-to-live of the updated record.", false ),
-
- RecordDataSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// Resolve Command Options
-//===========================================================================================================================
-
-static char * gResolve_Name = NULL;
-static char * gResolve_Type = NULL;
-static char * gResolve_Domain = NULL;
-static int gResolve_TimeLimitSecs = 0;
-
-static CLIOption kResolveOpts[] =
-{
- InterfaceOption(),
- StringOption( 'n', "name", &gResolve_Name, "service name", "Name of the service instance to resolve.", true ),
- StringOption( 't', "type", &gResolve_Type, "service type", "Type of the service instance to resolve.", true ),
- StringOption( 'd', "domain", &gResolve_Domain, "domain", "Domain of the service instance to resolve.", true ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_ForceMulticast(),
- DNSSDFlagsOption_IncludeAWDL(),
- DNSSDFlagsOption_ReturnIntermediates(),
- DNSSDFlagsOption_WakeOnResolve(),
-
- CLI_OPTION_GROUP( "Operation" ),
- ConnectionOptions(),
- IntegerOption( 'l', "timeLimit", &gResolve_TimeLimitSecs, "seconds", "Maximum duration of the resolve operation. Use '0' for no time limit.", false ),
-
- ConnectionSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// Reconfirm Command Options
-//===========================================================================================================================
-
-static const char * gReconfirmRecord_Name = NULL;
-static const char * gReconfirmRecord_Type = NULL;
-static const char * gReconfirmRecord_Class = NULL;
-static const char * gReconfirmRecord_Data = NULL;
-
-static CLIOption kReconfirmOpts[] =
-{
- InterfaceOption(),
- StringOption( 'n', "name", &gReconfirmRecord_Name, "record name", "Full name of the record to reconfirm.", true ),
- StringOption( 't', "type", &gReconfirmRecord_Type, "record type", "Type of the record to reconfirm.", true ),
- StringOption( 'c', "class", &gReconfirmRecord_Class, "record class", "Class of the record to reconfirm. Default class is IN.", false ),
- StringOption( 'd', "data", &gReconfirmRecord_Data, "record data", "The record data. See " kRecordDataSection_Name " below.", false ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
-
- RecordDataSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// getaddrinfo-POSIX Command Options
-//===========================================================================================================================
-
-static const char * gGAIPOSIX_HostName = NULL;
-static const char * gGAIPOSIX_ServName = NULL;
-static const char * gGAIPOSIX_Family = NULL;
-static int gGAIPOSIXFlag_AddrConfig = false;
-static int gGAIPOSIXFlag_All = false;
-static int gGAIPOSIXFlag_CanonName = false;
-static int gGAIPOSIXFlag_NumericHost = false;
-static int gGAIPOSIXFlag_NumericServ = false;
-static int gGAIPOSIXFlag_Passive = false;
-static int gGAIPOSIXFlag_V4Mapped = false;
-#if( defined( AI_V4MAPPED_CFG ) )
-static int gGAIPOSIXFlag_V4MappedCFG = false;
-#endif
-#if( defined( AI_DEFAULT ) )
-static int gGAIPOSIXFlag_Default = false;
-#endif
-#if( defined( AI_UNUSABLE ) )
-static int gGAIPOSIXFlag_Unusable = false;
-#endif
-
-static CLIOption kGetAddrInfoPOSIXOpts[] =
-{
- StringOption( 'n', "hostname", &gGAIPOSIX_HostName, "hostname", "Domain name to resolve or an IPv4 or IPv6 address.", true ),
- StringOption( 's', "servname", &gGAIPOSIX_ServName, "servname", "Port number in decimal or service name from services(5).", false ),
-
- CLI_OPTION_GROUP( "Hints" ),
- StringOptionEx( 'f', "family", &gGAIPOSIX_Family, "address family", "Address family to use for hints ai_family field.", false,
- "\n"
- "Possible address family values are 'inet' for AF_INET, 'inet6' for AF_INET6, or 'unspec' for AF_UNSPEC. If no\n"
- "address family is specified, then AF_UNSPEC is used.\n"
- "\n" ),
- BooleanOption( 0 , "flag-addrconfig", &gGAIPOSIXFlag_AddrConfig, "In hints ai_flags field, set AI_ADDRCONFIG." ),
- BooleanOption( 0 , "flag-all", &gGAIPOSIXFlag_All, "In hints ai_flags field, set AI_ALL." ),
- BooleanOption( 0 , "flag-canonname", &gGAIPOSIXFlag_CanonName, "In hints ai_flags field, set AI_CANONNAME." ),
- BooleanOption( 0 , "flag-numerichost", &gGAIPOSIXFlag_NumericHost, "In hints ai_flags field, set AI_NUMERICHOST." ),
- BooleanOption( 0 , "flag-numericserv", &gGAIPOSIXFlag_NumericServ, "In hints ai_flags field, set AI_NUMERICSERV." ),
- BooleanOption( 0 , "flag-passive", &gGAIPOSIXFlag_Passive, "In hints ai_flags field, set AI_PASSIVE." ),
- BooleanOption( 0 , "flag-v4mapped", &gGAIPOSIXFlag_V4Mapped, "In hints ai_flags field, set AI_V4MAPPED." ),
-#if( defined( AI_V4MAPPED_CFG ) )
- BooleanOption( 0 , "flag-v4mappedcfg", &gGAIPOSIXFlag_V4MappedCFG, "In hints ai_flags field, set AI_V4MAPPED_CFG." ),
-#endif
-#if( defined( AI_DEFAULT ) )
- BooleanOption( 0 , "flag-default", &gGAIPOSIXFlag_Default, "In hints ai_flags field, set AI_DEFAULT." ),
-#endif
-#if( defined( AI_UNUSABLE ) )
- BooleanOption( 0 , "flag-unusable", &gGAIPOSIXFlag_Unusable, "In hints ai_flags field, set AI_UNUSABLE." ),
-#endif
-
- CLI_SECTION( "Notes", "See getaddrinfo(3) man page for more details.\n" ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// ReverseLookup Command Options
-//===========================================================================================================================
-
-static const char * gReverseLookup_IPAddr = NULL;
-static int gReverseLookup_OneShot = false;
-static int gReverseLookup_TimeLimitSecs = 0;
-
-static CLIOption kReverseLookupOpts[] =
-{
- InterfaceOption(),
- StringOption( 'a', "address", &gReverseLookup_IPAddr, "IP address", "IPv4 or IPv6 address for which to perform a reverse IP lookup.", true ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
- DNSSDFlagsOption_ForceMulticast(),
- DNSSDFlagsOption_ReturnIntermediates(),
- DNSSDFlagsOption_SuppressUnusable(),
-
- CLI_OPTION_GROUP( "Operation" ),
- ConnectionOptions(),
- BooleanOption( 'o', "oneshot", &gReverseLookup_OneShot, "Finish after first set of results." ),
- IntegerOption( 'l', "timeLimit", &gReverseLookup_TimeLimitSecs, "seconds", "Specifies the max duration of the query record operation. Use '0' for no time limit.", false ),
-
- ConnectionSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// PortMapping Command Options
-//===========================================================================================================================
-
-static int gPortMapping_ProtocolTCP = false;
-static int gPortMapping_ProtocolUDP = false;
-static int gPortMapping_InternalPort = 0;
-static int gPortMapping_ExternalPort = 0;
-static int gPortMapping_TTL = 0;
-
-static CLIOption kPortMappingOpts[] =
-{
- InterfaceOption(),
- BooleanOption( 0, "tcp", &gPortMapping_ProtocolTCP, "Use kDNSServiceProtocol_TCP." ),
- BooleanOption( 0, "udp", &gPortMapping_ProtocolUDP, "Use kDNSServiceProtocol_UDP." ),
- IntegerOption( 0, "internalPort", &gPortMapping_InternalPort, "port number", "Internal port.", false ),
- IntegerOption( 0, "externalPort", &gPortMapping_ExternalPort, "port number", "Requested external port. Use '0' for any external port.", false ),
- IntegerOption( 0, "ttl", &gPortMapping_TTL, "seconds", "Requested TTL (renewal period) in seconds. Use '0' for a default value.", false ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption(),
-
- CLI_OPTION_GROUP( "Operation" ),
- ConnectionOptions(),
-
- ConnectionSection(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// BrowseAll Command Options
-//===========================================================================================================================
-
-static const char * gBrowseAll_Domain = NULL;
-static const char ** gBrowseAll_ServiceTypes = NULL;
-static size_t gBrowseAll_ServiceTypesCount = 0;
-static int gBrowseAll_BrowseTimeSecs = 5;
-static int gBrowseAll_ConnectTimeout = 0;
-
-static CLIOption kBrowseAllOpts[] =
-{
- InterfaceOption(),
- StringOption( 'd', "domain", &gBrowseAll_Domain, "domain", "Domain in which to browse for the service.", false ),
- MultiStringOption( 't', "type", &gBrowseAll_ServiceTypes, &gBrowseAll_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\". All services are browsed for if none is specified.", false ),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption_IncludeAWDL(),
-
- CLI_OPTION_GROUP( "Operation" ),
- IntegerOption( 'b', "browseTime", &gBrowseAll_BrowseTimeSecs, "seconds", "Amount of time to spend browsing in seconds. (default: 5)", false ),
- IntegerOption( 'c', "connectTimeout", &gBrowseAll_ConnectTimeout, "seconds", "Timeout for connection attempts. If <= 0, no connections are attempted. (default: 0)", false ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// GetNameInfo Command Options
-//===========================================================================================================================
-
-static void GetNameInfoCmd( void );
-
-static char * gGetNameInfo_IPAddress = NULL;
-static int gGetNameInfoFlag_DGram = false;
-static int gGetNameInfoFlag_NameReqd = false;
-static int gGetNameInfoFlag_NoFQDN = false;
-static int gGetNameInfoFlag_NumericHost = false;
-static int gGetNameInfoFlag_NumericScope = false;
-static int gGetNameInfoFlag_NumericServ = false;
-
-static CLIOption kGetNameInfoOpts[] =
-{
- StringOption( 'a', "address", &gGetNameInfo_IPAddress, "IP address", "IPv4 or IPv6 address to use in sockaddr structure.", true ),
-
- CLI_OPTION_GROUP( "Flags" ),
- BooleanOption( 0 , "flag-dgram", &gGetNameInfoFlag_DGram, "Use NI_DGRAM flag." ),
- BooleanOption( 0 , "flag-namereqd", &gGetNameInfoFlag_NameReqd, "Use NI_NAMEREQD flag." ),
- BooleanOption( 0 , "flag-nofqdn", &gGetNameInfoFlag_NoFQDN, "Use NI_NOFQDN flag." ),
- BooleanOption( 0 , "flag-numerichost", &gGetNameInfoFlag_NumericHost, "Use NI_NUMERICHOST flag." ),
- BooleanOption( 0 , "flag-numericscope", &gGetNameInfoFlag_NumericScope, "Use NI_NUMERICSCOPE flag." ),
- BooleanOption( 0 , "flag-numericserv", &gGetNameInfoFlag_NumericServ, "Use NI_NUMERICSERV flag." ),
-
- CLI_SECTION( "Notes", "See getnameinfo(3) man page for more details.\n" ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// GetAddrInfoStress Command Options
-//===========================================================================================================================
-
-static int gGAIStress_TestDurationSecs = 0;
-static int gGAIStress_ConnectionCount = 0;
-static int gGAIStress_DurationMinMs = 0;
-static int gGAIStress_DurationMaxMs = 0;
-static int gGAIStress_RequestCountMax = 0;
-
-static CLIOption kGetAddrInfoStressOpts[] =
-{
- InterfaceOption(),
-
- CLI_OPTION_GROUP( "Flags" ),
- DNSSDFlagsOption_ReturnIntermediates(),
- DNSSDFlagsOption_SuppressUnusable(),
-
- CLI_OPTION_GROUP( "Operation" ),
- IntegerOption( 0, "testDuration", &gGAIStress_TestDurationSecs, "seconds", "Stress test duration in seconds. Use '0' for forever.", false ),
- IntegerOption( 0, "connectionCount", &gGAIStress_ConnectionCount, "integer", "Number of simultaneous DNS-SD connections.", true ),
- IntegerOption( 0, "requestDurationMin", &gGAIStress_DurationMinMs, "ms", "Minimum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
- IntegerOption( 0, "requestDurationMax", &gGAIStress_DurationMaxMs, "ms", "Maximum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
- IntegerOption( 0, "consecutiveRequestMax", &gGAIStress_RequestCountMax, "integer", "Maximum number of requests on a connection before restarting it.", true ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// DNSQuery Command Options
-//===========================================================================================================================
-
-static char * gDNSQuery_Name = NULL;
-static char * gDNSQuery_Type = "A";
-static char * gDNSQuery_Server = NULL;
-static int gDNSQuery_TimeLimitSecs = 5;
-static int gDNSQuery_UseTCP = false;
-static int gDNSQuery_Flags = kDNSHeaderFlag_RecursionDesired;
-static int gDNSQuery_RawRData = false;
-static int gDNSQuery_Verbose = false;
-
-#if( TARGET_OS_DARWIN )
- #define kDNSQueryServerOptionIsRequired false
-#else
- #define kDNSQueryServerOptionIsRequired true
-#endif
-
-static CLIOption kDNSQueryOpts[] =
-{
- StringOption( 'n', "name", &gDNSQuery_Name, "name", "Question name (QNAME) to put in DNS query message.", true ),
- StringOption( 't', "type", &gDNSQuery_Type, "type", "Question type (QTYPE) to put in DNS query message. Default value is 'A'.", false ),
- StringOption( 's', "server", &gDNSQuery_Server, "IP address", "DNS server's IPv4 or IPv6 address.", kDNSQueryServerOptionIsRequired ),
- IntegerOption( 'l', "timeLimit", &gDNSQuery_TimeLimitSecs, "seconds", "Specifies query time limit. Use '-1' for no limit and '0' to exit immediately after sending.", false ),
- BooleanOption( 0 , "tcp", &gDNSQuery_UseTCP, "Send the DNS query via TCP instead of UDP." ),
- IntegerOption( 'f', "flags", &gDNSQuery_Flags, "flags", "16-bit value for DNS header flags/codes field. Default value is 0x0100 (Recursion Desired).", false ),
- BooleanOption( 0 , "raw", &gDNSQuery_RawRData, "Present record data as a hexdump." ),
- BooleanOption( 'v', "verbose", &gDNSQuery_Verbose, "Prints the DNS message to be sent to the server." ),
- CLI_OPTION_END()
-};
-
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-//===========================================================================================================================
-// DNSCrypt Command Options
-//===========================================================================================================================
-
-static char * gDNSCrypt_ProviderName = NULL;
-static char * gDNSCrypt_ProviderKey = NULL;
-static char * gDNSCrypt_Name = NULL;
-static char * gDNSCrypt_Type = NULL;
-static char * gDNSCrypt_Server = NULL;
-static int gDNSCrypt_TimeLimitSecs = 5;
-static int gDNSCrypt_RawRData = false;
-static int gDNSCrypt_Verbose = false;
-
-static CLIOption kDNSCryptOpts[] =
-{
- StringOption( 'p', "providerName", &gDNSCrypt_ProviderName, "name", "The DNSCrypt provider name.", true ),
- StringOption( 'k', "providerKey", &gDNSCrypt_ProviderKey, "hex string", "The DNSCrypt provider's public signing key.", true ),
- StringOption( 'n', "name", &gDNSCrypt_Name, "name", "Question name (QNAME) to put in DNS query message.", true ),
- StringOption( 't', "type", &gDNSCrypt_Type, "type", "Question type (QTYPE) to put in DNS query message.", true ),
- StringOption( 's', "server", &gDNSCrypt_Server, "IP address", "DNS server's IPv4 or IPv6 address.", true ),
- IntegerOption( 'l', "timeLimit", &gDNSCrypt_TimeLimitSecs, "seconds", "Specifies query time limit. Use '-1' for no time limit and '0' to exit immediately after sending.", false ),
- BooleanOption( 0 , "raw", &gDNSCrypt_RawRData, "Present record data as a hexdump." ),
- BooleanOption( 'v', "verbose", &gDNSCrypt_Verbose, "Prints the DNS message to be sent to the server." ),
- CLI_OPTION_END()
-};
-#endif
-
-//===========================================================================================================================
-// MDNSQuery Command Options
-//===========================================================================================================================
-
-static char * gMDNSQuery_Name = NULL;
-static char * gMDNSQuery_Type = NULL;
-static int gMDNSQuery_SourcePort = 0;
-static int gMDNSQuery_IsQU = false;
-static int gMDNSQuery_RawRData = false;
-static int gMDNSQuery_UseIPv4 = false;
-static int gMDNSQuery_UseIPv6 = false;
-static int gMDNSQuery_AllResponses = false;
-static int gMDNSQuery_ReceiveSecs = 1;
-
-static CLIOption kMDNSQueryOpts[] =
-{
- StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
- StringOption( 'n', "name", &gMDNSQuery_Name, "name", "Question name (QNAME) to put in mDNS message.", true ),
- StringOption( 't', "type", &gMDNSQuery_Type, "type", "Question type (QTYPE) to put in mDNS message.", true ),
- IntegerOption( 'p', "sourcePort", &gMDNSQuery_SourcePort, "port number", "UDP source port to use when sending mDNS messages. Default is 5353 for QM questions.", false ),
- BooleanOption( 'u', "QU", &gMDNSQuery_IsQU, "Set the unicast-response bit, i.e., send a QU question." ),
- BooleanOption( 0 , "raw", &gMDNSQuery_RawRData, "Present record data as a hexdump." ),
- BooleanOption( 0 , "ipv4", &gMDNSQuery_UseIPv4, "Use IPv4." ),
- BooleanOption( 0 , "ipv6", &gMDNSQuery_UseIPv6, "Use IPv6." ),
- BooleanOption( 'a', "allResponses", &gMDNSQuery_AllResponses, "Print all received mDNS messages, not just those containing answers." ),
- IntegerOption( 'r', "receiveTime", &gMDNSQuery_ReceiveSecs, "seconds", "Amount of time to spend receiving messages after the query is sent. The default is one second. Use -1 for unlimited time.", false ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// MDNSCollider Command Options
-//===========================================================================================================================
-
-#define kMDNSColliderProgramSection_Intro \
- "Programs dictate when the collider sends out unsolicited response messages for its record and how the collider\n" \
- "ought to react to probe queries that match its record's name, if at all.\n" \
- "\n" \
- "For example, suppose that the goal is to cause a specific unique record in the verified state to be renamed.\n" \
- "The collider should be invoked such that its record's name is equal to that of the record being targeted. Also,\n" \
- "the record's type and data should be such that no record with that name, type, and data combination currently\n" \
- "exists. If the mDNS responder that owns the record follows sections 8.1 and 9 of RFC 6762, then the goal can be\n" \
- "accomplished with the following program:\n" \
- "\n" \
- " probes 3r; send; wait 5000\n" \
- "\n" \
- "The first command, 'probes 3r', tells the collider to respond to the next three probe queries that match its\n" \
- "record's name. The second command, makes the collider send an unsolicited response message that contains its\n" \
- "record in the answer section. The third command makes the collider wait for five seconds before exiting, which\n" \
- "is more than enough time for the collider to respond to probe queries.\n" \
- "\n" \
- "The send command will cause the targeted record to go into the probing state per section 9 since the collider's\n" \
- "record conflicts with target record. Per the probes command, the subsequent probe query sent during the probing\n" \
- "state will be answered by the collider, which will cause the record to be renamed per section 8.1.\n"
-
-#define kMDNSColliderProgramSection_Probes \
- "The probes command defines how the collider ought to react to probe queries that match its record's name.\n" \
- "\n" \
- "Usage: probes [<action-string>]\n" \
- "\n" \
- "The syntax for an action-string is\n" \
- "\n" \
- " <action-string> ::= <action> | <action-string> \"-\" <action>\n" \
- " <action> ::= [<repeat-count>] <action-code>\n" \
- " <repeat-count> ::= \"1\" | \"2\" | ... | \"10\"\n" \
- " <action-code> ::= \"n\" | \"r\" | \"u\" | \"m\" | \"p\"\n" \
- "\n" \
- "An expanded action-string is defined as\n" \
- "\n" \
- " <expanded-action-string> ::= <action-code> | <expanded-action-string> \"-\" <action-code>\n" \
- "\n" \
- "The action-string argument is converted into an expanded-action-string by expanding each action with a\n" \
- "repeat-count into an expanded-action-string consisting of exactly <repeat-count> <action-code>s. For example,\n" \
- "2n-r expands to n-n-r. Action-strings that expand to expanded-action-strings with more than 10 action-codes\n" \
- "are not allowed.\n" \
- "\n" \
- "When the probes command is executed, it does two things. Firstly, it resets to zero the collider's count of\n" \
- "probe queries that match its record's name. Secondly, it defines how the collider ought to react to such probe\n" \
- "queries based on the action-string argument. Specifically, the nth action-code in the expanded version of the\n" \
- "action-string argument defines how the collider ought to react to the nth received probe query:\n" \
- "\n" \
- " Code Action\n" \
- " ---- ------\n" \
- " n Do nothing.\n" \
- " r Respond to the probe query.\n" \
- " u Respond to the probe query via unicast.\n" \
- " m Respond to the probe query via multicast.\n" \
- " p Multicast own probe query. (Useful for causing simultaneous probe scenarios.)\n" \
- "\n" \
- "Note: If no action is defined for a received probe query, then the collider does nothing, i.e., it doesn't send\n" \
- "a response nor does it multicast its own probe query.\n"
-
-#define kMDNSColliderProgramSection_Send \
- "The send command multicasts an unsolicited mDNS response containing the collider's record in the answer\n" \
- "section, which can be used to force unique records with the same record name into the probing state.\n" \
- "\n" \
- "Usage: send\n"
-
-#define kMDNSColliderProgramSection_Wait \
- "The wait command pauses program execution for the interval of time specified by its argument.\n" \
- "\n" \
- "Usage: wait <milliseconds>\n"
-
-#define kMDNSColliderProgramSection_Loop \
- "The loop command starts a counting loop. The done statement marks the end of the loop body. The loop command's\n" \
- "argument specifies the number of loop iterations. Note: Loop nesting is supported up to a depth of 16.\n" \
- "\n" \
- "Usage: loop <non-zero count>; ... ; done\n" \
- "\n" \
- "For example, the following program sends three unsolicited responses at an approximate rate of one per second:\n" \
- "\n" \
- " loop 3; wait 1000; send; done"
-
-#define ConnectionSection() CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
-
-static const char * gMDNSCollider_Name = NULL;
-static const char * gMDNSCollider_Type = NULL;
-static const char * gMDNSCollider_RecordData = NULL;
-static int gMDNSCollider_UseIPv4 = false;
-static int gMDNSCollider_UseIPv6 = false;
-static const char * gMDNSCollider_Program = NULL;
-
-static CLIOption kMDNSColliderOpts[] =
-{
- StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
- StringOption( 'n', "name", &gMDNSCollider_Name, "name", "Collider's record name.", true ),
- StringOption( 't', "type", &gMDNSCollider_Type, "type", "Collider's record type.", true ),
- StringOption( 'd', "data", &gMDNSCollider_RecordData, "record data", "Collider's record data. See " kRecordDataSection_Name " below.", true ),
- StringOption( 'p', "program", &gMDNSCollider_Program, "program", "Program to execute. See Program section below.", true ),
- BooleanOption( 0 , "ipv4", &gMDNSCollider_UseIPv4, "Use IPv4." ),
- BooleanOption( 0 , "ipv6", &gMDNSCollider_UseIPv6, "Use IPv6." ),
-
- RecordDataSection(),
- CLI_SECTION( "Program", kMDNSColliderProgramSection_Intro ),
- CLI_SECTION( "Program Command: probes", kMDNSColliderProgramSection_Probes ),
- CLI_SECTION( "Program Command: send", kMDNSColliderProgramSection_Send ),
- CLI_SECTION( "Program Command: wait", kMDNSColliderProgramSection_Wait ),
- CLI_SECTION( "Program Command: loop", kMDNSColliderProgramSection_Loop ),
- CLI_OPTION_END()
-};
-
-static void MDNSColliderCmd( void );
-
-//===========================================================================================================================
-// PIDToUUID Command Options
-//===========================================================================================================================
-
-static int gPIDToUUID_PID = 0;
-
-static CLIOption kPIDToUUIDOpts[] =
-{
- IntegerOption( 'p', "pid", &gPIDToUUID_PID, "PID", "Process ID.", true ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// DNSServer Command Options
-//===========================================================================================================================
-
-#define kDNSServerInfoText_Intro \
- "The DNS server answers certain queries in the d.test. domain. Responses are dynamically generated based on the\n" \
- "presence of special labels in the query's QNAME. There are currently eight types of special labels that can be\n" \
- "used to generate specific responses: Alias labels, Alias-TTL labels, Count labels, Tag labels, TTL labels, the\n" \
- "IPv4 label, the IPv6 label, and SRV labels.\n" \
- "\n" \
- "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
-
-#define kDNSServerInfoText_NameExistence \
- "A name is considered to exist if it's an Address name or an SRV name.\n" \
- "\n" \
- "An Address name is defined as a name that ends with d.test., and the other labels, if any, and in no particular\n" \
- "order, unless otherwise noted, consist of\n" \
- "\n" \
- " 1. at most one Alias or Alias-TTL label as the first label;\n" \
- " 2. at most one Count label;\n" \
- " 3. zero or more Tag labels;\n" \
- " 4. at most one TTL label; and\n" \
- " 5. at most one IPv4 or IPv6 label.\n" \
- "\n" \
- "An SRV name is defined as a name with the following form:\n" \
- "\n" \
- " _<service>._<proto>[.<parent domain>][.<SRV label 1>[.<target 1>][.<SRV label 2>[.<target 2>][...]]].d.test.\n" \
- "\n" \
- "See \"SRV Names\" for details.\n"
-
-#define kDNSServerInfoText_ResourceRecords \
- "Currently, the server only supports CNAME, A, AAAA, and SRV records.\n" \
- "\n" \
- "Address names that begin with an Alias or Alias-TTL label are aliases of canonical names, i.e., they're the\n" \
- "names of CNAME records. See \"Alias Labels\" and \"Alias-TTL Labels\" for details.\n" \
- "\n" \
- "A canonical Address name can exclusively be the name of one or more A records, can exclusively be the name or\n" \
- "one or more AAAA records, or can be the name of both A and AAAA records. Address names that contain an IPv4\n" \
- "label have at least one A record, but no AAAA records. Address names that contain an IPv6 label, have at least\n" \
- "one AAAA record, but no A records. All other Address names have at least one A record and at least one AAAA\n" \
- "record. See \"Count Labels\" for how the number of address records for a given Address name is determined.\n" \
- "\n" \
- "A records contain IPv4 addresses in the 203.0.113.0/24 block, while AAAA records contain IPv6 addresses in the\n" \
- "2001:db8:1::/120 block. Both of these address blocks are reserved for documentation. See\n" \
- "<https://tools.ietf.org/html/rfc5737> and <https://tools.ietf.org/html/rfc3849>.\n" \
- "\n" \
- "SRV names are names of SRV records.\n" \
- "\n" \
- "Unless otherwise specified, all resource records will use a default TTL. The default TTL can be set with the\n" \
- "--defaultTTL option. See \"Alias-TTL Labels\" and \"TTL Labels\" for details on how to query for CNAME, A, and\n" \
- "AAAA records with specific TTL values.\n"
-
-#define kDNSServerInfoText_AliasLabel \
- "Alias labels are of the form \"alias\" or \"alias-N\", where N is an integer in [2, 2^31 - 1].\n" \
- "\n" \
- "If QNAME is an Address name and its first label is Alias label \"alias-N\", then the response will contain\n" \
- "exactly N CNAME records:\n" \
- "\n" \
- " 1. For each i in [3, N], the response will contain a CNAME record whose name is identical to QNAME, except\n" \
- " that the first label is \"alias-i\" instead, and whose RDATA is the name of the other CNAME record whose\n" \
- " name has \"alias-(i - 1)\" as its first label.\n" \
- "\n" \
- " 2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n" \
- " is \"alias-2\" instead, and whose RDATA is the name identical to QNAME, except that the first label is\n" \
- " \"alias\" instead.\n" \
- "\n" \
- " 3. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n" \
- " is \"alias\" instead, and whose RDATA is the name identical to QNAME minus its first label.\n" \
- "\n" \
- "If QNAME is an Address name and its first label is Alias label \"alias\", then the response will contain a\n" \
- "single CNAME record. The CNAME record's name will be equal to QNAME and its RDATA will be the name identical to\n" \
- "QNAME minus its first label.\n" \
- "\n" \
- "Example. A response to a query with a QNAME of alias-3.count-5.d.test will contain the following CNAME\n" \
- "records:\n" \
- "\n" \
- " alias-4.count-5.d.test. 60 IN CNAME alias-3.count-5.d.test.\n" \
- " alias-3.count-5.d.test. 60 IN CNAME alias-2.count-5.d.test.\n" \
- " alias-2.count-5.d.test. 60 IN CNAME alias.count-5.d.test.\n" \
- " alias.count-5.d.test. 60 IN CNAME count-5.d.test.\n"
-
-#define kDNSServerInfoText_AliasTTLLabel \
- "Alias-TTL labels are of the form \"alias-ttl-T_1[-T_2[...-T_N]]\", where each T_i is an integer in\n" \
- "[0, 2^31 - 1] and N is a positive integer bounded by the size of the maximum legal label length (63 octets).\n" \
- "\n" \
- "If QNAME is an Address name and its first label is Alias-TTL label \"alias-ttl-T_1...-T_N\", then the response\n" \
- "will contain exactly N CNAME records:\n" \
- "\n" \
- " 1. For each i in [1, N - 1], the response will contain a CNAME record whose name is identical to QNAME,\n" \
- " except that the first label is \"alias-ttl-T_i...-T_N\" instead, whose TTL value is T_i, and whose RDATA\n" \
- " is the name of the other CNAME record whose name has \"alias-ttl-T_(i+1)...-T_N\" as its first label.\n" \
- "\n" \
- " 2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n" \
- " is \"alias-ttl-T_N\", whose TTL is T_N, and whose RDATA is identical to QNAME stripped of its first\n" \
- " label.\n" \
- "\n" \
- "Example. A response to a query with a QNAME of alias-ttl-20-40-80.count-5.d.test will contain the following\n" \
- "CNAME records:\n" \
- "\n" \
- " alias-ttl-20-40-80.count-5.d.test. 20 IN CNAME alias-ttl-40-80.count-5.d.test.\n" \
- " alias-ttl-40-80.count-5.d.test. 40 IN CNAME alias-ttl-80.count-5.d.test.\n" \
- " alias-ttl-80.count-5.d.test. 80 IN CNAME count-5.d.test.\n"
-
-#define kDNSServerInfoText_CountLabel \
- "Count labels are of the form \"count-N_1\" or \"count-N_1-N_2\", where N_1 is an integer in [1, 255] and N_2 is\n" \
- "an integer in [N_1, 255].\n" \
- "\n" \
- "If QNAME is an Address name, contains Count label \"count-N\", and has the type of address records specified by\n" \
- "QTYPE, then the response will contain exactly N address records:\n" \
- "\n" \
- " 1. For i in [1, N], the response will contain an address record of type QTYPE whose name is equal to QNAME\n" \
- " and whose RDATA is an address equal to a constant base address + i.\n" \
- "\n" \
- " 2. The address records will be ordered by the address contained in RDATA in ascending order.\n" \
- "\n" \
- "Example. A response to an A record query with a QNAME of alias.count-3.d.test will contain the following A\n" \
- "records:\n" \
- "\n" \
- " count-3.d.test. 60 IN A 203.0.113.1\n" \
- " count-3.d.test. 60 IN A 203.0.113.2\n" \
- " count-3.d.test. 60 IN A 203.0.113.3\n" \
- "\n" \
- "If QNAME is an Address name, contains Count label \"count-N_1-N_2\", and has the type of address records\n" \
- "specified by QTYPE, then the response will contain exactly N_1 address records:\n" \
- "\n" \
- " 1. Each of the address records will be of type QTYPE, have name equal to QNAME, and have as its RDATA a\n" \
- " unique address equal to a constant base address + i, where i is a randomly chosen integer in [1, N_2].\n" \
- "\n" \
- " 2. The order of the address records will be random.\n" \
- "\n" \
- "Example. A response to a AAAA record query with a QNAME of count-3-100.ttl-20.d.test could contain the\n" \
- "following AAAA records:\n" \
- "\n" \
- " count-3-100.ttl-20.d.test. 20 IN AAAA 2001:db8:1::c\n" \
- " count-3-100.ttl-20.d.test. 20 IN AAAA 2001:db8:1::3a\n" \
- " count-3-100.ttl-20.d.test. 20 IN AAAA 2001:db8:1::4f\n" \
- "\n" \
- "If QNAME is an Address name, but doesn't have the type of address records specified by QTYPE, then the response\n" \
- "will contain no address records, regardless of whether it contains a Count label.\n" \
- "\n" \
- "Address names that don't have a Count label are treated as though they contain a count label equal to\n" \
- "count-1\".\n"
-
-#define kDNSServerInfoText_TagLabel \
- "Tag labels are labels prefixed with \"tag-\" and contain zero or more arbitrary octets after the prefix.\n" \
- "\n" \
- "This type of label exists to allow testers to \"uniquify\" domain names. Tag labels can also serve as padding\n" \
- "to increase the sizes of domain names.\n"
-
-#define kDNSServerInfoText_TTLLabel \
- "TTL labels are of the form \"ttl-T\", where T is an integer in [0, 2^31 - 1].\n" \
- "\n" \
- "If QNAME is an Address name and contains TTL label \"ttl-T\", then all non-CNAME records contained in the\n" \
- "response will have a TTL value equal to T.\n"
-
-#define kDNSServerInfoText_IPv4Label \
- "The IPv4 label is \"ipv4\". See \"Resource Records\" for the affect of this label.\n"
-
-#define kDNSServerInfoText_IPv6Label \
- "The IPv6 label is \"ipv6\". See \"Resource Records\" for the affect of this label.\n"
-
-#define kDNSServerInfoText_SRVNames \
- "SRV labels are of the form \"srv-R-W-P\", where R, W, and P are integers in [0, 2^16 - 1].\n" \
- "\n" \
- "After the first two labels, i.e., the service and protocol labels, the sequence of labels, which may be empty,\n" \
- "leading up to the the first SRV label, if one exists, or the d.test. labels will be used as a parent domain for\n" \
- "the target hostname of each of the SRV name's SRV records.\n" \
- "\n" \
- "If QNAME is an SRV name and QTYPE is SRV, then for each SRV label, the response will contain an SRV record with\n" \
- "priority R, weight W, port P, and target hostname <target>[.<parent domain>]., where <target> is the sequence\n" \
- "of labels, which may be empty, that follows the SRV label leading up to either the next SRV label or the\n" \
- "d.test. labels, whichever comes first.\n" \
- "\n" \
- "Example. A response to an SRV record query with a QNAME of\n" \
- "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. will contain the following SRV records:\n" \
- "\n" \
- "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. 60 IN SRV 0 0 80 www.example.com.\n" \
- "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. 60 IN SRV 1 0 8080 www.example.com.\n"
-
-#define kDNSServerInfoText_BadUDPMode \
- "The purpose of Bad UDP mode is to test mDNSResponder's TCP fallback mechanism by which mDNSResponder reissues a\n" \
- "UDP query as a TCP query if the UDP response contains the expected QNAME, QTYPE, and QCLASS, but a message ID\n" \
- "that's not equal to the query's message ID.\n" \
- "\n" \
- "This mode is identical to the normal mode except that all responses sent via UDP have a message ID equal to the\n" \
- "query's message ID plus one. Also, in this mode, to aid in debugging, A records in responses sent via UDP have\n" \
- "IPv4 addresses in the 0.0.0.0/24 block instead of the 203.0.113.0/24 block, i.e., 0.0.0.0 is used as the IPv4\n" \
- "base address, and AAAA records in responses sent via UDP have IPv6 addresses in the ::ffff:0:0/120 block\n" \
- "instead of the 2001:db8:1::/120 block, i.e., ::ffff:0:0 is used as the IPv6 base address.\n"
-
-static int gDNSServer_LoopbackOnly = false;
-static int gDNSServer_Foreground = false;
-static int gDNSServer_ResponseDelayMs = 0;
-static int gDNSServer_DefaultTTL = 60;
-static int gDNSServer_Port = kDNSPort;
-static const char * gDNSServer_DomainOverride = NULL;
-#if( TARGET_OS_DARWIN )
-static const char * gDNSServer_FollowPID = NULL;
-#endif
-static int gDNSServer_BadUDPMode = false;
-
-static CLIOption kDNSServerOpts[] =
-{
- BooleanOption( 'l', "loopback", &gDNSServer_LoopbackOnly, "Bind to to the loopback interface." ),
- BooleanOption( 'f', "foreground", &gDNSServer_Foreground, "Direct log output to stdout instead of system logging." ),
- IntegerOption( 'd', "responseDelay", &gDNSServer_ResponseDelayMs, "ms", "The amount of additional delay in milliseconds to apply to responses. (default: 0)", false ),
- IntegerOption( 0 , "defaultTTL", &gDNSServer_DefaultTTL, "seconds", "Resource record TTL value to use when unspecified. (default: 60)", false ),
- IntegerOption( 'p', "port", &gDNSServer_Port, "port number", "UDP/TCP port number to use. Use 0 for any port. (default: 53)", false ),
- StringOption( 0 , "domain", &gDNSServer_DomainOverride, "domain", "Used to override 'd.test.' as the server's domain.", false ),
-#if( TARGET_OS_DARWIN )
- StringOption( 0 , "follow", &gDNSServer_FollowPID, "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
-#endif
- BooleanOption( 0 , "badUDPMode", &gDNSServer_BadUDPMode, "Run in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
-
- CLI_SECTION( "Intro", kDNSServerInfoText_Intro ),
- CLI_SECTION( "Name Existence", kDNSServerInfoText_NameExistence ),
- CLI_SECTION( "Resource Records", kDNSServerInfoText_ResourceRecords ),
- CLI_SECTION( "Alias Labels", kDNSServerInfoText_AliasLabel ),
- CLI_SECTION( "Alias-TTL Labels", kDNSServerInfoText_AliasTTLLabel ),
- CLI_SECTION( "Count Labels", kDNSServerInfoText_CountLabel ),
- CLI_SECTION( "Tag Labels", kDNSServerInfoText_TagLabel ),
- CLI_SECTION( "TTL Labels", kDNSServerInfoText_TTLLabel ),
- CLI_SECTION( "IPv4 Label", kDNSServerInfoText_IPv4Label ),
- CLI_SECTION( "IPv6 Label", kDNSServerInfoText_IPv6Label ),
- CLI_SECTION( "SRV Names", kDNSServerInfoText_SRVNames ),
- CLI_SECTION( "Bad UDP Mode", kDNSServerInfoText_BadUDPMode ),
- CLI_OPTION_END()
-};
-
-static void DNSServerCmd( void );
-
-//===========================================================================================================================
-// MDNSReplier Command Options
-//===========================================================================================================================
-
-#define kMDNSReplierPortBase 50000
-
-#define kMDNSReplierInfoText_Intro \
- "The mDNS replier answers mDNS queries for its authoritative records. These records are of class IN and of types\n" \
- "PTR, SRV, TXT, A, and AAAA as described below.\n" \
- "\n" \
- "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
-
-#define kMDNSReplierInfoText_Parameters \
- "There are five parameters that control the replier's set of authoritative records.\n" \
- "\n" \
- " 1. <hostname> is the base name used for service instance names and the names of A and AAAA records. This\n" \
- " parameter is specified with the --hostname option.\n" \
- " 2. <tag> is an arbitrary string used to uniquify service types. This parameter is specified with the --tag\n" \
- " option.\n" \
- " 3. N_max in an integer in [1, 65535] and limits service types to those that have no more than N_max\n" \
- " instances. It also limits the number of hostnames to N_max, i.e., <hostname>.local.,\n" \
- " <hostname>-1.local., ..., <hostname>-N_max.local. This parameter is specified with the\n" \
- " --maxInstanceCount option.\n" \
- " 4. N_a is an integer in [1, 255] and the number of A records per hostname. This parameter is specified\n" \
- " with the --countA option.\n" \
- " 5. N_aaaa is an integer in [1, 255] and the number of AAAA records per hostname. This parameter is\n" \
- " specified with the --countAAAA option.\n"
-
-#define kMDNSReplierInfoText_PTR \
- "The replier's authoritative PTR records have names of the form _t-<tag>-<L>-<N>._tcp.local., where L is an\n" \
- "integer in [1, 65535], and N is an integer in [1, N_max].\n" \
- "\n" \
- "For a given L and N, the replier has exactly N authoritative PTR records:\n" \
- "\n" \
- " 1. The first PTR record is defined as\n" \
- "\n" \
- " NAME: _t-<tag>-<L>-<N>._tcp.local.\n" \
- " TYPE: PTR\n" \
- " CLASS: IN\n" \
- " TTL: 4500\n" \
- " RDATA: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n" \
- "\n" \
- " 2. For each i in [2, N], there is one PTR record defined as\n" \
- "\n" \
- " NAME: _t-<tag>-<L>-<N>._tcp.local.\n" \
- " TYPE: PTR\n" \
- " CLASS: IN\n" \
- " TTL: 4500\n" \
- " RDATA: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"
-
-#define kMDNSReplierInfoText_SRV \
- "The replier's authoritative SRV records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n" \
- "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n" \
- "\"<hostname> (<i>)\", where i is in [2, N].\n" \
- "\n" \
- "For a given L and N, the replier has exactly N authoritative SRV records:\n" \
- "\n" \
- " 1. The first SRV record is defined as\n" \
- "\n" \
- " NAME: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n" \
- " TYPE: SRV\n" \
- " CLASS: IN\n" \
- " TTL: 120\n" \
- " RDATA:\n" \
- " Priority: 0\n" \
- " Weight: 0\n" \
- " Port: (50000 + L) mod 2^16\n" \
- " Target: <hostname>.local.\n" \
- "\n" \
- " 2. For each i in [2, N], there is one SRV record defined as:\n" \
- "\n" \
- " NAME: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n" \
- " TYPE: SRV\n" \
- " CLASS: IN\n" \
- " TTL: 120\n" \
- " RDATA:\n" \
- " Priority: 0\n" \
- " Weight: 0\n" \
- " Port: (50000 + L) mod 2^16\n" \
- " Target: <hostname>-<i>.local.\n"
-
-#define kMDNSReplierInfoText_TXT \
- "The replier's authoritative TXT records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n" \
- "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n" \
- "\"<hostname> (<i>)\", where i is in [2, N].\n" \
- "\n" \
- "For a given L and N, the replier has exactly N authoritative TXT records:\n" \
- "\n" \
- " 1. The first TXT record is defined as\n" \
- "\n" \
- " NAME: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n" \
- " TYPE: TXT\n" \
- " CLASS: IN\n" \
- " TTL: 4500\n" \
- " RDLENGTH: L\n" \
- " RDATA: <one or more strings with an aggregate length of L octets>\n" \
- "\n" \
- " 2. For each i in [2, N], there is one TXT record:\n" \
- "\n" \
- " NAME: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n" \
- " TYPE: TXT\n" \
- " CLASS: IN\n" \
- " TTL: 4500\n" \
- " RDLENGTH: L\n" \
- " RDATA: <one or more strings with an aggregate length of L octets>\n" \
- "\n" \
- "The RDATA of each TXT record is exactly L octets and consists of a repeating series of the 15-byte string\n" \
- "\"hash=0x<32-bit FNV-1 hash of the record name as an 8-character hexadecimal string>\". The last instance of\n" \
- "the string may be truncated to satisfy the TXT record data's size requirement.\n"
-
-#define kMDNSReplierInfoText_A \
- "The replier has exactly N_max x N_a authoritative A records:\n" \
- "\n" \
- " 1. For each j in [1, N_a], an A record is defined as\n" \
- "\n" \
- " NAME: <hostname>.local.\n" \
- " TYPE: A\n" \
- " CLASS: IN\n" \
- " TTL: 120\n" \
- " RDLENGTH: 4\n" \
- " RDATA: 0.0.1.<j>\n" \
- "\n" \
- " 2. For each i in [2, N_max], for each j in [1, N_a], an A record is defined as\n" \
- "\n" \
- " NAME: <hostname>-<i>.local.\n" \
- " TYPE: A\n" \
- " CLASS: IN\n" \
- " TTL: 120\n" \
- " RDLENGTH: 4\n" \
- " RDATA: 0.<ceil(i / 256)>.<i mod 256>.<j>\n"
-
-#define kMDNSReplierInfoText_AAAA \
- "The replier has exactly N_max x N_aaaa authoritative AAAA records:\n" \
- "\n" \
- " 1. For each j in [1, N_aaaa], a AAAA record is defined as\n" \
- "\n" \
- " NAME: <hostname>.local.\n" \
- " TYPE: AAAA\n" \
- " CLASS: IN\n" \
- " TTL: 120\n" \
- " RDLENGTH: 16\n" \
- " RDATA: 2001:db8:2::1:<j>\n" \
- "\n" \
- " 2. For each i in [2, N_max], for each j in [1, N_aaaa], a AAAA record is defined as\n" \
- "\n" \
- " NAME: <hostname>-<i>.local.\n" \
- " TYPE: AAAA\n" \
- " CLASS: IN\n" \
- " TTL: 120\n" \
- " RDLENGTH: 16\n" \
- " RDATA: 2001:db8:2::<i>:<j>\n"
-
-#define kMDNSReplierInfoText_Responses \
- "When generating answers for a query message, any two records pertaining to the same hostname will be grouped\n" \
- "together in the same response message, and any two records pertaining to different hostnames will be in\n" \
- "separate response messages.\n"
-
-static const char * gMDNSReplier_Hostname = NULL;
-static const char * gMDNSReplier_ServiceTypeTag = NULL;
-static int gMDNSReplier_MaxInstanceCount = 1000;
-static int gMDNSReplier_NoAdditionals = false;
-static int gMDNSReplier_RecordCountA = 1;
-static int gMDNSReplier_RecordCountAAAA = 1;
-static double gMDNSReplier_UnicastDropRate = 0.0;
-static double gMDNSReplier_MulticastDropRate = 0.0;
-static int gMDNSReplier_MaxDropCount = 0;
-static int gMDNSReplier_UseIPv4 = false;
-static int gMDNSReplier_UseIPv6 = false;
-static int gMDNSReplier_Foreground = false;
-static const char * gMDNSReplier_FollowPID = NULL;
-
-static CLIOption kMDNSReplierOpts[] =
-{
- StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
- StringOption( 'n', "hostname", &gMDNSReplier_Hostname, "string", "Base name to use for hostnames and service instance names.", true ),
- StringOption( 't', "tag", &gMDNSReplier_ServiceTypeTag, "string", "Tag to use for service types, e.g., _t-<tag>-<TXT size>-<count>._tcp.", true ),
- IntegerOption( 'c', "maxInstanceCount", &gMDNSReplier_MaxInstanceCount, "count", "Maximum number of service instances. (default: 1000)", false ),
- BooleanOption( 0 , "noAdditionals", &gMDNSReplier_NoAdditionals, "When answering queries, don't include any additional records." ),
- IntegerOption( 0 , "countA", &gMDNSReplier_RecordCountA, "count", "Number of A records per hostname. (default: 1)", false ),
- IntegerOption( 0 , "countAAAA", &gMDNSReplier_RecordCountAAAA, "count", "Number of AAAA records per hostname. (default: 1)", false ),
- DoubleOption( 0 , "udrop", &gMDNSReplier_UnicastDropRate, "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
- DoubleOption( 0 , "mdrop", &gMDNSReplier_MulticastDropRate, "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
- IntegerOption( 0 , "maxDropCount", &gMDNSReplier_MaxDropCount, "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
- BooleanOption( 0 , "ipv4", &gMDNSReplier_UseIPv4, "Use IPv4." ),
- BooleanOption( 0 , "ipv6", &gMDNSReplier_UseIPv6, "Use IPv6." ),
- BooleanOption( 'f', "foreground", &gMDNSReplier_Foreground, "Direct log output to stdout instead of system logging." ),
-#if( TARGET_OS_DARWIN )
- StringOption( 0 , "follow", &gMDNSReplier_FollowPID, "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
-#endif
-
- CLI_SECTION( "Intro", kMDNSReplierInfoText_Intro ),
- CLI_SECTION( "Authoritative Record Parameters", kMDNSReplierInfoText_Parameters ),
- CLI_SECTION( "Authoritative PTR Records", kMDNSReplierInfoText_PTR ),
- CLI_SECTION( "Authoritative SRV Records", kMDNSReplierInfoText_SRV ),
- CLI_SECTION( "Authoritative TXT Records", kMDNSReplierInfoText_TXT ),
- CLI_SECTION( "Authoritative A Records", kMDNSReplierInfoText_A ),
- CLI_SECTION( "Authoritative AAAA Records", kMDNSReplierInfoText_AAAA ),
- CLI_SECTION( "Responses", kMDNSReplierInfoText_Responses ),
- CLI_OPTION_END()
-};
-
-static void MDNSReplierCmd( void );
-
-//===========================================================================================================================
-// Test Command Options
-//===========================================================================================================================
-
-#define kTestExitStatusSection_Name "Exit Status"
-#define kTestExitStatusSection_Text \
- "This test command can exit with one of three status codes:\n" \
- "\n" \
- "0 - The test ran to completion and passed.\n" \
- "1 - A fatal error prevented the test from completing.\n" \
- "2 - The test ran to completion, but it or a subtest failed. See test output for details.\n" \
- "\n" \
- "Note: The pass/fail status applies to the correctness or results. It does not necessarily imply anything about\n" \
- "performance.\n"
-
-#define TestExitStatusSection() CLI_SECTION( kTestExitStatusSection_Name, kTestExitStatusSection_Text )
-
-#define kGAIPerfTestSuiteName_Basic "basic"
-#define kGAIPerfTestSuiteName_Advanced "advanced"
-
-static const char * gGAIPerf_TestSuite = NULL;
-static int gGAIPerf_CallDelayMs = 10;
-static int gGAIPerf_ServerDelayMs = 10;
-static int gGAIPerf_SkipPathEvalulation = false;
-static int gGAIPerf_BadUDPMode = false;
-static int gGAIPerf_IterationCount = 100;
-static const char * gGAIPerf_OutputFilePath = NULL;
-static const char * gGAIPerf_OutputFormat = kOutputFormatStr_JSON;
-static int gGAIPerf_OutputAppendNewline = false;
-
-static void GAIPerfCmd( void );
-
-#define kGAIPerfSectionText_TestSuiteBasic \
- "This test suite consists of the following three test cases:\n" \
- "\n" \
- "Test Case #1: Resolve a domain name with\n" \
- "\n" \
- " 2 CNAME records, 4 A records, and 4 AAAA records\n" \
- "\n" \
- "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n" \
- "server queries.\n" \
- "\n" \
- "Test Case #2: Resolve a domain name with\n" \
- "\n" \
- " 2 CNAME records, 4 A records, and 4 AAAA records\n" \
- "\n" \
- "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n" \
- "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n" \
- "which should ideally require no additional server queries, i.e., the results should come from the cache.\n" \
- "\n" \
- "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n" \
- "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n" \
- "domain name in the preliminary iteration isn't counted in the performance stats.\n" \
- "\n" \
- "Test Case #3: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
-
-#define kGAIPerfSectionText_TestSuiteAdvanced \
- "This test suite consists of 33 test cases. Test cases 1 through 32 can be described in the following way\n" \
- "\n" \
- "Test Case #N (where N is in [1, 32] and odd): Resolve a domain name with\n" \
- "\n" \
- " N_c CNAME records, N_a A records, and N_a AAAA records\n" \
- "\n" \
- "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n" \
- "server queries.\n" \
- "\n" \
- "Test Case #N (where N is in [1, 32] and even): Resolve a domain name with\n" \
- "\n" \
- " N_c CNAME records, N_a A records, and N_a AAAA records\n" \
- "\n" \
- "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n" \
- "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n" \
- "which should ideally require no additional server queries, i.e., the results should come from the cache.\n" \
- "\n" \
- "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n" \
- "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n" \
- "domain name in the preliminary iteration isn't counted in the performance stats.\n" \
- "\n" \
- "N_c and N_a take on the following values, depending on the value of N:\n" \
- "\n" \
- " N_c is 0 if N is in [1, 8].\n" \
- " N_c is 1 if N is in [9, 16].\n" \
- " N_c is 2 if N is in [17, 24].\n" \
- " N_c is 4 if N is in [25, 32].\n" \
- "\n" \
- " N_a is 1 if N mod 8 is 1 or 2.\n" \
- " N_a is 2 if N mod 8 is 3 or 4.\n" \
- " N_a is 4 if N mod 8 is 5 or 6.\n" \
- " N_a is 8 if N mod 8 is 7 or 0.\n" \
- "\n" \
- "Finally,\n" \
- "\n" \
- "Test Case #33: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
-
-static CLIOption kGAIPerfOpts[] =
-{
- StringOptionEx( 's', "suite", &gGAIPerf_TestSuite, "name", "Name of the predefined test suite to run.", true,
- "\n"
- "There are currently two predefined test suites, '" kGAIPerfTestSuiteName_Basic "' and '" kGAIPerfTestSuiteName_Advanced "', which are described below.\n"
- "\n"
- ),
- StringOption( 'o', "output", &gGAIPerf_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
- FormatOption( 'f', "format", &gGAIPerf_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
- BooleanOption( 'n', "appendNewline", &gGAIPerf_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
- IntegerOption( 0 , "callDelay", &gGAIPerf_CallDelayMs, "ms", "Time to wait before calling DNSServiceGetAddrInfo() in milliseconds. (default: 10)", false ),
- BooleanOption( 0 , "skipPathEval", &gGAIPerf_SkipPathEvalulation, "Use kDNSServiceFlagsPathEvaluationDone when calling DNSServiceGetAddrInfo()." ),
- IntegerOption( 'i', "iterations", &gGAIPerf_IterationCount, "count", "The number of iterations per test case. (default: 100)", false ),
-
- CLI_OPTION_GROUP( "DNS Server Options" ),
- IntegerOption( 0 , "responseDelay", &gGAIPerf_ServerDelayMs, "ms", "Additional delay in milliseconds to have the server apply to responses. (default: 10)", false ),
- BooleanOption( 0 , "badUDPMode", &gGAIPerf_BadUDPMode, "Run server in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
-
- CLI_SECTION( "Test Suite \"Basic\"", kGAIPerfSectionText_TestSuiteBasic ),
- CLI_SECTION( "Test Suite \"Advanced\"", kGAIPerfSectionText_TestSuiteAdvanced ),
- TestExitStatusSection(),
- CLI_OPTION_END()
-};
-
-static void MDNSDiscoveryTestCmd( void );
-
-static int gMDNSDiscoveryTest_InstanceCount = 100;
-static int gMDNSDiscoveryTest_TXTSize = 100;
-static int gMDNSDiscoveryTest_BrowseTimeSecs = 2;
-static int gMDNSDiscoveryTest_FlushCache = false;
-static char * gMDNSDiscoveryTest_Interface = NULL;
-static int gMDNSDiscoveryTest_NoAdditionals = false;
-static int gMDNSDiscoveryTest_RecordCountA = 1;
-static int gMDNSDiscoveryTest_RecordCountAAAA = 1;
-static double gMDNSDiscoveryTest_UnicastDropRate = 0.0;
-static double gMDNSDiscoveryTest_MulticastDropRate = 0.0;
-static int gMDNSDiscoveryTest_MaxDropCount = 0;
-static int gMDNSDiscoveryTest_UseIPv4 = false;
-static int gMDNSDiscoveryTest_UseIPv6 = false;
-static const char * gMDNSDiscoveryTest_OutputFormat = kOutputFormatStr_JSON;
-static int gMDNSDiscoveryTest_OutputAppendNewline = false;
-static const char * gMDNSDiscoveryTest_OutputFilePath = NULL;
-
-static CLIOption kMDNSDiscoveryTestOpts[] =
-{
- IntegerOption( 'c', "instanceCount", &gMDNSDiscoveryTest_InstanceCount, "count", "Number of service instances to discover. (default: 100)", false ),
- IntegerOption( 's', "txtSize", &gMDNSDiscoveryTest_TXTSize, "bytes", "Desired size of each service instance's TXT record data. (default: 100)", false ),
- IntegerOption( 'b', "browseTime", &gMDNSDiscoveryTest_BrowseTimeSecs, "seconds", "Amount of time to spend browsing in seconds. (default: 2)", false ),
- BooleanOption( 0 , "flushCache", &gMDNSDiscoveryTest_FlushCache, "Flush mDNSResponder's record cache before browsing. Requires root privileges." ),
-
- CLI_OPTION_GROUP( "mDNS Replier Parameters" ),
- StringOption( 'i', "interface", &gMDNSDiscoveryTest_Interface, "name or index", "Network interface. If unspecified, any available mDNS-capable interface will be used.", false ),
- BooleanOption( 0 , "noAdditionals", &gMDNSDiscoveryTest_NoAdditionals, "When answering queries, don't include any additional records." ),
- IntegerOption( 0 , "countA", &gMDNSDiscoveryTest_RecordCountA, "count", "Number of A records per hostname. (default: 1)", false ),
- IntegerOption( 0 , "countAAAA", &gMDNSDiscoveryTest_RecordCountAAAA, "count", "Number of AAAA records per hostname. (default: 1)", false ),
- DoubleOption( 0 , "udrop", &gMDNSDiscoveryTest_UnicastDropRate, "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
- DoubleOption( 0 , "mdrop", &gMDNSDiscoveryTest_MulticastDropRate, "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
- IntegerOption( 0 , "maxDropCount", &gMDNSDiscoveryTest_MaxDropCount, "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
- BooleanOption( 0 , "ipv4", &gMDNSDiscoveryTest_UseIPv4, "Use IPv4." ),
- BooleanOption( 0 , "ipv6", &gMDNSDiscoveryTest_UseIPv6, "Use IPv6." ),
-
- CLI_OPTION_GROUP( "Results" ),
- FormatOption( 'f', "format", &gMDNSDiscoveryTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
- StringOption( 'o', "output", &gMDNSDiscoveryTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
- BooleanOption( 'n', "appendNewline", &gMDNSDiscoveryTest_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-
- TestExitStatusSection(),
- CLI_OPTION_END()
-};
-
-static void DotLocalTestCmd( void );
-
-static const char * gDotLocalTest_Interface = NULL;
-static const char * gDotLocalTest_OutputFormat = kOutputFormatStr_JSON;
-static int gDotLocalTest_OutputAppendNewline = false;
-static const char * gDotLocalTest_OutputFilePath = NULL;
-
-#define kDotLocalTestSubtestDesc_GAIMDNSOnly "GAI for a dotlocal name that has only MDNS A and AAAA records."
-#define kDotLocalTestSubtestDesc_GAIDNSOnly "GAI for a dotlocal name that has only DNS A and AAAA records."
-#define kDotLocalTestSubtestDesc_GAIBoth "GAI for a dotlocal name that has both mDNS and DNS A and AAAA records."
-#define kDotLocalTestSubtestDesc_GAINeither "GAI for a dotlocal name that has no A or AAAA records."
-#define kDotLocalTestSubtestDesc_GAINoSuchRecord \
- "GAI for a dotlocal name that has no A or AAAA records, but is a subdomain name of a search domain."
-#define kDotLocalTestSubtestDesc_QuerySRV "SRV query for a dotlocal name that has only a DNS SRV record."
-
-#define kDotLocalTestSectionText_Description \
- "The goal of the dotlocal test is to verify that mDNSResponder properly handles queries for domain names in the\n" \
- "local domain when a local SOA record exists. As part of the test setup, a test DNS server and an mdnsreplier are\n" \
- "spawned, and a dummy local SOA record is registered with DNSServiceRegisterRecord(). The server is invoked such\n" \
- "that its domain is a second-level subdomain of the local domain, i.e., <some label>.local, while the mdnsreplier is\n" \
- "invoked such that its base hostname is equal to the server's domain, e.g., if the server's domain is test.local.,\n" \
- "then the mdnsreplier's base hostname is test.local.\n" \
- "\n" \
- "The dotlocal test consists of six subtests that perform either a DNSServiceGetAddrInfo (GAI) operation for a\n" \
- "hostname in the local domain or a DNSServiceQueryRecord operation to query for an SRV record in the local domain:\n" \
- "\n" \
- "1. " kDotLocalTestSubtestDesc_GAIMDNSOnly "\n" \
- "2. " kDotLocalTestSubtestDesc_GAIDNSOnly "\n" \
- "3. " kDotLocalTestSubtestDesc_GAIBoth "\n" \
- "4. " kDotLocalTestSubtestDesc_GAINeither "\n" \
- "5. " kDotLocalTestSubtestDesc_GAINoSuchRecord "\n" \
- "6. " kDotLocalTestSubtestDesc_QuerySRV "\n" \
- "\n" \
- "Each subtest runs for five seconds.\n"
-
-static CLIOption kDotLocalTestOpts[] =
-{
- StringOption( 'i', "interface", &gDotLocalTest_Interface, "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
-
- CLI_OPTION_GROUP( "Results" ),
- FormatOption( 'f', "format", &gDotLocalTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
- StringOption( 'o', "output", &gDotLocalTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
- BooleanOption( 'n', "appendNewline", &gDotLocalTest_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-
- CLI_SECTION( "Description", kDotLocalTestSectionText_Description ),
- TestExitStatusSection(),
- CLI_OPTION_END()
-};
-
-static void ProbeConflictTestCmd( void );
-
-static const char * gProbeConflictTest_Interface = NULL;
-static int gProbeConflictTest_UseComputerName = false;
-static const char * gProbeConflictTest_OutputFormat = kOutputFormatStr_JSON;
-static int gProbeConflictTest_OutputAppendNewline = false;
-static const char * gProbeConflictTest_OutputFilePath = NULL;
-
-static CLIOption kProbeConflictTestOpts[] =
-{
- StringOption( 'i', "interface", &gProbeConflictTest_Interface, "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
- BooleanOption( 'c', "useComputerName", &gProbeConflictTest_UseComputerName, "Use the device's \"computer name\" for the test service's name." ),
-
- CLI_OPTION_GROUP( "Results" ),
- FormatOption( 'f', "format", &gProbeConflictTest_OutputFormat, "Specifies the test report output format. (default: " kOutputFormatStr_JSON ")", false ),
- StringOption( 'o', "output", &gProbeConflictTest_OutputFilePath, "path", "Path of the file to write test report to instead of standard output (stdout).", false ),
- BooleanOption( 'n', "appendNewline", &gProbeConflictTest_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-
- TestExitStatusSection(),
- CLI_OPTION_END()
-};
-
-static CLIOption kTestOpts[] =
-{
- Command( "gaiperf", GAIPerfCmd, kGAIPerfOpts, "Runs DNSServiceGetAddrInfo() performance tests.", false ),
- Command( "mdnsdiscovery", MDNSDiscoveryTestCmd, kMDNSDiscoveryTestOpts, "Tests mDNS service discovery for correctness.", false ),
- Command( "dotlocal", DotLocalTestCmd, kDotLocalTestOpts, "Tests DNS and mDNS queries for domain names in the local domain.", false ),
- Command( "probeconflicts", ProbeConflictTestCmd, kProbeConflictTestOpts, "Tests various probing conflict scenarios.", false ),
-
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// SSDP Command Options
-//===========================================================================================================================
-
-static int gSSDPDiscover_MX = 1;
-static const char * gSSDPDiscover_ST = "ssdp:all";
-static int gSSDPDiscover_ReceiveSecs = 1;
-static int gSSDPDiscover_UseIPv4 = false;
-static int gSSDPDiscover_UseIPv6 = false;
-static int gSSDPDiscover_Verbose = false;
-
-static CLIOption kSSDPDiscoverOpts[] =
-{
- StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
- IntegerOption( 'm', "mx", &gSSDPDiscover_MX, "seconds", "MX value in search request, i.e., max response delay in seconds. (Default: 1 second)", false ),
- StringOption( 's', "st", &gSSDPDiscover_ST, "string", "ST value in search request, i.e., the search target. (Default: \"ssdp:all\")", false ),
- IntegerOption( 'r', "receiveTime", &gSSDPDiscover_ReceiveSecs, "seconds", "Amount of time to spend receiving responses. -1 means unlimited. (Default: 1 second)", false ),
- BooleanOption( 0 , "ipv4", &gSSDPDiscover_UseIPv4, "Use IPv4, i.e., multicast to 239.255.255.250:1900." ),
- BooleanOption( 0 , "ipv6", &gSSDPDiscover_UseIPv6, "Use IPv6, i.e., multicast to [ff02::c]:1900" ),
- BooleanOption( 'v', "verbose", &gSSDPDiscover_Verbose, "Prints the search request(s) that were sent." ),
- CLI_OPTION_END()
-};
-
-static void SSDPDiscoverCmd( void );
-
-static CLIOption kSSDPOpts[] =
-{
- Command( "discover", SSDPDiscoverCmd, kSSDPDiscoverOpts, "Crafts and multicasts an SSDP search message.", false ),
- CLI_OPTION_END()
-};
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// res_query Command Options
-//===========================================================================================================================
-
-static void ResQueryCmd( void );
-
-static const char * gResQuery_Name = NULL;
-static const char * gResQuery_Type = NULL;
-static const char * gResQuery_Class = NULL;
-static int gResQuery_UseLibInfo = false;
-
-static CLIOption kResQueryOpts[] =
-{
- StringOption( 'n', "name", &gResQuery_Name, "domain name", "Full domain name of record to query.", true ),
- StringOption( 't', "type", &gResQuery_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
- StringOption( 'c', "class", &gResQuery_Class, "record class", "Record class by name or number. Default class is IN.", false ),
- BooleanOption( 0 , "libinfo", &gResQuery_UseLibInfo, "Use res_query from libinfo instead of libresolv." ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// dns_query Command Options
-//===========================================================================================================================
-
-static void ResolvDNSQueryCmd( void );
-
-static const char * gResolvDNSQuery_Name = NULL;
-static const char * gResolvDNSQuery_Type = NULL;
-static const char * gResolvDNSQuery_Class = NULL;
-static const char * gResolvDNSQuery_Path = NULL;
-
-static CLIOption kResolvDNSQueryOpts[] =
-{
- StringOption( 'n', "name", &gResolvDNSQuery_Name, "domain name", "Full domain name of record to query.", true ),
- StringOption( 't', "type", &gResolvDNSQuery_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
- StringOption( 'c', "class", &gResolvDNSQuery_Class, "record class", "Record class by name or number. Default class is IN.", false ),
- StringOption( 'p', "path", &gResolvDNSQuery_Path, "file path", "The path argument to pass to dns_open() before calling dns_query(). Default value is NULL.", false ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// CFHost Command Options
-//===========================================================================================================================
-
-static void CFHostCmd( void );
-
-static const char * gCFHost_Name = NULL;
-static int gCFHost_WaitSecs = 0;
-
-static CLIOption kCFHostOpts[] =
-{
- StringOption( 'n', "name", &gCFHost_Name, "hostname", "Hostname to resolve.", true ),
- IntegerOption( 'w', "wait", &gCFHost_WaitSecs, "seconds", "Time in seconds to wait before a normal exit. (default: 0)", false ),
- CLI_OPTION_END()
-};
-
-static CLIOption kLegacyOpts[] =
-{
- Command( "res_query", ResQueryCmd, kResQueryOpts, "Uses res_query() from either libresolv or libinfo to query for a record.", true ),
- Command( "dns_query", ResolvDNSQueryCmd, kResolvDNSQueryOpts, "Uses dns_query() from libresolv to query for a record.", true ),
- Command( "cfhost", CFHostCmd, kCFHostOpts, "Uses CFHost to resolve a hostname.", true ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// DNSConfigAdd Command Options
-//===========================================================================================================================
-
-static void DNSConfigAddCmd( void );
-
-static CFStringRef gDNSConfigAdd_ID = NULL;
-static char ** gDNSConfigAdd_IPAddrArray = NULL;
-static size_t gDNSConfigAdd_IPAddrCount = 0;
-static char ** gDNSConfigAdd_DomainArray = NULL;
-static size_t gDNSConfigAdd_DomainCount = 0;
-static const char * gDNSConfigAdd_Interface = NULL;
-
-static CLIOption kDNSConfigAddOpts[] =
-{
- CFStringOption( 0 , "id", &gDNSConfigAdd_ID, "ID", "Arbitrary ID to use for resolver entry.", true ),
- MultiStringOption( 'a', "address", &gDNSConfigAdd_IPAddrArray, &gDNSConfigAdd_IPAddrCount, "IP address", "DNS server IP address(es). Can be specified more than once.", true ),
- MultiStringOption( 'd', "domain", &gDNSConfigAdd_DomainArray, &gDNSConfigAdd_DomainCount, "domain", "Specific domain(s) for the resolver entry. Can be specified more than once.", false ),
- StringOption( 'i', "interface", &gDNSConfigAdd_Interface, "interface name", "Specific interface for the resolver entry.", false ),
-
- CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// DNSConfigRemove Command Options
-//===========================================================================================================================
-
-static void DNSConfigRemoveCmd( void );
-
-static CFStringRef gDNSConfigRemove_ID = NULL;
-
-static CLIOption kDNSConfigRemoveOpts[] =
-{
- CFStringOption( 0, "id", &gDNSConfigRemove_ID, "ID", "ID of resolver entry to remove.", true ),
-
- CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
- CLI_OPTION_END()
-};
-
-static CLIOption kDNSConfigOpts[] =
-{
- Command( "add", DNSConfigAddCmd, kDNSConfigAddOpts, "Add a supplemental resolver entry to the system's DNS configuration.", true ),
- Command( "remove", DNSConfigRemoveCmd, kDNSConfigRemoveOpts, "Remove a supplemental resolver entry from the system's DNS configuration.", true ),
- CLI_OPTION_END()
-};
-#endif // TARGET_OS_DARWIN
-
-//===========================================================================================================================
-// Command Table
-//===========================================================================================================================
-
-static OSStatus VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset );
-
-static void BrowseCmd( void );
-static void GetAddrInfoCmd( void );
-static void QueryRecordCmd( void );
-static void RegisterCmd( void );
-static void RegisterRecordCmd( void );
-static void ResolveCmd( void );
-static void ReconfirmCmd( void );
-static void GetAddrInfoPOSIXCmd( void );
-static void ReverseLookupCmd( void );
-static void PortMappingCmd( void );
-static void BrowseAllCmd( void );
-static void GetAddrInfoStressCmd( void );
-static void DNSQueryCmd( void );
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-static void DNSCryptCmd( void );
-#endif
-static void MDNSQueryCmd( void );
-static void PIDToUUIDCmd( void );
-static void DaemonVersionCmd( void );
-
-static CLIOption kGlobalOpts[] =
-{
- CLI_OPTION_CALLBACK_EX( 'V', "version", VersionOptionCallback, NULL, NULL,
- kCLIOptionFlags_NoArgument | kCLIOptionFlags_GlobalOnly, "Displays the version of this tool.", NULL ),
- CLI_OPTION_HELP(),
-
- // Common commands.
-
- Command( "browse", BrowseCmd, kBrowseOpts, "Uses DNSServiceBrowse() to browse for one or more service types.", false ),
- Command( "getAddrInfo", GetAddrInfoCmd, kGetAddrInfoOpts, "Uses DNSServiceGetAddrInfo() to resolve a hostname to IP addresses.", false ),
- Command( "queryRecord", QueryRecordCmd, kQueryRecordOpts, "Uses DNSServiceQueryRecord() to query for an arbitrary DNS record.", false ),
- Command( "register", RegisterCmd, kRegisterOpts, "Uses DNSServiceRegister() to register a service.", false ),
- Command( "registerRecord", RegisterRecordCmd, kRegisterRecordOpts, "Uses DNSServiceRegisterRecord() to register a record.", false ),
- Command( "resolve", ResolveCmd, kResolveOpts, "Uses DNSServiceResolve() to resolve a service.", false ),
- Command( "reconfirm", ReconfirmCmd, kReconfirmOpts, "Uses DNSServiceReconfirmRecord() to reconfirm a record.", false ),
- Command( "getaddrinfo-posix", GetAddrInfoPOSIXCmd, kGetAddrInfoPOSIXOpts, "Uses getaddrinfo() to resolve a hostname to IP addresses.", false ),
- Command( "reverseLookup", ReverseLookupCmd, kReverseLookupOpts, "Uses DNSServiceQueryRecord() to perform a reverse IP address lookup.", false ),
- Command( "portMapping", PortMappingCmd, kPortMappingOpts, "Uses DNSServiceNATPortMappingCreate() to create a port mapping.", false ),
- Command( "browseAll", BrowseAllCmd, kBrowseAllOpts, "Browse and resolve all (or specific) services and, optionally, attempt connections.", false ),
-
- // Uncommon commands.
-
- Command( "getnameinfo", GetNameInfoCmd, kGetNameInfoOpts, "Calls getnameinfo() and prints results.", true ),
- Command( "getAddrInfoStress", GetAddrInfoStressCmd, kGetAddrInfoStressOpts, "Runs DNSServiceGetAddrInfo() stress testing.", true ),
- Command( "DNSQuery", DNSQueryCmd, kDNSQueryOpts, "Crafts and sends a DNS query.", true ),
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
- Command( "DNSCrypt", DNSCryptCmd, kDNSCryptOpts, "Crafts and sends a DNSCrypt query.", true ),
-#endif
- Command( "mdnsquery", MDNSQueryCmd, kMDNSQueryOpts, "Crafts and sends an mDNS query over the specified interface.", true ),
- Command( "mdnscollider", MDNSColliderCmd, kMDNSColliderOpts, "Creates record name collision scenarios.", true ),
- Command( "pid2uuid", PIDToUUIDCmd, kPIDToUUIDOpts, "Prints the UUID of a process.", true ),
- Command( "server", DNSServerCmd, kDNSServerOpts, "DNS server for testing.", true ),
- Command( "mdnsreplier", MDNSReplierCmd, kMDNSReplierOpts, "Responds to mDNS queries for a set of authoritative resource records.", true ),
- Command( "test", NULL, kTestOpts, "Commands for testing DNS-SD.", true ),
- Command( "ssdp", NULL, kSSDPOpts, "Commands for testing Simple Service Discovery Protocol (SSDP).", true ),
-#if( TARGET_OS_DARWIN )
- Command( "legacy", NULL, kLegacyOpts, "Commands for legacy non-DNS-SD API.", true ),
- Command( "dnsconfig", NULL, kDNSConfigOpts, "Add/remove a supplemental resolver entry to/from the system's DNS configuration.", true ),
-#endif
- Command( "daemonVersion", DaemonVersionCmd, NULL, "Prints the version of the DNS-SD daemon.", true ),
-
- CLI_COMMAND_HELP(),
- CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-// Helper Prototypes
-//===========================================================================================================================
-
-#define kExitReason_OneShotDone "one-shot done"
-#define kExitReason_ReceivedResponse "received response"
-#define kExitReason_SIGINT "interrupt signal"
-#define kExitReason_Timeout "timeout"
-#define kExitReason_TimeLimit "time limit"
-
-static void Exit( void *inContext ) ATTRIBUTE_NORETURN;
-
-static int
- PrintFTimestampHandler(
- PrintFContext * inContext,
- PrintFFormat * inFormat,
- PrintFVAList * inArgs,
- void * inUserContext );
-static int
- PrintFDNSMessageHandler(
- PrintFContext * inContext,
- PrintFFormat * inFormat,
- PrintFVAList * inArgs,
- void * inUserContext );
-static int
- PrintFAddRmvFlagsHandler(
- PrintFContext * inContext,
- PrintFFormat * inFormat,
- PrintFVAList * inArgs,
- void * inUserContext );
-
-static DNSServiceFlags GetDNSSDFlagsFromOpts( void );
-
-typedef enum
-{
- kConnectionType_None = 0,
- kConnectionType_Normal = 1,
- kConnectionType_DelegatePID = 2,
- kConnectionType_DelegateUUID = 3
-
-} ConnectionType;
-
-typedef struct
-{
- ConnectionType type;
- union
- {
- int32_t pid;
- uint8_t uuid[ 16 ];
-
- } delegate;
-
-} ConnectionDesc;
-
-static OSStatus
- CreateConnectionFromArgString(
- const char * inString,
- dispatch_queue_t inQueue,
- DNSServiceRef * outSDRef,
- ConnectionDesc * outDesc );
-static OSStatus InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex );
-static OSStatus RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen );
-static OSStatus RecordTypeFromArgString( const char *inString, uint16_t *outValue );
-static OSStatus RecordClassFromArgString( const char *inString, uint16_t *outValue );
-
-#define kInterfaceNameBufLen ( Max( IF_NAMESIZE, 16 ) + 1 )
-
-static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] );
-static const char * RecordTypeToString( unsigned int inValue );
-
-static OSStatus
- DNSMessageExtractDomainName(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const uint8_t * inNamePtr,
- uint8_t inBuf[ kDomainNameLengthMax ],
- const uint8_t ** outNextPtr );
-static OSStatus
- DNSMessageExtractDomainNameString(
- const void * inMsgPtr,
- size_t inMsgLen,
- const void * inNamePtr,
- char inBuf[ kDNSServiceMaxDomainName ],
- const uint8_t ** outNextPtr );
-static OSStatus
- DNSMessageExtractQuestion(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const uint8_t * inPtr,
- uint8_t inNameBuf[ kDomainNameLengthMax ],
- uint16_t * outType,
- uint16_t * outClass,
- const uint8_t ** outPtr );
-static OSStatus
- DNSMessageExtractRecord(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const uint8_t * inPtr,
- uint8_t inNameBuf[ kDomainNameLengthMax ],
- uint16_t * outType,
- uint16_t * outClass,
- uint32_t * outTTL,
- const uint8_t ** outRDataPtr,
- size_t * outRDataLen,
- const uint8_t ** outPtr );
-static OSStatus DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr );
-static OSStatus
- DNSRecordDataToString(
- const void * inRDataPtr,
- size_t inRDataLen,
- unsigned int inRDataType,
- const void * inMsgPtr,
- size_t inMsgLen,
- char ** outString );
-static OSStatus
- DomainNameAppendString(
- uint8_t inDomainName[ kDomainNameLengthMax ],
- const char * inString,
- uint8_t ** outEndPtr );
-static Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 );
-static size_t DomainNameLength( const uint8_t *inName );
-static OSStatus DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen );
-#define DomainNameDup( IN_NAME, OUT_NAME, OUT_LEN ) DomainNameDupEx( IN_NAME, false, OUT_NAME, OUT_LEN )
-#define DomainNameDupLower( IN_NAME, OUT_NAME, OUT_LEN ) DomainNameDupEx( IN_NAME, true, OUT_NAME, OUT_LEN )
-
-static OSStatus
- DomainNameFromString(
- uint8_t inDomainName[ kDomainNameLengthMax ],
- const char * inString,
- uint8_t ** outEndPtr );
-static OSStatus
- DomainNameToString(
- const uint8_t * inDomainName,
- const uint8_t * inEnd,
- char inBuf[ kDNSServiceMaxDomainName ],
- const uint8_t ** outNextPtr );
-
-static OSStatus
- DNSMessageToText(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- Boolean inIsMDNS,
- Boolean inPrintRaw,
- char ** outText );
-
-#define kDNSQueryMessageMaxLen ( kDNSHeaderLength + kDomainNameLengthMax + 4 )
-
-static OSStatus
- WriteDNSQueryMessage(
- uint8_t inMsg[ kDNSQueryMessageMaxLen ],
- uint16_t inMsgID,
- uint16_t inFlags,
- const char * inQName,
- uint16_t inQType,
- uint16_t inQClass,
- size_t * outMsgLen );
-
-// Dispatch helpers
-
-typedef void ( *DispatchHandler )( void *inContext );
-
-static OSStatus
- DispatchSignalSourceCreate(
- int inSignal,
- DispatchHandler inEventHandler,
- void * inContext,
- dispatch_source_t * outSource );
-static OSStatus
- DispatchSocketSourceCreate(
- SocketRef inSock,
- dispatch_source_type_t inType,
- dispatch_queue_t inQueue,
- DispatchHandler inEventHandler,
- DispatchHandler inCancelHandler,
- void * inContext,
- dispatch_source_t * outSource );
-
-#define DispatchReadSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
- DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_READ, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
-
-#define DispatchWriteSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
- DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_WRITE, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
-
-static OSStatus
- DispatchTimerCreate(
- dispatch_time_t inStart,
- uint64_t inIntervalNs,
- uint64_t inLeewayNs,
- dispatch_queue_t inQueue,
- DispatchHandler inEventHandler,
- DispatchHandler inCancelHandler,
- void * inContext,
- dispatch_source_t * outTimer );
-
-#define DispatchTimerOneShotCreate( IN_START, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, IN_CONTEXT, OUT_TIMER ) \
- DispatchTimerCreate( IN_START, DISPATCH_TIME_FOREVER, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, NULL, IN_CONTEXT, OUT_TIMER )
-
-static OSStatus
- DispatchProcessMonitorCreate(
- pid_t inPID,
- unsigned long inFlags,
- dispatch_queue_t inQueue,
- DispatchHandler inEventHandler,
- DispatchHandler inCancelHandler,
- void * inContext,
- dispatch_source_t * outMonitor );
-
-static const char * ServiceTypeDescription( const char *inName );
-
-typedef struct
-{
- SocketRef sock; // Socket.
- void * userContext; // User context.
- int32_t refCount; // Reference count.
-
-} SocketContext;
-
-static OSStatus SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext );
-static SocketContext * SocketContextRetain( SocketContext *inContext );
-static void SocketContextRelease( SocketContext *inContext );
-static void SocketContextCancelHandler( void *inContext );
-
-#define ForgetSocketContext( X ) ForgetCustom( X, SocketContextRelease )
-
-static OSStatus StringToInt32( const char *inString, int32_t *outValue );
-static OSStatus StringToUInt32( const char *inString, uint32_t *outValue );
-#if( TARGET_OS_DARWIN )
-static OSStatus StringToPID( const char *inString, pid_t *outPID );
-#endif
-static OSStatus StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
-static OSStatus StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
-static OSStatus StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen );
-#if( TARGET_OS_DARWIN )
-static OSStatus GetDefaultDNSServer( sockaddr_ip *outAddr );
-#endif
-static OSStatus
- _ServerSocketOpenEx2(
- int inFamily,
- int inType,
- int inProtocol,
- const void * inAddr,
- int inPort,
- int * outPort,
- int inRcvBufSize,
- Boolean inNoPortReuse,
- SocketRef * outSock );
-
-static const struct sockaddr * GetMDNSMulticastAddrV4( void );
-static const struct sockaddr * GetMDNSMulticastAddrV6( void );
-static OSStatus GetAnyMDNSInterface( char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex );
-
-static OSStatus
- CreateMulticastSocket(
- const struct sockaddr * inAddr,
- int inPort,
- const char * inIfName,
- uint32_t inIfIndex,
- Boolean inJoin,
- int * outPort,
- SocketRef * outSock );
-
-static OSStatus DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr );
-static OSStatus CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax );
-static OSStatus CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax );
-static OSStatus CheckRootUser( void );
-static OSStatus SpawnCommand( pid_t *outPID, const char *inFormat, ... );
-static OSStatus
- OutputPropertyList(
- CFPropertyListRef inPList,
- OutputFormatType inType,
- Boolean inAppendNewline,
- const char * inOutputFilePath );
-static void
- DNSRecordFixedFieldsSet(
- DNSRecordFixedFields * inFields,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- uint16_t inRDLength );
-static void
- SRVRecordDataFixedFieldsGet(
- const SRVRecordDataFixedFields * inFields,
- unsigned int * outPriority,
- unsigned int * outWeight,
- unsigned int * outPort );
-static void
- SRVRecordDataFixedFieldsSet(
- SRVRecordDataFixedFields * inFields,
- uint16_t inPriority,
- uint16_t inWeight,
- uint16_t inPort );
-static void
- SOARecordDataFixedFieldsGet(
- const SOARecordDataFixedFields * inFields,
- uint32_t * outSerial,
- uint32_t * outRefresh,
- uint32_t * outRetry,
- uint32_t * outExpire,
- uint32_t * outMinimum );
-static void
- SOARecordDataFixedFieldsSet(
- SOARecordDataFixedFields * inFields,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimum );
-static OSStatus CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen );
-static OSStatus CreateTXTRecordDataFromString( const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen );
-static OSStatus
- CreateNSECRecordData(
- const uint8_t * inNextDomainName,
- uint8_t ** outPtr,
- size_t * outLen,
- unsigned int inTypeCount,
- ... );
-static OSStatus
- AppendSOARecord(
- DataBuffer * inDB,
- const uint8_t * inNamePtr,
- size_t inNameLen,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- const uint8_t * inMName,
- const uint8_t * inRName,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimumTTL,
- size_t * outLen );
-static OSStatus
- CreateSOARecordData(
- const uint8_t * inMName,
- const uint8_t * inRName,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimumTTL,
- uint8_t ** outPtr,
- size_t * outLen );
-static OSStatus
- _DataBuffer_AppendDNSQuestion(
- DataBuffer * inDB,
- const uint8_t * inNamePtr,
- size_t inNameLen,
- uint16_t inType,
- uint16_t inClass );
-static OSStatus
- _DataBuffer_AppendDNSRecord(
- DataBuffer * inDB,
- const uint8_t * inNamePtr,
- size_t inNameLen,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- const uint8_t * inRDataPtr,
- size_t inRDataLen );
-static char * _NanoTime64ToDateString( NanoTime64 inTime, char *inBuf, size_t inMaxLen );
-
-#define Unused( X ) (void)(X)
-
-//===========================================================================================================================
-// MDNSCollider
-//===========================================================================================================================
-
-typedef struct MDNSColliderPrivate * MDNSColliderRef;
-
-typedef uint32_t MDNSColliderProtocols;
-#define kMDNSColliderProtocol_None 0
-#define kMDNSColliderProtocol_IPv4 ( 1 << 0 )
-#define kMDNSColliderProtocol_IPv6 ( 1 << 1 )
-
-typedef void ( *MDNSColliderStopHandler_f )( void *inContext, OSStatus inError );
-
-static OSStatus MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider );
-static OSStatus MDNSColliderStart( MDNSColliderRef inCollider );
-static void MDNSColliderStop( MDNSColliderRef inCollider );
-static void MDNSColliderSetProtocols( MDNSColliderRef inCollider, MDNSColliderProtocols inProtocols );
-static void MDNSColliderSetInterfaceIndex( MDNSColliderRef inCollider, uint32_t inInterfaceIndex );
-static OSStatus MDNSColliderSetProgram( MDNSColliderRef inCollider, const char *inProgramStr );
-static void
- MDNSColliderSetStopHandler(
- MDNSColliderRef inCollider,
- MDNSColliderStopHandler_f inStopHandler,
- void * inStopContext );
-static OSStatus
- MDNSColliderSetRecord(
- MDNSColliderRef inCollider,
- const uint8_t * inName,
- uint16_t inType,
- const void * inRDataPtr,
- size_t inRDataLen );
-static CFTypeID MDNSColliderGetTypeID( void );
-
-//===========================================================================================================================
-// ServiceBrowser
-//===========================================================================================================================
-
-typedef struct ServiceBrowserPrivate * ServiceBrowserRef;
-typedef struct ServiceBrowserResults ServiceBrowserResults;
-typedef struct SBRDomain SBRDomain;
-typedef struct SBRServiceType SBRServiceType;
-typedef struct SBRServiceInstance SBRServiceInstance;
-typedef struct SBRIPAddress SBRIPAddress;
-
-typedef void ( *ServiceBrowserCallback_f )( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
-
-struct ServiceBrowserResults
-{
- SBRDomain * domainList; // List of domains in which services were found.
-};
-
-struct SBRDomain
-{
- SBRDomain * next; // Next domain in list.
- char * name; // Name of domain represented by this object.
- SBRServiceType * typeList; // List of service types in this domain.
-};
-
-struct SBRServiceType
-{
- SBRServiceType * next; // Next service type in list.
- char * name; // Name of service type represented by this object.
- SBRServiceInstance * instanceList; // List of service instances of this service type.
-};
-
-struct SBRServiceInstance
-{
- SBRServiceInstance * next; // Next service instance in list.
- char * name; // Name of service instance represented by this object.
- char * hostname; // Target from service instance's SRV record.
- uint32_t ifIndex; // Index of interface over which this service instance was discovered.
- uint16_t port; // Port from service instance's SRV record.
- uint8_t * txtPtr; // Service instance's TXT record data.
- size_t txtLen; // Service instance's TXT record data length.
- SBRIPAddress * ipaddrList; // List of IP addresses that the hostname resolved to.
- uint64_t discoverTimeUs; // Time it took to discover this service instance in microseconds.
- uint64_t resolveTimeUs; // Time it took to resolve this service instance in microseconds.
-};
-
-struct SBRIPAddress
-{
- SBRIPAddress * next; // Next IP address in list.
- sockaddr_ip sip; // IPv4 or IPv6 address.
- uint64_t resolveTimeUs; // Time it took to resolve this IP address in microseconds.
-};
-
-static CFTypeID ServiceBrowserGetTypeID( void );
-static OSStatus
- ServiceBrowserCreate(
- dispatch_queue_t inQueue,
- uint32_t inInterfaceIndex,
- const char * inDomain,
- unsigned int inBrowseTimeSecs,
- Boolean inIncludeAWDL,
- ServiceBrowserRef * outBrowser );
-static void ServiceBrowserStart( ServiceBrowserRef inBrowser );
-static OSStatus ServiceBrowserAddServiceType( ServiceBrowserRef inBrowser, const char *inServiceType );
-static void
- ServiceBrowserSetCallback(
- ServiceBrowserRef inBrowser,
- ServiceBrowserCallback_f inCallback,
- void * inContext );
-static void ServiceBrowserResultsRetain( ServiceBrowserResults *inResults );
-static void ServiceBrowserResultsRelease( ServiceBrowserResults *inResults );
-
-#define ForgetServiceBrowserResults( X ) ForgetCustom( X, ServiceBrowserResultsRelease )
-
-//===========================================================================================================================
-// main
-//===========================================================================================================================
-
-int main( int argc, const char **argv )
-{
- OSStatus err;
-
- // Route DebugServices logging output to stderr.
-
- dlog_control( "DebugServices:output=file;stderr" );
-
- PrintFRegisterExtension( "du:time", PrintFTimestampHandler, NULL );
- PrintFRegisterExtension( "du:dnsmsg", PrintFDNSMessageHandler, NULL );
- PrintFRegisterExtension( "du:arflags", PrintFAddRmvFlagsHandler, NULL );
- CLIInit( argc, argv );
- err = CLIParse( kGlobalOpts, kCLIFlags_None );
- if( err ) exit( 1 );
-
- return( gExitCode );
-}
-
-//===========================================================================================================================
-// VersionOptionCallback
-//===========================================================================================================================
-
-static OSStatus VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset )
-{
- const char * srcVers;
-#if( MDNSRESPONDER_PROJECT )
- char srcStr[ 16 ];
-#endif
-
- Unused( inOption );
- Unused( inArg );
- Unused( inUnset );
-
-#if( MDNSRESPONDER_PROJECT )
- srcVers = SourceVersionToCString( _DNS_SD_H, srcStr );
-#else
- srcVers = DNSSDUTIL_SOURCE_VERSION;
-#endif
- FPrintF( stdout, "%s version %v (%s)\n", gProgramName, kDNSSDUtilNumVersion, srcVers );
-
- return( kEndingErr );
-}
-
-//===========================================================================================================================
-// BrowseCmd
-//===========================================================================================================================
-
-typedef struct BrowseResolveOp BrowseResolveOp;
-
-struct BrowseResolveOp
-{
- BrowseResolveOp * next; // Next resolve operation in list.
- DNSServiceRef sdRef; // sdRef of the DNSServiceResolve or DNSServiceQueryRecord operation.
- char * fullName; // Full name of the service to resolve.
- uint32_t interfaceIndex; // Interface index of the DNSServiceResolve or DNSServiceQueryRecord operation.
-};
-
-typedef struct
-{
- DNSServiceRef mainRef; // Main sdRef for shared connection.
- DNSServiceRef * opRefs; // Array of sdRefs for individual Browse operarions.
- size_t opRefsCount; // Count of array of sdRefs for non-shared connections.
- const char * domain; // Domain for DNSServiceBrowse operation(s).
- DNSServiceFlags flags; // Flags for DNSServiceBrowse operation(s).
- char ** serviceTypes; // Array of service types to browse for.
- size_t serviceTypesCount; // Count of array of service types to browse for.
- int timeLimitSecs; // Time limit of DNSServiceBrowse operation in seconds.
- BrowseResolveOp * resolveList; // List of resolve and/or TXT record query operations.
- uint32_t ifIndex; // Interface index of DNSServiceBrowse operation(s).
- Boolean printedHeader; // True if results header has been printed.
- Boolean doResolve; // True if service instances are to be resolved.
- Boolean doResolveTXTOnly; // True if TXT records of service instances are to be queried.
-
-} BrowseContext;
-
-static void BrowsePrintPrologue( const BrowseContext *inContext );
-static void BrowseContextFree( BrowseContext *inContext );
-static OSStatus BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp );
-static void BrowseResolveOpFree( BrowseResolveOp *inOp );
-static void DNSSD_API
- BrowseCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inRegType,
- const char * inDomain,
- void * inContext );
-static void DNSSD_API
- BrowseResolveCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- const char * inHostname,
- uint16_t inPort,
- uint16_t inTXTLen,
- const unsigned char * inTXTPtr,
- void * inContext );
-static void DNSSD_API
- BrowseQueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-
-static void BrowseCmd( void )
-{
- OSStatus err;
- size_t i;
- BrowseContext * context = NULL;
- dispatch_source_t signalSource = NULL;
- int useMainConnection;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (BrowseContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->opRefs = (DNSServiceRef *) calloc( gBrowse_ServiceTypesCount, sizeof( DNSServiceRef ) );
- require_action( context->opRefs, exit, err = kNoMemoryErr );
- context->opRefsCount = gBrowse_ServiceTypesCount;
-
- // Check command parameters.
-
- if( gBrowse_TimeLimitSecs < 0 )
- {
- FPrintF( stderr, "Invalid time limit: %d seconds.\n", gBrowse_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create main connection.
-
- if( gConnectionOpt )
- {
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
- require_noerr_quiet( err, exit );
- useMainConnection = true;
- }
- else
- {
- useMainConnection = false;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
- if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-
- // Get interface.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Set remaining parameters.
-
- context->serviceTypes = gBrowse_ServiceTypes;
- context->serviceTypesCount = gBrowse_ServiceTypesCount;
- context->domain = gBrowse_Domain;
- context->doResolve = gBrowse_DoResolve ? true : false;
- context->timeLimitSecs = gBrowse_TimeLimitSecs;
- context->doResolveTXTOnly = gBrowse_QueryTXT ? true : false;
-
- // Print prologue.
-
- BrowsePrintPrologue( context );
-
- // Start operation(s).
-
- for( i = 0; i < context->serviceTypesCount; ++i )
- {
- DNSServiceRef sdRef;
-
- sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
- err = DNSServiceBrowse( &sdRef, context->flags, context->ifIndex, context->serviceTypes[ i ], context->domain,
- BrowseCallback, context );
- require_noerr( err, exit );
-
- context->opRefs[ i ] = sdRef;
- if( !useMainConnection )
- {
- err = DNSServiceSetDispatchQueue( context->opRefs[ i ], dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
- }
-
- // Set time limit.
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
- kExitReason_TimeLimit, Exit );
- }
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) BrowseContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// BrowsePrintPrologue
-//===========================================================================================================================
-
-static void BrowsePrintPrologue( const BrowseContext *inContext )
-{
- const int timeLimitSecs = inContext->timeLimitSecs;
- const char * const * ptr = (const char **) inContext->serviceTypes;
- const char * const * const end = (const char **) inContext->serviceTypes + inContext->serviceTypesCount;
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Service types: %s", *ptr++ );
- while( ptr < end ) FPrintF( stdout, ", %s", *ptr++ );
- FPrintF( stdout, "\n" );
- FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
- FPrintF( stdout, "Time limit: " );
- if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-// BrowseContextFree
-//===========================================================================================================================
-
-static void BrowseContextFree( BrowseContext *inContext )
-{
- size_t i;
-
- for( i = 0; i < inContext->opRefsCount; ++i )
- {
- DNSServiceForget( &inContext->opRefs[ i ] );
- }
- if( inContext->serviceTypes )
- {
- StringArray_Free( inContext->serviceTypes, inContext->serviceTypesCount );
- inContext->serviceTypes = NULL;
- inContext->serviceTypesCount = 0;
- }
- DNSServiceForget( &inContext->mainRef );
- free( inContext );
-}
-
-//===========================================================================================================================
-// BrowseResolveOpCreate
-//===========================================================================================================================
-
-static OSStatus BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp )
-{
- OSStatus err;
- BrowseResolveOp * resolveOp;
-
- resolveOp = (BrowseResolveOp *) calloc( 1, sizeof( *resolveOp ) );
- require_action( resolveOp, exit, err = kNoMemoryErr );
-
- resolveOp->fullName = strdup( inFullName );
- require_action( resolveOp->fullName, exit, err = kNoMemoryErr );
-
- resolveOp->interfaceIndex = inInterfaceIndex;
-
- *outOp = resolveOp;
- resolveOp = NULL;
- err = kNoErr;
-
-exit:
- if( resolveOp ) BrowseResolveOpFree( resolveOp );
- return( err );
-}
-
-//===========================================================================================================================
-// BrowseResolveOpFree
-//===========================================================================================================================
-
-static void BrowseResolveOpFree( BrowseResolveOp *inOp )
-{
- DNSServiceForget( &inOp->sdRef );
- ForgetMem( &inOp->fullName );
- free( inOp );
-}
-
-//===========================================================================================================================
-// BrowseCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- BrowseCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inRegType,
- const char * inDomain,
- void * inContext )
-{
- BrowseContext * const context = (BrowseContext *) inContext;
- OSStatus err;
- BrowseResolveOp * newOp = NULL;
- BrowseResolveOp ** p;
- char fullName[ kDNSServiceMaxDomainName ];
- struct timeval now;
-
- Unused( inSDRef );
-
- gettimeofday( &now, NULL );
-
- err = inError;
- require_noerr( err, exit );
-
- if( !context->printedHeader )
- {
- FPrintF( stdout, "%-26s %-14s IF %-20s %-20s Instance Name\n", "Timestamp", "Flags", "Domain", "Service Type" );
- context->printedHeader = true;
- }
- FPrintF( stdout, "%{du:time} %{du:arflags} %2d %-20s %-20s %s\n",
- &now, inFlags, (int32_t) inInterfaceIndex, inDomain, inRegType, inName );
-
- if( !context->doResolve && !context->doResolveTXTOnly ) goto exit;
-
- err = DNSServiceConstructFullName( fullName, inName, inRegType, inDomain );
- require_noerr( err, exit );
-
- if( inFlags & kDNSServiceFlagsAdd )
- {
- DNSServiceRef sdRef;
- DNSServiceFlags flags;
-
- err = BrowseResolveOpCreate( fullName, inInterfaceIndex, &newOp );
- require_noerr( err, exit );
-
- if( context->mainRef )
- {
- sdRef = context->mainRef;
- flags = kDNSServiceFlagsShareConnection;
- }
- else
- {
- flags = 0;
- }
- if( context->doResolve )
- {
- err = DNSServiceResolve( &sdRef, flags, inInterfaceIndex, inName, inRegType, inDomain, BrowseResolveCallback,
- NULL );
- require_noerr( err, exit );
- }
- else
- {
- err = DNSServiceQueryRecord( &sdRef, flags, inInterfaceIndex, fullName, kDNSServiceType_TXT, kDNSServiceClass_IN,
- BrowseQueryRecordCallback, NULL );
- require_noerr( err, exit );
- }
-
- newOp->sdRef = sdRef;
- if( !context->mainRef )
- {
- err = DNSServiceSetDispatchQueue( newOp->sdRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
- for( p = &context->resolveList; *p; p = &( *p )->next ) {}
- *p = newOp;
- newOp = NULL;
- }
- else
- {
- BrowseResolveOp * resolveOp;
-
- for( p = &context->resolveList; ( resolveOp = *p ) != NULL; p = &resolveOp->next )
- {
- if( ( resolveOp->interfaceIndex == inInterfaceIndex ) && ( strcasecmp( resolveOp->fullName, fullName ) == 0 ) )
- {
- break;
- }
- }
- if( resolveOp )
- {
- *p = resolveOp->next;
- BrowseResolveOpFree( resolveOp );
- }
- }
-
-exit:
- if( newOp ) BrowseResolveOpFree( newOp );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// BrowseQueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- BrowseQueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- struct timeval now;
-
- Unused( inSDRef );
- Unused( inClass );
- Unused( inTTL );
- Unused( inContext );
-
- gettimeofday( &now, NULL );
-
- err = inError;
- require_noerr( err, exit );
- require_action( inType == kDNSServiceType_TXT, exit, err = kTypeErr );
-
- FPrintF( stdout, "%{du:time} %s %s TXT on interface %d\n TXT: %#{txt}\n",
- &now, ( inFlags & kDNSServiceFlagsAdd ) ? "Add" : "Rmv", inFullName, (int32_t) inInterfaceIndex,
- inRDataPtr, (size_t) inRDataLen );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// BrowseResolveCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- BrowseResolveCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- const char * inHostname,
- uint16_t inPort,
- uint16_t inTXTLen,
- const unsigned char * inTXTPtr,
- void * inContext )
-{
- struct timeval now;
- char errorStr[ 64 ];
-
- Unused( inSDRef );
- Unused( inFlags );
- Unused( inContext );
-
- gettimeofday( &now, NULL );
-
- if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
-
- FPrintF( stdout, "%{du:time} %s can be reached at %s:%u (interface %d)%?s\n",
- &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
- if( inTXTLen == 1 )
- {
- FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
- }
- else
- {
- FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
- }
-}
-
-//===========================================================================================================================
-// GetAddrInfoCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServiceRef mainRef; // Main sdRef for shared connection.
- DNSServiceRef opRef; // sdRef for the DNSServiceGetAddrInfo operation.
- const char * name; // Hostname to resolve.
- DNSServiceFlags flags; // Flags argument for DNSServiceGetAddrInfo().
- DNSServiceProtocol protocols; // Protocols argument for DNSServiceGetAddrInfo().
- uint32_t ifIndex; // Interface index argument for DNSServiceGetAddrInfo().
- int timeLimitSecs; // Time limit for the DNSServiceGetAddrInfo() operation in seconds.
- Boolean printedHeader; // True if the results header has been printed.
- Boolean oneShotMode; // True if command is done after the first set of results (one-shot mode).
- Boolean needIPv4; // True if in one-shot mode and an IPv4 result is needed.
- Boolean needIPv6; // True if in one-shot mode and an IPv6 result is needed.
-
-} GetAddrInfoContext;
-
-static void GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext );
-static void GetAddrInfoContextFree( GetAddrInfoContext *inContext );
-static void DNSSD_API
- GetAddrInfoCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext );
-
-static void GetAddrInfoCmd( void )
-{
- OSStatus err;
- DNSServiceRef sdRef;
- GetAddrInfoContext * context = NULL;
- dispatch_source_t signalSource = NULL;
- int useMainConnection;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Check command parameters.
-
- if( gGetAddrInfo_TimeLimitSecs < 0 )
- {
- FPrintF( stderr, "Invalid time limit: %d s.\n", gGetAddrInfo_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create context.
-
- context = (GetAddrInfoContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Create main connection.
-
- if( gConnectionOpt )
- {
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
- require_noerr_quiet( err, exit );
- useMainConnection = true;
- }
- else
- {
- useMainConnection = false;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
- if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-
- // Get interface.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Set remaining parameters.
-
- context->name = gGetAddrInfo_Name;
- context->timeLimitSecs = gGetAddrInfo_TimeLimitSecs;
- if( gGetAddrInfo_ProtocolIPv4 ) context->protocols |= kDNSServiceProtocol_IPv4;
- if( gGetAddrInfo_ProtocolIPv6 ) context->protocols |= kDNSServiceProtocol_IPv6;
- if( gGetAddrInfo_OneShot )
- {
- context->oneShotMode = true;
- context->needIPv4 = ( gGetAddrInfo_ProtocolIPv4 || !gGetAddrInfo_ProtocolIPv6 ) ? true : false;
- context->needIPv6 = ( gGetAddrInfo_ProtocolIPv6 || !gGetAddrInfo_ProtocolIPv4 ) ? true : false;
- }
-
- // Print prologue.
-
- GetAddrInfoPrintPrologue( context );
-
- // Start operation.
-
- sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
- err = DNSServiceGetAddrInfo( &sdRef, context->flags, context->ifIndex, context->protocols, context->name,
- GetAddrInfoCallback, context );
- require_noerr( err, exit );
-
- context->opRef = sdRef;
- if( !useMainConnection )
- {
- err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
-
- // Set time limit.
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
- kExitReason_TimeLimit, Exit );
- }
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) GetAddrInfoContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// GetAddrInfoPrintPrologue
-//===========================================================================================================================
-
-static void GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext )
-{
- const int timeLimitSecs = inContext->timeLimitSecs;
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Protocols: %#{flags}\n", inContext->protocols, kDNSServiceProtocolDescriptors );
- FPrintF( stdout, "Name: %s\n", inContext->name );
- FPrintF( stdout, "Mode: %s\n", inContext->oneShotMode ? "one-shot" : "continuous" );
- FPrintF( stdout, "Time limit: " );
- if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-// GetAddrInfoContextFree
-//===========================================================================================================================
-
-static void GetAddrInfoContextFree( GetAddrInfoContext *inContext )
-{
- DNSServiceForget( &inContext->opRef );
- DNSServiceForget( &inContext->mainRef );
- free( inContext );
-}
-
-//===========================================================================================================================
-// GetAddrInfoCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- GetAddrInfoCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext )
-{
- GetAddrInfoContext * const context = (GetAddrInfoContext *) inContext;
- struct timeval now;
- OSStatus err;
- const char * addrStr;
- char addrStrBuf[ kSockAddrStringMaxSize ];
-
- Unused( inSDRef );
-
- gettimeofday( &now, NULL );
-
- switch( inError )
- {
- case kDNSServiceErr_NoError:
- case kDNSServiceErr_NoSuchRecord:
- err = kNoErr;
- break;
-
- case kDNSServiceErr_Timeout:
- Exit( kExitReason_Timeout );
-
- default:
- err = inError;
- goto exit;
- }
-
- if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
- {
- dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
- err = kTypeErr;
- goto exit;
- }
-
- if( !inError )
- {
- err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
- require_noerr( err, exit );
- addrStr = addrStrBuf;
- }
- else
- {
- addrStr = ( inSockAddr->sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr;
- }
-
- if( !context->printedHeader )
- {
- FPrintF( stdout, "%-26s %-14s IF %-32s %-38s %6s\n", "Timestamp", "Flags", "Hostname", "Address", "TTL" );
- context->printedHeader = true;
- }
- FPrintF( stdout, "%{du:time} %{du:arflags} %2d %-32s %-38s %6u\n",
- &now, inFlags, (int32_t) inInterfaceIndex, inHostname, addrStr, inTTL );
-
- if( context->oneShotMode )
- {
- if( inFlags & kDNSServiceFlagsAdd )
- {
- if( inSockAddr->sa_family == AF_INET ) context->needIPv4 = false;
- else context->needIPv6 = false;
- }
- if( !( inFlags & kDNSServiceFlagsMoreComing ) && !context->needIPv4 && !context->needIPv6 )
- {
- Exit( kExitReason_OneShotDone );
- }
- }
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// QueryRecordCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServiceRef mainRef; // Main sdRef for shared connection.
- DNSServiceRef opRef; // sdRef for the DNSServiceQueryRecord operation.
- const char * recordName; // Resource record name argument for DNSServiceQueryRecord().
- DNSServiceFlags flags; // Flags argument for DNSServiceQueryRecord().
- uint32_t ifIndex; // Interface index argument for DNSServiceQueryRecord().
- int timeLimitSecs; // Time limit for the DNSServiceQueryRecord() operation in seconds.
- uint16_t recordType; // Resource record type argument for DNSServiceQueryRecord().
- Boolean printedHeader; // True if the results header was printed.
- Boolean oneShotMode; // True if command is done after the first set of results (one-shot mode).
- Boolean gotRecord; // True if in one-shot mode and received at least one record of the desired type.
- Boolean printRawRData; // True if RDATA results are not to be formatted when printed.
-
-} QueryRecordContext;
-
-static void QueryRecordPrintPrologue( const QueryRecordContext *inContext );
-static void QueryRecordContextFree( QueryRecordContext *inContext );
-static void DNSSD_API
- QueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-
-static void QueryRecordCmd( void )
-{
- OSStatus err;
- DNSServiceRef sdRef;
- QueryRecordContext * context = NULL;
- dispatch_source_t signalSource = NULL;
- int useMainConnection;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Check command parameters.
-
- if( gQueryRecord_TimeLimitSecs < 0 )
- {
- FPrintF( stderr, "Invalid time limit: %d seconds.\n", gQueryRecord_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create main connection.
-
- if( gConnectionOpt )
- {
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
- require_noerr_quiet( err, exit );
- useMainConnection = true;
- }
- else
- {
- useMainConnection = false;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
- if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-
- // Get interface.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Get record type.
-
- err = RecordTypeFromArgString( gQueryRecord_Type, &context->recordType );
- require_noerr( err, exit );
-
- // Set remaining parameters.
-
- context->recordName = gQueryRecord_Name;
- context->timeLimitSecs = gQueryRecord_TimeLimitSecs;
- context->oneShotMode = gQueryRecord_OneShot ? true : false;
- context->printRawRData = gQueryRecord_RawRData ? true : false;
-
- // Print prologue.
-
- QueryRecordPrintPrologue( context );
-
- // Start operation.
-
- sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
- err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
- kDNSServiceClass_IN, QueryRecordCallback, context );
- require_noerr( err, exit );
-
- context->opRef = sdRef;
- if( !useMainConnection )
- {
- err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
-
- // Set time limit.
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_TimeLimit,
- Exit );
- }
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) QueryRecordContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// QueryRecordContextFree
-//===========================================================================================================================
-
-static void QueryRecordContextFree( QueryRecordContext *inContext )
-{
- DNSServiceForget( &inContext->opRef );
- DNSServiceForget( &inContext->mainRef );
- free( inContext );
-}
-
-//===========================================================================================================================
-// QueryRecordPrintPrologue
-//===========================================================================================================================
-
-static void QueryRecordPrintPrologue( const QueryRecordContext *inContext )
-{
- const int timeLimitSecs = inContext->timeLimitSecs;
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Name: %s\n", inContext->recordName );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->recordType ), inContext->recordType );
- FPrintF( stdout, "Mode: %s\n", inContext->oneShotMode ? "one-shot" : "continuous" );
- FPrintF( stdout, "Time limit: " );
- if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
-}
-
-//===========================================================================================================================
-// QueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- QueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- QueryRecordContext * const context = (QueryRecordContext *) inContext;
- struct timeval now;
- OSStatus err;
- char * rdataStr = NULL;
-
- Unused( inSDRef );
-
- gettimeofday( &now, NULL );
-
- switch( inError )
- {
- case kDNSServiceErr_NoError:
- case kDNSServiceErr_NoSuchRecord:
- err = kNoErr;
- break;
-
- case kDNSServiceErr_Timeout:
- Exit( kExitReason_Timeout );
-
- default:
- err = inError;
- goto exit;
- }
-
- if( inError != kDNSServiceErr_NoSuchRecord )
- {
- if( !context->printRawRData ) DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
- if( !rdataStr )
- {
- ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, INT_MAX );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- }
-
- if( !context->printedHeader )
- {
- FPrintF( stdout, "%-26s %-14s IF %-32s %-5s %-5s %6s RData\n",
- "Timestamp", "Flags", "Name", "Type", "Class", "TTL" );
- context->printedHeader = true;
- }
- FPrintF( stdout, "%{du:time} %{du:arflags} %2d %-32s %-5s %?-5s%?5u %6u %s\n",
- &now, inFlags, (int32_t) inInterfaceIndex, inFullName, RecordTypeToString( inType ),
- ( inClass == kDNSServiceClass_IN ), "IN", ( inClass != kDNSServiceClass_IN ), inClass, inTTL,
- rdataStr ? rdataStr : kNoSuchRecordStr );
-
- if( context->oneShotMode )
- {
- if( ( inFlags & kDNSServiceFlagsAdd ) &&
- ( ( context->recordType == kDNSServiceType_ANY ) || ( context->recordType == inType ) ) )
- {
- context->gotRecord = true;
- }
- if( !( inFlags & kDNSServiceFlagsMoreComing ) && context->gotRecord ) Exit( kExitReason_OneShotDone );
- }
-
-exit:
- FreeNullSafe( rdataStr );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// RegisterCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSRecordRef recordRef; // Reference returned by DNSServiceAddRecord().
- uint8_t * dataPtr; // Record data.
- size_t dataLen; // Record data length.
- uint32_t ttl; // Record TTL value.
- uint16_t type; // Record type.
-
-} ExtraRecord;
-
-typedef struct
-{
- DNSServiceRef opRef; // sdRef for DNSServiceRegister operation.
- const char * name; // Service name argument for DNSServiceRegister().
- const char * type; // Service type argument for DNSServiceRegister().
- const char * domain; // Domain in which advertise the service.
- uint8_t * txtPtr; // Service TXT record data. (malloc'd)
- size_t txtLen; // Service TXT record data len.
- ExtraRecord * extraRecords; // Array of extra records to add to registered service.
- size_t extraRecordsCount; // Number of extra records.
- uint8_t * updateTXTPtr; // Pointer to record data for TXT record update. (malloc'd)
- size_t updateTXTLen; // Length of record data for TXT record update.
- uint32_t updateTTL; // TTL of updated TXT record.
- int updateDelayMs; // Post-registration TXT record update delay in milliseconds.
- DNSServiceFlags flags; // Flags argument for DNSServiceRegister().
- uint32_t ifIndex; // Interface index argument for DNSServiceRegister().
- int lifetimeMs; // Lifetime of the record registration in milliseconds.
- uint16_t port; // Service instance's port number.
- Boolean printedHeader; // True if results header was printed.
- Boolean didRegister; // True if service was registered.
-
-} RegisterContext;
-
-static void RegisterPrintPrologue( const RegisterContext *inContext );
-static void RegisterContextFree( RegisterContext *inContext );
-static void DNSSD_API
- RegisterCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inType,
- const char * inDomain,
- void * inContext );
-static void RegisterUpdate( void *inContext );
-
-static void RegisterCmd( void )
-{
- OSStatus err;
- RegisterContext * context = NULL;
- dispatch_source_t signalSource = NULL;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (RegisterContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Check command parameters.
-
- if( ( gRegister_Port < 0 ) || ( gRegister_Port > UINT16_MAX ) )
- {
- FPrintF( stderr, "Port number %d is out-of-range.\n", gRegister_Port );
- err = kParamErr;
- goto exit;
- }
-
- if( ( gAddRecord_DataCount != gAddRecord_TypesCount ) || ( gAddRecord_TTLsCount != gAddRecord_TypesCount ) )
- {
- FPrintF( stderr, "There are missing additional record parameters.\n" );
- err = kParamErr;
- goto exit;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
-
- // Get interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Get TXT record data.
-
- if( gRegister_TXT )
- {
- err = RecordDataFromArgString( gRegister_TXT, &context->txtPtr, &context->txtLen );
- require_noerr_quiet( err, exit );
- }
-
- // Set remaining parameters.
-
- context->name = gRegister_Name;
- context->type = gRegister_Type;
- context->domain = gRegister_Domain;
- context->port = (uint16_t) gRegister_Port;
- context->lifetimeMs = gRegister_LifetimeMs;
-
- if( gAddRecord_TypesCount > 0 )
- {
- size_t i;
-
- context->extraRecords = (ExtraRecord *) calloc( gAddRecord_TypesCount, sizeof( ExtraRecord ) );
- require_action( context, exit, err = kNoMemoryErr );
- context->extraRecordsCount = gAddRecord_TypesCount;
-
- for( i = 0; i < gAddRecord_TypesCount; ++i )
- {
- ExtraRecord * const extraRecord = &context->extraRecords[ i ];
-
- err = RecordTypeFromArgString( gAddRecord_Types[ i ], &extraRecord->type );
- require_noerr( err, exit );
-
- err = StringToUInt32( gAddRecord_TTLs[ i ], &extraRecord->ttl );
- if( err )
- {
- FPrintF( stderr, "Invalid TTL value: %s\n", gAddRecord_TTLs[ i ] );
- err = kParamErr;
- goto exit;
- }
-
- err = RecordDataFromArgString( gAddRecord_Data[ i ], &extraRecord->dataPtr, &extraRecord->dataLen );
- require_noerr_quiet( err, exit );
- }
- }
-
- if( gUpdateRecord_Data )
- {
- err = RecordDataFromArgString( gUpdateRecord_Data, &context->updateTXTPtr, &context->updateTXTLen );
- require_noerr_quiet( err, exit );
-
- context->updateTTL = (uint32_t) gUpdateRecord_TTL;
- context->updateDelayMs = gUpdateRecord_DelayMs;
- }
-
- // Print prologue.
-
- RegisterPrintPrologue( context );
-
- // Start operation.
-
- err = DNSServiceRegister( &context->opRef, context->flags, context->ifIndex, context->name, context->type,
- context->domain, NULL, htons( context->port ), (uint16_t) context->txtLen, context->txtPtr,
- RegisterCallback, context );
- ForgetMem( &context->txtPtr );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
-
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) RegisterContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// RegisterPrintPrologue
-//===========================================================================================================================
-
-static void RegisterPrintPrologue( const RegisterContext *inContext )
-{
- size_t i;
- int infinite;
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Name: %s\n", inContext->name ? inContext->name : "<NULL>" );
- FPrintF( stdout, "Type: %s\n", inContext->type );
- FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
- FPrintF( stdout, "Port: %u\n", inContext->port );
- FPrintF( stdout, "TXT data: %#{txt}\n", inContext->txtPtr, inContext->txtLen );
- infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
- FPrintF( stdout, "Lifetime: %?s%?d ms\n", infinite, "∞", !infinite, inContext->lifetimeMs );
- if( inContext->updateTXTPtr )
- {
- FPrintF( stdout, "\nUpdate record:\n" );
- FPrintF( stdout, " Delay: %d ms\n", ( inContext->updateDelayMs > 0 ) ? inContext->updateDelayMs : 0 );
- FPrintF( stdout, " TTL: %u%?s\n",
- inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
- FPrintF( stdout, " TXT data: %#{txt}\n", inContext->updateTXTPtr, inContext->updateTXTLen );
- }
- if( inContext->extraRecordsCount > 0 ) FPrintF( stdout, "\n" );
- for( i = 0; i < inContext->extraRecordsCount; ++i )
- {
- const ExtraRecord * record = &inContext->extraRecords[ i ];
-
- FPrintF( stdout, "Extra record %zu:\n", i + 1 );
- FPrintF( stdout, " Type: %s (%u)\n", RecordTypeToString( record->type ), record->type );
- FPrintF( stdout, " TTL: %u%?s\n", record->ttl, record->ttl == 0, " (system will use a default value.)" );
- FPrintF( stdout, " RData: %#H\n\n", record->dataPtr, (int) record->dataLen, INT_MAX );
- }
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-// RegisterContextFree
-//===========================================================================================================================
-
-static void RegisterContextFree( RegisterContext *inContext )
-{
- ExtraRecord * record;
- const ExtraRecord * const end = inContext->extraRecords + inContext->extraRecordsCount;
-
- DNSServiceForget( &inContext->opRef );
- ForgetMem( &inContext->txtPtr );
- for( record = inContext->extraRecords; record < end; ++record )
- {
- check( !record->recordRef );
- ForgetMem( &record->dataPtr );
- }
- ForgetMem( &inContext->extraRecords );
- ForgetMem( &inContext->updateTXTPtr );
- free( inContext );
-}
-
-//===========================================================================================================================
-// RegisterCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- RegisterCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inType,
- const char * inDomain,
- void * inContext )
-{
- RegisterContext * const context = (RegisterContext *) inContext;
- OSStatus err;
- struct timeval now;
-
- Unused( inSDRef );
-
- gettimeofday( &now, NULL );
-
- if( !context->printedHeader )
- {
- FPrintF( stdout, "%-26s %-14s Service\n", "Timestamp", "Flags" );
- context->printedHeader = true;
- }
- FPrintF( stdout, "%{du:time} %{du:arflags} %s.%s%s %?#m\n", &now, inFlags, inName, inType, inDomain, inError, inError );
-
- require_noerr_action_quiet( inError, exit, err = inError );
-
- if( !context->didRegister && ( inFlags & kDNSServiceFlagsAdd ) )
- {
- context->didRegister = true;
- if( context->updateTXTPtr )
- {
- if( context->updateDelayMs > 0 )
- {
- dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
- context, RegisterUpdate );
- }
- else
- {
- RegisterUpdate( context );
- }
- }
- if( context->extraRecordsCount > 0 )
- {
- ExtraRecord * record;
- const ExtraRecord * const end = context->extraRecords + context->extraRecordsCount;
-
- for( record = context->extraRecords; record < end; ++record )
- {
- err = DNSServiceAddRecord( context->opRef, &record->recordRef, 0, record->type,
- (uint16_t) record->dataLen, record->dataPtr, record->ttl );
- require_noerr( err, exit );
- }
- }
- if( context->lifetimeMs == 0 )
- {
- Exit( kExitReason_TimeLimit );
- }
- else if( context->lifetimeMs > 0 )
- {
- dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
- kExitReason_TimeLimit, Exit );
- }
- }
- err = kNoErr;
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// RegisterUpdate
-//===========================================================================================================================
-
-static void RegisterUpdate( void *inContext )
-{
- OSStatus err;
- RegisterContext * const context = (RegisterContext *) inContext;
-
- err = DNSServiceUpdateRecord( context->opRef, NULL, 0, (uint16_t) context->updateTXTLen, context->updateTXTPtr,
- context->updateTTL );
- require_noerr( err, exit );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// RegisterRecordCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServiceRef conRef; // sdRef to be initialized by DNSServiceCreateConnection().
- DNSRecordRef recordRef; // Registered record reference.
- const char * recordName; // Name of resource record.
- uint8_t * dataPtr; // Pointer to resource record data.
- size_t dataLen; // Length of resource record data.
- uint32_t ttl; // TTL value of resource record in seconds.
- uint32_t ifIndex; // Interface index argument for DNSServiceRegisterRecord().
- DNSServiceFlags flags; // Flags argument for DNSServiceRegisterRecord().
- int lifetimeMs; // Lifetime of the record registration in milliseconds.
- uint16_t recordType; // Resource record type.
- uint8_t * updateDataPtr; // Pointer to data for record update. (malloc'd)
- size_t updateDataLen; // Length of data for record update.
- uint32_t updateTTL; // TTL for updated record.
- int updateDelayMs; // Post-registration record update delay in milliseconds.
- Boolean didRegister; // True if the record was registered.
-
-} RegisterRecordContext;
-
-static void RegisterRecordPrintPrologue( const RegisterRecordContext *inContext );
-static void RegisterRecordContextFree( RegisterRecordContext *inContext );
-static void DNSSD_API
- RegisterRecordCallback(
- DNSServiceRef inSDRef,
- DNSRecordRef inRecordRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- void * inContext );
-static void RegisterRecordUpdate( void *inContext );
-
-static void RegisterRecordCmd( void )
-{
- OSStatus err;
- RegisterRecordContext * context = NULL;
- dispatch_source_t signalSource = NULL;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (RegisterRecordContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Create connection.
-
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->conRef, NULL );
- require_noerr_quiet( err, exit );
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
-
- // Get interface.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Get record type.
-
- err = RecordTypeFromArgString( gRegisterRecord_Type, &context->recordType );
- require_noerr( err, exit );
-
- // Get record data.
-
- if( gRegisterRecord_Data )
- {
- err = RecordDataFromArgString( gRegisterRecord_Data, &context->dataPtr, &context->dataLen );
- require_noerr_quiet( err, exit );
- }
-
- // Set remaining parameters.
-
- context->recordName = gRegisterRecord_Name;
- context->ttl = (uint32_t) gRegisterRecord_TTL;
- context->lifetimeMs = gRegisterRecord_LifetimeMs;
-
- // Get update data.
-
- if( gRegisterRecord_UpdateData )
- {
- err = RecordDataFromArgString( gRegisterRecord_UpdateData, &context->updateDataPtr, &context->updateDataLen );
- require_noerr_quiet( err, exit );
-
- context->updateTTL = (uint32_t) gRegisterRecord_UpdateTTL;
- context->updateDelayMs = gRegisterRecord_UpdateDelayMs;
- }
-
- // Print prologue.
-
- RegisterRecordPrintPrologue( context );
-
- // Start operation.
-
- err = DNSServiceRegisterRecord( context->conRef, &context->recordRef, context->flags, context->ifIndex,
- context->recordName, context->recordType, kDNSServiceClass_IN, (uint16_t) context->dataLen, context->dataPtr,
- context->ttl, RegisterRecordCallback, context );
- if( err )
- {
- FPrintF( stderr, "DNSServiceRegisterRecord() returned %#m\n", err );
- goto exit;
- }
-
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) RegisterRecordContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// RegisterRecordPrintPrologue
-//===========================================================================================================================
-
-static void RegisterRecordPrintPrologue( const RegisterRecordContext *inContext )
-{
- int infinite;
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Name: %s\n", inContext->recordName );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->recordType ), inContext->recordType );
- FPrintF( stdout, "TTL: %u\n", inContext->ttl );
- FPrintF( stdout, "Data: %#H\n", inContext->dataPtr, (int) inContext->dataLen, INT_MAX );
- infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
- FPrintF( stdout, "Lifetime: %?s%?d ms\n", infinite, "∞", !infinite, inContext->lifetimeMs );
- if( inContext->updateDataPtr )
- {
- FPrintF( stdout, "\nUpdate record:\n" );
- FPrintF( stdout, " Delay: %d ms\n", ( inContext->updateDelayMs >= 0 ) ? inContext->updateDelayMs : 0 );
- FPrintF( stdout, " TTL: %u%?s\n",
- inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
- FPrintF( stdout, " RData: %#H\n", inContext->updateDataPtr, (int) inContext->updateDataLen, INT_MAX );
- }
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-// RegisterRecordContextFree
-//===========================================================================================================================
-
-static void RegisterRecordContextFree( RegisterRecordContext *inContext )
-{
- DNSServiceForget( &inContext->conRef );
- ForgetMem( &inContext->dataPtr );
- ForgetMem( &inContext->updateDataPtr );
- free( inContext );
-}
-
-//===========================================================================================================================
-// RegisterRecordCallback
-//===========================================================================================================================
-
-static void
- RegisterRecordCallback(
- DNSServiceRef inSDRef,
- DNSRecordRef inRecordRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- void * inContext )
-{
- RegisterRecordContext * context = (RegisterRecordContext *) inContext;
- struct timeval now;
-
- Unused( inSDRef );
- Unused( inRecordRef );
- Unused( inFlags );
- Unused( context );
-
- gettimeofday( &now, NULL );
- FPrintF( stdout, "%{du:time} Record registration result (error %#m)\n", &now, inError );
-
- if( !context->didRegister && !inError )
- {
- context->didRegister = true;
- if( context->updateDataPtr )
- {
- if( context->updateDelayMs > 0 )
- {
- dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
- context, RegisterRecordUpdate );
- }
- else
- {
- RegisterRecordUpdate( context );
- }
- }
- if( context->lifetimeMs == 0 )
- {
- Exit( kExitReason_TimeLimit );
- }
- else if( context->lifetimeMs > 0 )
- {
- dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
- kExitReason_TimeLimit, Exit );
- }
- }
-}
-
-//===========================================================================================================================
-// RegisterRecordUpdate
-//===========================================================================================================================
-
-static void RegisterRecordUpdate( void *inContext )
-{
- OSStatus err;
- RegisterRecordContext * const context = (RegisterRecordContext *) inContext;
-
- err = DNSServiceUpdateRecord( context->conRef, context->recordRef, 0, (uint16_t) context->updateDataLen,
- context->updateDataPtr, context->updateTTL );
- require_noerr( err, exit );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// ResolveCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServiceRef mainRef; // Main sdRef for shared connections.
- DNSServiceRef opRef; // sdRef for the DNSServiceResolve operation.
- DNSServiceFlags flags; // Flags argument for DNSServiceResolve().
- const char * name; // Service name argument for DNSServiceResolve().
- const char * type; // Service type argument for DNSServiceResolve().
- const char * domain; // Domain argument for DNSServiceResolve().
- uint32_t ifIndex; // Interface index argument for DNSServiceResolve().
- int timeLimitSecs; // Time limit for the DNSServiceResolve operation in seconds.
-
-} ResolveContext;
-
-static void ResolvePrintPrologue( const ResolveContext *inContext );
-static void ResolveContextFree( ResolveContext *inContext );
-static void DNSSD_API
- ResolveCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- const char * inHostname,
- uint16_t inPort,
- uint16_t inTXTLen,
- const unsigned char * inTXTPtr,
- void * inContext );
-
-static void ResolveCmd( void )
-{
- OSStatus err;
- DNSServiceRef sdRef;
- ResolveContext * context = NULL;
- dispatch_source_t signalSource = NULL;
- int useMainConnection;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (ResolveContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Check command parameters.
-
- if( gResolve_TimeLimitSecs < 0 )
- {
- FPrintF( stderr, "Invalid time limit: %d seconds.\n", gResolve_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create main connection.
-
- if( gConnectionOpt )
- {
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
- require_noerr_quiet( err, exit );
- useMainConnection = true;
- }
- else
- {
- useMainConnection = false;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
- if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-
- // Get interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Set remaining parameters.
-
- context->name = gResolve_Name;
- context->type = gResolve_Type;
- context->domain = gResolve_Domain;
- context->timeLimitSecs = gResolve_TimeLimitSecs;
-
- // Print prologue.
-
- ResolvePrintPrologue( context );
-
- // Start operation.
-
- sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
- err = DNSServiceResolve( &sdRef, context->flags, context->ifIndex, context->name, context->type, context->domain,
- ResolveCallback, NULL );
- require_noerr( err, exit );
-
- context->opRef = sdRef;
- if( !useMainConnection )
- {
- err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
-
- // Set time limit.
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
- kExitReason_TimeLimit, Exit );
- }
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) ResolveContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// ReconfirmCmd
-//===========================================================================================================================
-
-static void ReconfirmCmd( void )
-{
- OSStatus err;
- uint8_t * rdataPtr = NULL;
- size_t rdataLen = 0;
- DNSServiceFlags flags;
- uint32_t ifIndex;
- uint16_t type, class;
- char ifName[ kInterfaceNameBufLen ];
-
- // Get flags.
-
- flags = GetDNSSDFlagsFromOpts();
-
- // Get interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &ifIndex );
- require_noerr_quiet( err, exit );
-
- // Get record type.
-
- err = RecordTypeFromArgString( gReconfirmRecord_Type, &type );
- require_noerr( err, exit );
-
- // Get record data.
-
- if( gReconfirmRecord_Data )
- {
- err = RecordDataFromArgString( gReconfirmRecord_Data, &rdataPtr, &rdataLen );
- require_noerr_quiet( err, exit );
- }
-
- // Get record class.
-
- if( gReconfirmRecord_Class )
- {
- err = RecordClassFromArgString( gReconfirmRecord_Class, &class );
- require_noerr( err, exit );
- }
- else
- {
- class = kDNSServiceClass_IN;
- }
-
- // Print prologue.
-
- FPrintF( stdout, "Flags: %#{flags}\n", flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
- FPrintF( stdout, "Name: %s\n", gReconfirmRecord_Name );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
- FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
- FPrintF( stdout, "Data: %#H\n", rdataPtr, (int) rdataLen, INT_MAX );
- FPrintF( stdout, "---\n" );
-
- err = DNSServiceReconfirmRecord( flags, ifIndex, gReconfirmRecord_Name, type, class, (uint16_t) rdataLen, rdataPtr );
- FPrintF( stdout, "Error: %#m\n", err );
-
-exit:
- FreeNullSafe( rdataPtr );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// ResolvePrintPrologue
-//===========================================================================================================================
-
-static void ResolvePrintPrologue( const ResolveContext *inContext )
-{
- const int timeLimitSecs = inContext->timeLimitSecs;
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Name: %s\n", inContext->name );
- FPrintF( stdout, "Type: %s\n", inContext->type );
- FPrintF( stdout, "Domain: %s\n", inContext->domain );
- FPrintF( stdout, "Time limit: " );
- if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-// ResolveContextFree
-//===========================================================================================================================
-
-static void ResolveContextFree( ResolveContext *inContext )
-{
- DNSServiceForget( &inContext->opRef );
- DNSServiceForget( &inContext->mainRef );
- free( inContext );
-}
-
-//===========================================================================================================================
-// ResolveCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- ResolveCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- const char * inHostname,
- uint16_t inPort,
- uint16_t inTXTLen,
- const unsigned char * inTXTPtr,
- void * inContext )
-{
- struct timeval now;
- char errorStr[ 64 ];
-
- Unused( inSDRef );
- Unused( inFlags );
- Unused( inContext );
-
- gettimeofday( &now, NULL );
-
- if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
-
- FPrintF( stdout, "%{du:time}: %s can be reached at %s:%u (interface %d)%?s\n",
- &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
- if( inTXTLen == 1 )
- {
- FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
- }
- else
- {
- FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
- }
-}
-
-//===========================================================================================================================
-// GetAddrInfoPOSIXCmd
-//===========================================================================================================================
-
-#define AddressFamilyStr( X ) ( \
- ( (X) == AF_INET ) ? "inet" : \
- ( (X) == AF_INET6 ) ? "inet6" : \
- ( (X) == AF_UNSPEC ) ? "unspec" : \
- "???" )
-
-typedef struct
-{
- unsigned int flag;
- const char * str;
-
-} FlagStringPair;
-
-#define CaseFlagStringify( X ) { (X), # X }
-
-const FlagStringPair kGAIPOSIXFlagStringPairs[] =
-{
-#if( defined( AI_UNUSABLE ) )
- CaseFlagStringify( AI_UNUSABLE ),
-#endif
- CaseFlagStringify( AI_NUMERICSERV ),
- CaseFlagStringify( AI_V4MAPPED ),
- CaseFlagStringify( AI_ADDRCONFIG ),
-#if( defined( AI_V4MAPPED_CFG ) )
- CaseFlagStringify( AI_V4MAPPED_CFG ),
-#endif
- CaseFlagStringify( AI_ALL ),
- CaseFlagStringify( AI_NUMERICHOST ),
- CaseFlagStringify( AI_CANONNAME ),
- CaseFlagStringify( AI_PASSIVE ),
- { 0, NULL }
-};
-
-static void GetAddrInfoPOSIXCmd( void )
-{
- OSStatus err;
- struct addrinfo hints;
- struct timeval now;
- const struct addrinfo * addrInfo;
- struct addrinfo * addrInfoList = NULL;
- const FlagStringPair * pair;
-
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_socktype = SOCK_STREAM;
-
- // Set hints address family.
-
- if( !gGAIPOSIX_Family ) hints.ai_family = AF_UNSPEC;
- else if( strcasecmp( gGAIPOSIX_Family, "inet" ) == 0 ) hints.ai_family = AF_INET;
- else if( strcasecmp( gGAIPOSIX_Family, "inet6" ) == 0 ) hints.ai_family = AF_INET6;
- else if( strcasecmp( gGAIPOSIX_Family, "unspec" ) == 0 ) hints.ai_family = AF_UNSPEC;
- else
- {
- FPrintF( stderr, "Invalid address family: %s.\n", gGAIPOSIX_Family );
- err = kParamErr;
- goto exit;
- }
-
- // Set hints flags.
-
- if( gGAIPOSIXFlag_AddrConfig ) hints.ai_flags |= AI_ADDRCONFIG;
- if( gGAIPOSIXFlag_All ) hints.ai_flags |= AI_ALL;
- if( gGAIPOSIXFlag_CanonName ) hints.ai_flags |= AI_CANONNAME;
- if( gGAIPOSIXFlag_NumericHost ) hints.ai_flags |= AI_NUMERICHOST;
- if( gGAIPOSIXFlag_NumericServ ) hints.ai_flags |= AI_NUMERICSERV;
- if( gGAIPOSIXFlag_Passive ) hints.ai_flags |= AI_PASSIVE;
- if( gGAIPOSIXFlag_V4Mapped ) hints.ai_flags |= AI_V4MAPPED;
-#if( defined( AI_V4MAPPED_CFG ) )
- if( gGAIPOSIXFlag_V4MappedCFG ) hints.ai_flags |= AI_V4MAPPED_CFG;
-#endif
-#if( defined( AI_DEFAULT ) )
- if( gGAIPOSIXFlag_Default ) hints.ai_flags |= AI_DEFAULT;
-#endif
-#if( defined( AI_UNUSABLE ) )
- if( gGAIPOSIXFlag_Unusable ) hints.ai_flags |= AI_UNUSABLE;
-#endif
-
- // Print prologue.
-
- FPrintF( stdout, "Hostname: %s\n", gGAIPOSIX_HostName );
- FPrintF( stdout, "Servname: %s\n", gGAIPOSIX_ServName );
- FPrintF( stdout, "Address family: %s\n", AddressFamilyStr( hints.ai_family ) );
- FPrintF( stdout, "Flags: 0x%X < ", hints.ai_flags );
- for( pair = kGAIPOSIXFlagStringPairs; pair->str != NULL; ++pair )
- {
- if( ( (unsigned int) hints.ai_flags ) & pair->flag ) FPrintF( stdout, "%s ", pair->str );
- }
- FPrintF( stdout, ">\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
- // Call getaddrinfo().
-
- err = getaddrinfo( gGAIPOSIX_HostName, gGAIPOSIX_ServName, &hints, &addrInfoList );
- gettimeofday( &now, NULL );
- if( err )
- {
- FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
- }
- else
- {
- int addrCount = 0;
-
- for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next ) { ++addrCount; }
-
- FPrintF( stdout, "Addresses (%d total):\n", addrCount );
- for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next )
- {
- FPrintF( stdout, "%##a\n", addrInfo->ai_addr );
- }
- }
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "End time: %{du:time}\n", &now );
-
-exit:
- if( addrInfoList ) freeaddrinfo( addrInfoList );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// ReverseLookupCmd
-//===========================================================================================================================
-
-#define kIP6ARPADomainStr "ip6.arpa."
-
-static void ReverseLookupCmd( void )
-{
- OSStatus err;
- QueryRecordContext * context = NULL;
- DNSServiceRef sdRef;
- dispatch_source_t signalSource = NULL;
- uint32_t ipv4Addr;
- uint8_t ipv6Addr[ 16 ];
- char recordName[ ( 16 * 4 ) + sizeof( kIP6ARPADomainStr ) ];
- int useMainConnection;
- const char * endPtr;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Check command parameters.
-
- if( gReverseLookup_TimeLimitSecs < 0 )
- {
- FPrintF( stderr, "Invalid time limit: %d s.\n", gReverseLookup_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create main connection.
-
- if( gConnectionOpt )
- {
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
- require_noerr_quiet( err, exit );
- useMainConnection = true;
- }
- else
- {
- useMainConnection = false;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
- if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-
- // Get interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Create reverse lookup record name.
-
- err = StringToIPv4Address( gReverseLookup_IPAddr, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix,
- &ipv4Addr, NULL, NULL, NULL, &endPtr );
- if( err || ( *endPtr != '\0' ) )
- {
- char * dst;
- int i;
-
- err = StringToIPv6Address( gReverseLookup_IPAddr,
- kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
- ipv6Addr, NULL, NULL, NULL, &endPtr );
- if( err || ( *endPtr != '\0' ) )
- {
- FPrintF( stderr, "Invalid IP address: \"%s\".\n", gReverseLookup_IPAddr );
- err = kParamErr;
- goto exit;
- }
- dst = recordName;
- for( i = 15; i >= 0; --i )
- {
- *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] & 0x0F ];
- *dst++ = '.';
- *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] >> 4 ];
- *dst++ = '.';
- }
- strcpy_literal( dst, kIP6ARPADomainStr );
- check( ( strlen( recordName ) + 1 ) <= sizeof( recordName ) );
- }
- else
- {
- SNPrintF( recordName, sizeof( recordName ), "%u.%u.%u.%u.in-addr.arpa.",
- ipv4Addr & 0xFF,
- ( ipv4Addr >> 8 ) & 0xFF,
- ( ipv4Addr >> 16 ) & 0xFF,
- ( ipv4Addr >> 24 ) & 0xFF );
- }
-
- // Set remaining parameters.
-
- context->recordName = recordName;
- context->recordType = kDNSServiceType_PTR;
- context->timeLimitSecs = gReverseLookup_TimeLimitSecs;
- context->oneShotMode = gReverseLookup_OneShot ? true : false;
-
- // Print prologue.
-
- QueryRecordPrintPrologue( context );
-
- // Start operation.
-
- sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
- err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
- kDNSServiceClass_IN, QueryRecordCallback, context );
- require_noerr( err, exit );
-
- context->opRef = sdRef;
- if( !useMainConnection )
- {
- err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
-
- // Set time limit.
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
- kExitReason_TimeLimit, Exit );
- }
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) QueryRecordContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// PortMappingCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServiceRef mainRef; // Main sdRef for shared connection.
- DNSServiceRef opRef; // sdRef for the DNSServiceNATPortMappingCreate operation.
- DNSServiceFlags flags; // Flags for DNSServiceNATPortMappingCreate operation.
- uint32_t ifIndex; // Interface index argument for DNSServiceNATPortMappingCreate operation.
- DNSServiceProtocol protocols; // Protocols argument for DNSServiceNATPortMappingCreate operation.
- uint32_t ttl; // TTL argument for DNSServiceNATPortMappingCreate operation.
- uint16_t internalPort; // Internal port argument for DNSServiceNATPortMappingCreate operation.
- uint16_t externalPort; // External port argument for DNSServiceNATPortMappingCreate operation.
- Boolean printedHeader; // True if results header was printed.
-
-} PortMappingContext;
-
-static void PortMappingPrintPrologue( const PortMappingContext *inContext );
-static void PortMappingContextFree( PortMappingContext *inContext );
-static void DNSSD_API
- PortMappingCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- uint32_t inExternalIPv4Address,
- DNSServiceProtocol inProtocol,
- uint16_t inInternalPort,
- uint16_t inExternalPort,
- uint32_t inTTL,
- void * inContext );
-
-static void PortMappingCmd( void )
-{
- OSStatus err;
- PortMappingContext * context = NULL;
- DNSServiceRef sdRef;
- dispatch_source_t signalSource = NULL;
- int useMainConnection;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Create context.
-
- context = (PortMappingContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- // Check command parameters.
-
- if( ( gPortMapping_InternalPort < 0 ) || ( gPortMapping_InternalPort > UINT16_MAX ) )
- {
- FPrintF( stderr, "Internal port number %d is out-of-range.\n", gPortMapping_InternalPort );
- err = kParamErr;
- goto exit;
- }
-
- if( ( gPortMapping_ExternalPort < 0 ) || ( gPortMapping_ExternalPort > UINT16_MAX ) )
- {
- FPrintF( stderr, "External port number %d is out-of-range.\n", gPortMapping_ExternalPort );
- err = kParamErr;
- goto exit;
- }
-
- // Create main connection.
-
- if( gConnectionOpt )
- {
- err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
- require_noerr_quiet( err, exit );
- useMainConnection = true;
- }
- else
- {
- useMainConnection = false;
- }
-
- // Get flags.
-
- context->flags = GetDNSSDFlagsFromOpts();
- if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-
- // Get interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- // Set remaining parameters.
-
- if( gPortMapping_ProtocolTCP ) context->protocols |= kDNSServiceProtocol_TCP;
- if( gPortMapping_ProtocolUDP ) context->protocols |= kDNSServiceProtocol_UDP;
- context->ttl = (uint32_t) gPortMapping_TTL;
- context->internalPort = (uint16_t) gPortMapping_InternalPort;
- context->externalPort = (uint16_t) gPortMapping_ExternalPort;
-
- // Print prologue.
-
- PortMappingPrintPrologue( context );
-
- // Start operation.
-
- sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
- err = DNSServiceNATPortMappingCreate( &sdRef, context->flags, context->ifIndex, context->protocols,
- htons( context->internalPort ), htons( context->externalPort ), context->ttl, PortMappingCallback, context );
- require_noerr( err, exit );
-
- context->opRef = sdRef;
- if( !useMainConnection )
- {
- err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
- }
-
- dispatch_main();
-
-exit:
- dispatch_source_forget( &signalSource );
- if( context ) PortMappingContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// PortMappingPrintPrologue
-//===========================================================================================================================
-
-static void PortMappingPrintPrologue( const PortMappingContext *inContext )
-{
- char ifName[ kInterfaceNameBufLen ];
-
- InterfaceIndexToName( inContext->ifIndex, ifName );
-
- FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
- FPrintF( stdout, "Protocols: %#{flags}\n", inContext->protocols, kDNSServiceProtocolDescriptors );
- FPrintF( stdout, "Internal Port: %u\n", inContext->internalPort );
- FPrintF( stdout, "External Port: %u\n", inContext->externalPort );
- FPrintF( stdout, "TTL: %u%?s\n", inContext->ttl, !inContext->ttl,
- " (system will use a default value.)" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
-}
-
-//===========================================================================================================================
-// PortMappingContextFree
-//===========================================================================================================================
-
-static void PortMappingContextFree( PortMappingContext *inContext )
-{
- DNSServiceForget( &inContext->opRef );
- DNSServiceForget( &inContext->mainRef );
- free( inContext );
-}
-
-//===========================================================================================================================
-// PortMappingCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- PortMappingCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- uint32_t inExternalIPv4Address,
- DNSServiceProtocol inProtocol,
- uint16_t inInternalPort,
- uint16_t inExternalPort,
- uint32_t inTTL,
- void * inContext )
-{
- PortMappingContext * const context = (PortMappingContext *) inContext;
- struct timeval now;
- char errorStr[ 128 ];
-
- Unused( inSDRef );
- Unused( inFlags );
-
- gettimeofday( &now, NULL );
-
- if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " (error: %#m)", inError );
- if( !context->printedHeader )
- {
- FPrintF( stdout, "%-26s IF %7s %15s %7s %6s Protocol\n", "Timestamp", "IntPort", "ExtAddr", "ExtPort", "TTL" );
- context->printedHeader = true;
- }
- FPrintF( stdout, "%{du:time} %2u %7u %15.4a %7u %6u %#{flags}%?s\n",
- &now, inInterfaceIndex, ntohs( inInternalPort), &inExternalIPv4Address, ntohs( inExternalPort ), inTTL,
- inProtocol, kDNSServiceProtocolDescriptors, inError, errorStr );
-}
-
-//===========================================================================================================================
-// BrowseAllCmd
-//===========================================================================================================================
-
-typedef struct BrowseAllConnection BrowseAllConnection;
-
-typedef struct
-{
- ServiceBrowserRef browser; // Service browser.
- ServiceBrowserResults * results; // Results from the service browser.
- BrowseAllConnection * connectionList; // List of connections.
- dispatch_source_t connectionTimer; // Timer for connection timeout.
- int connectionPendingCount; // Number of pending connections.
- int connectionTimeoutSecs; // Timeout value for connections in seconds.
-
-} BrowseAllContext;
-
-struct BrowseAllConnection
-{
- BrowseAllConnection * next; // Next connection object in list.
- sockaddr_ip sip; // IPv4 or IPv6 address to connect to.
- uint16_t port; // TCP port to connect to.
- AsyncConnectionRef asyncCnx; // AsyncConnection object to handle the actual connection.
- OSStatus status; // Status of connection. NoErr means connection succeeded.
- CFTimeInterval connectTimeSecs; // Time it took to connect in seconds.
- int32_t refCount; // This object's reference count.
- BrowseAllContext * context; // Back pointer to parent context.
-};
-
-static void _BrowseAllContextFree( BrowseAllContext *inContext );
-static void _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
-static OSStatus
- _BrowseAllConnectionCreate(
- const struct sockaddr * inSockAddr,
- uint16_t inPort,
- BrowseAllContext * inContext,
- BrowseAllConnection ** outConnection );
-static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection );
-static void _BrowseAllConnectionRelease( BrowseAllConnection *inConnection );
-static void _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg );
-static void _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg );
-static void _BrowseAllExit( void *inContext );
-
-static Boolean _IsServiceTypeTCP( const char *inServiceType );
-
-static void BrowseAllCmd( void )
-{
- OSStatus err;
- BrowseAllContext * context = NULL;
- size_t i;
- uint32_t ifIndex;
- char ifName[ kInterfaceNameBufLen ];
-
- // Check parameters.
-
- if( gBrowseAll_BrowseTimeSecs <= 0 )
- {
- FPrintF( stdout, "Invalid browse time: %d seconds.\n", gBrowseAll_BrowseTimeSecs );
- err = kParamErr;
- goto exit;
- }
-
- context = (BrowseAllContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->connectionTimeoutSecs = gBrowseAll_ConnectTimeout;
-#if( TARGET_OS_POSIX )
- // Increase the open file descriptor limit for connection sockets.
-
- if( context->connectionTimeoutSecs > 0 )
- {
- struct rlimit fdLimits;
-
- err = getrlimit( RLIMIT_NOFILE, &fdLimits );
- err = map_global_noerr_errno( err );
- require_noerr( err, exit );
-
- if( fdLimits.rlim_cur < 4096 )
- {
- fdLimits.rlim_cur = 4096;
- err = setrlimit( RLIMIT_NOFILE, &fdLimits );
- err = map_global_noerr_errno( err );
- require_noerr( err, exit );
- }
- }
-#endif
-
- // Get interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &ifIndex );
- require_noerr_quiet( err, exit );
-
- // Print prologue.
-
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
- FPrintF( stdout, "Service types: ");
- if( gBrowseAll_ServiceTypesCount > 0 )
- {
- FPrintF( stdout, "%s", gBrowseAll_ServiceTypes[ 0 ] );
- for( i = 1; i < gBrowseAll_ServiceTypesCount; ++i )
- {
- FPrintF( stdout, ", %s", gBrowseAll_ServiceTypes[ i ] );
- }
- FPrintF( stdout, "\n" );
- }
- else
- {
- FPrintF( stdout, "all services\n" );
- }
- FPrintF( stdout, "Domain: %s\n", gBrowseAll_Domain ? gBrowseAll_Domain : "default domains" );
- FPrintF( stdout, "Browse time: %d second%?c\n", gBrowseAll_BrowseTimeSecs, gBrowseAll_BrowseTimeSecs != 1, 's' );
- FPrintF( stdout, "Connect timeout: %d second%?c\n",
- context->connectionTimeoutSecs, context->connectionTimeoutSecs != 1, 's' );
- FPrintF( stdout, "IncludeAWDL: %s\n", gDNSSDFlag_IncludeAWDL ? "yes" : "no" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
- err = ServiceBrowserCreate( dispatch_get_main_queue(), ifIndex, gBrowseAll_Domain,
- (unsigned int) gBrowseAll_BrowseTimeSecs, gDNSSDFlag_IncludeAWDL ? true : false, &context->browser );
- require_noerr( err, exit );
-
- for( i = 0; i < gBrowseAll_ServiceTypesCount; ++i )
- {
- err = ServiceBrowserAddServiceType( context->browser, gBrowseAll_ServiceTypes[ i ] );
- require_noerr( err, exit );
- }
- ServiceBrowserSetCallback( context->browser, _BrowseAllServiceBrowserCallback, context );
- ServiceBrowserStart( context->browser );
- dispatch_main();
-
-exit:
- if( context ) _BrowseAllContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// _BrowseAllContextFree
-//===========================================================================================================================
-
-static void _BrowseAllContextFree( BrowseAllContext *inContext )
-{
- check( !inContext->browser );
- check( !inContext->connectionTimer );
- check( !inContext->connectionList );
- ForgetServiceBrowserResults( &inContext->results );
- free( inContext );
-}
-
-//===========================================================================================================================
-// _BrowseAllServiceBrowserCallback
-//===========================================================================================================================
-
-#define kDiscardProtocolPort 9
-
-static void _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
-{
- OSStatus err;
- BrowseAllContext * const context = (BrowseAllContext *) inContext;
- SBRDomain * domain;
- SBRServiceType * type;
- SBRServiceInstance * instance;
- SBRIPAddress * ipaddr;
-
- Unused( inError );
-
- require_action( inResults, exit, err = kUnexpectedErr );
-
- check( !context->results );
- context->results = inResults;
- ServiceBrowserResultsRetain( context->results );
-
- check( context->connectionPendingCount == 0 );
- if( context->connectionTimeoutSecs > 0 )
- {
- BrowseAllConnection * connection;
- BrowseAllConnection ** connectionPtr = &context->connectionList;
- char destination[ kSockAddrStringMaxSize ];
-
- for( domain = context->results->domainList; domain; domain = domain->next )
- {
- for( type = domain->typeList; type; type = type->next )
- {
- if( !_IsServiceTypeTCP( type->name ) ) continue;
- for( instance = type->instanceList; instance; instance = instance->next )
- {
- if( instance->port == kDiscardProtocolPort ) continue;
- for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
- {
- err = _BrowseAllConnectionCreate( &ipaddr->sip.sa, instance->port, context, &connection );
- require_noerr( err, exit );
-
- *connectionPtr = connection;
- connectionPtr = &connection->next;
-
- err = SockAddrToString( &ipaddr->sip, kSockAddrStringFlagsNoPort, destination );
- check_noerr( err );
- if( !err )
- {
- err = AsyncConnection_Connect( &connection->asyncCnx, destination, -instance->port,
- kAsyncConnectionFlag_P2P, kAsyncConnectionNoTimeout,
- kSocketBufferSize_DontSet, kSocketBufferSize_DontSet,
- _BrowseAllConnectionProgress, connection, _BrowseAllConnectionHandler, connection,
- dispatch_get_main_queue() );
- check_noerr( err );
- }
- if( !err )
- {
- _BrowseAllConnectionRetain( connection );
- connection->status = kInProgressErr;
- ++context->connectionPendingCount;
- }
- else
- {
- connection->status = err;
- }
- }
- }
- }
- }
- }
-
- if( context->connectionPendingCount > 0 )
- {
- check( !context->connectionTimer );
- err = DispatchTimerCreate( dispatch_time_seconds( context->connectionTimeoutSecs ), DISPATCH_TIME_FOREVER,
- 100 * kNanosecondsPerMillisecond, NULL, _BrowseAllExit, NULL, context, &context->connectionTimer );
- require_noerr( err, exit );
- dispatch_resume( context->connectionTimer );
- }
- else
- {
- dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
- }
- err = kNoErr;
-
-exit:
- ForgetCF( &context->browser );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// _BrowseAllConnectionCreate
-//===========================================================================================================================
-
-static OSStatus
- _BrowseAllConnectionCreate(
- const struct sockaddr * inSockAddr,
- uint16_t inPort,
- BrowseAllContext * inContext,
- BrowseAllConnection ** outConnection )
-{
- OSStatus err;
- BrowseAllConnection * obj;
-
- obj = (BrowseAllConnection *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->refCount = 1;
- SockAddrCopy( inSockAddr, &obj->sip );
- obj->port = inPort;
- obj->context = inContext;
-
- *outConnection = obj;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _BrowseAllConnectionRetain
-//===========================================================================================================================
-
-static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection )
-{
- ++inConnection->refCount;
-}
-
-//===========================================================================================================================
-// _BrowseAllConnectionRelease
-//===========================================================================================================================
-
-static void _BrowseAllConnectionRelease( BrowseAllConnection *inConnection )
-{
- if( --inConnection->refCount == 0 ) free( inConnection );
-}
-
-//===========================================================================================================================
-// _BrowseAllConnectionProgress
-//===========================================================================================================================
-
-static void _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg )
-{
- BrowseAllConnection * const connection = (BrowseAllConnection *) inArg;
-
- if( inPhase == kAsyncConnectionPhase_Connected )
- {
- const AsyncConnectedInfo * const info = (AsyncConnectedInfo *) inDetails;
-
- connection->connectTimeSecs = info->connectSecs;
- }
-}
-
-//===========================================================================================================================
-// _BrowseAllConnectionHandler
-//===========================================================================================================================
-
-static void _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg )
-{
- BrowseAllConnection * const connection = (BrowseAllConnection *) inArg;
- BrowseAllContext * const context = connection->context;
-
- connection->status = inError;
- ForgetSocket( &inSock );
- if( context )
- {
- check( context->connectionPendingCount > 0 );
- if( ( --context->connectionPendingCount == 0 ) && context->connectionTimer )
- {
- dispatch_source_forget( &context->connectionTimer );
- dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
- }
- }
- _BrowseAllConnectionRelease( connection );
-}
-
-//===========================================================================================================================
-// _BrowseAllExit
-//===========================================================================================================================
-
-#define Indent( X ) ( (X) * 4 ), ""
-
-static void _BrowseAllExit( void *inContext )
-{
- BrowseAllContext * const context = (BrowseAllContext *) inContext;
- SBRDomain * domain;
- SBRServiceType * type;
- SBRServiceInstance * instance;
- SBRIPAddress * ipaddr;
- char textBuf[ 512 ];
-#if( TARGET_OS_POSIX )
- const Boolean useColor = isatty( STDOUT_FILENO ) ? true : false;
-#endif
-
- dispatch_source_forget( &context->connectionTimer );
-
- for( domain = context->results->domainList; domain; domain = domain->next )
- {
- FPrintF( stdout, "%s\n\n", domain->name );
-
- for( type = domain->typeList; type; type = type->next )
- {
- const char * description;
- const Boolean serviceTypeIsTCP = _IsServiceTypeTCP( type->name );
-
- description = ServiceTypeDescription( type->name );
- if( description ) FPrintF( stdout, "%*s" "%s (%s)\n\n", Indent( 1 ), description, type->name );
- else FPrintF( stdout, "%*s" "%s\n\n", Indent( 1 ), type->name );
-
- for( instance = type->instanceList; instance; instance = instance->next )
- {
- char * dst = textBuf;
- char * const lim = &textBuf[ countof( textBuf ) ];
- char ifname[ IF_NAMESIZE + 1 ];
-
- SNPrintF_Add( &dst, lim, "%s via ", instance->name );
- if( instance->ifIndex == 0 )
- {
- SNPrintF_Add( &dst, lim, "the Internet" );
- }
- else if( if_indextoname( instance->ifIndex, ifname ) )
- {
- NetTransportType netType;
-
- SocketGetInterfaceInfo( kInvalidSocketRef, ifname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &netType );
- SNPrintF_Add( &dst, lim, "%s (%s)",
- ( netType == kNetTransportType_Ethernet ) ? "Ethernet" : NetTransportTypeToString( netType ),
- ifname );
- }
- else
- {
- SNPrintF_Add( &dst, lim, "interface index %u", instance->ifIndex );
- }
- FPrintF( stdout, "%*s" "%-55s %4llu.%03llu ms\n\n",
- Indent( 2 ), textBuf, instance->discoverTimeUs / 1000, instance->discoverTimeUs % 1000 );
-
- if( instance->hostname )
- {
- SNPrintF( textBuf, sizeof( textBuf ), "%s:%u", instance->hostname, instance->port );
- FPrintF( stdout, "%*s" "%-51s %4llu.%03llu ms\n",
- Indent( 3 ), textBuf, instance->resolveTimeUs / 1000, instance->resolveTimeUs % 1000 );
- }
- else
- {
- FPrintF( stdout, "%*s" "%s:%u\n", Indent( 3 ), instance->hostname, instance->port );
- }
-
- for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
- {
- BrowseAllConnection * conn;
- BrowseAllConnection ** connPtr;
-
- FPrintF( stdout, "%*s" "%-##47a %4llu.%03llu ms",
- Indent( 4 ), &ipaddr->sip.sa, ipaddr->resolveTimeUs / 1000, ipaddr->resolveTimeUs % 1000 );
-
- conn = NULL;
- if( serviceTypeIsTCP && ( instance->port != kDiscardProtocolPort ) )
- {
- for( connPtr = &context->connectionList; ( conn = *connPtr ) != NULL; connPtr = &conn->next )
- {
- if( ( conn->port == instance->port ) &&
- ( SockAddrCompareAddr( &conn->sip, &ipaddr->sip ) == 0 ) ) break;
- }
- if( conn )
- {
- if( conn->status == kInProgressErr ) conn->status = kTimeoutErr;
- *connPtr = conn->next;
- conn->context = NULL;
- AsyncConnection_Forget( &conn->asyncCnx );
- }
- }
-
- if( conn )
- {
- if( conn->status == kNoErr )
- {
- FPrintF( stdout, " (%sconnected%s in %.3f ms)\n",
- useColor ? kANSIGreen : "", useColor ? kANSINormal : "", conn->connectTimeSecs * 1000 );
- }
- else
- {
- FPrintF( stdout, " (%scould not connect%s: %m)\n",
- useColor ? kANSIRed : "", useColor ? kANSINormal : "", conn->status );
- }
- _BrowseAllConnectionRelease( conn );
- }
- else
- {
- FPrintF( stdout, " (no connection attempted)\n" );
- }
- }
-
- FPrintF( stdout, "\n" );
- if( instance->txtLen == 0 ) continue;
-
- FPrintF( stdout, "%*s" "TXT record (%zu byte%?c):\n",
- Indent( 3 ), instance->txtLen, instance->txtLen != 1, 's' );
- if( instance->txtLen > 1 )
- {
- FPrintF( stdout, "%3{txt}", instance->txtPtr, instance->txtLen );
- }
- else
- {
- FPrintF( stdout, "%*s" "%#H\n", Indent( 3 ), instance->txtPtr, (int) instance->txtLen, INT_MAX );
- }
- FPrintF( stdout, "\n" );
- }
- FPrintF( stdout, "\n" );
- }
- }
-
- _BrowseAllContextFree( context );
- Exit( NULL );
-}
-
-//===========================================================================================================================
-// _IsServiceTypeTCP
-//===========================================================================================================================
-
-static Boolean _IsServiceTypeTCP( const char *inServiceType )
-{
- OSStatus err;
- const uint8_t * secondLabel;
- uint8_t name[ kDomainNameLengthMax ];
-
- err = DomainNameFromString( name, inServiceType, NULL );
- if( !err )
- {
- secondLabel = NextLabel( name );
- if( secondLabel && DomainNameEqual( secondLabel, (const uint8_t *) "\x04" "_tcp" ) ) return( true );
- }
- return( false );
-}
-
-//===========================================================================================================================
-// GetNameInfoCmd
-//===========================================================================================================================
-
-const FlagStringPair kGetNameInfoFlagStringPairs[] =
-{
- CaseFlagStringify( NI_NUMERICSCOPE ),
- CaseFlagStringify( NI_DGRAM ),
- CaseFlagStringify( NI_NUMERICSERV ),
- CaseFlagStringify( NI_NAMEREQD ),
- CaseFlagStringify( NI_NUMERICHOST ),
- CaseFlagStringify( NI_NOFQDN ),
- { 0, NULL }
-};
-
-static void GetNameInfoCmd( void )
-{
- OSStatus err;
- sockaddr_ip sip;
- size_t sockAddrLen;
- unsigned int flags;
- const FlagStringPair * pair;
- struct timeval now;
- char host[ NI_MAXHOST ];
- char serv[ NI_MAXSERV ];
-
- err = StringToSockAddr( gGetNameInfo_IPAddress, &sip, sizeof( sip ), &sockAddrLen );
- check_noerr( err );
- if( err )
- {
- FPrintF( stderr, "Failed to convert \"%s\" to a sockaddr.\n", gGetNameInfo_IPAddress );
- goto exit;
- }
-
- flags = 0;
- if( gGetNameInfoFlag_DGram ) flags |= NI_DGRAM;
- if( gGetNameInfoFlag_NameReqd ) flags |= NI_NAMEREQD;
- if( gGetNameInfoFlag_NoFQDN ) flags |= NI_NOFQDN;
- if( gGetNameInfoFlag_NumericHost ) flags |= NI_NUMERICHOST;
- if( gGetNameInfoFlag_NumericScope ) flags |= NI_NUMERICSCOPE;
- if( gGetNameInfoFlag_NumericServ ) flags |= NI_NUMERICSERV;
-
- // Print prologue.
-
- FPrintF( stdout, "SockAddr: %##a\n", &sip.sa );
- FPrintF( stdout, "Flags: 0x%X < ", flags );
- for( pair = kGetNameInfoFlagStringPairs; pair->str != NULL; ++pair )
- {
- if( flags & pair->flag ) FPrintF( stdout, "%s ", pair->str );
- }
- FPrintF( stdout, ">\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
- // Call getnameinfo().
-
- err = getnameinfo( &sip.sa, (socklen_t) sockAddrLen, host, (socklen_t) sizeof( host ), serv, (socklen_t) sizeof( serv ),
- (int) flags );
- gettimeofday( &now, NULL );
- if( err )
- {
- FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
- }
- else
- {
- FPrintF( stdout, "host: %s\n", host );
- FPrintF( stdout, "serv: %s\n", serv );
- }
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "End time: %{du:time}\n", &now );
-
-exit:
- gExitCode = err ? 1 : 0;
-}
-
-//===========================================================================================================================
-// GetAddrInfoStressCmd
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServiceRef mainRef;
- DNSServiceRef sdRef;
- DNSServiceFlags flags;
- unsigned int interfaceIndex;
- unsigned int connectionNumber;
- unsigned int requestCount;
- unsigned int requestCountMax;
- unsigned int requestCountLimit;
- unsigned int durationMinMs;
- unsigned int durationMaxMs;
-
-} GAIStressContext;
-
-static void GetAddrInfoStressEvent( void *inContext );
-static void DNSSD_API
- GetAddrInfoStressCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext );
-
-static void GetAddrInfoStressCmd( void )
-{
- OSStatus err;
- GAIStressContext * context = NULL;
- int i;
- DNSServiceFlags flags;
- uint32_t ifIndex;
- char ifName[ kInterfaceNameBufLen ];
-
- if( gGAIStress_TestDurationSecs < 0 )
- {
- FPrintF( stdout, "Invalid test duration: %d s.\n", gGAIStress_TestDurationSecs );
- err = kParamErr;
- goto exit;
- }
- if( gGAIStress_ConnectionCount <= 0 )
- {
- FPrintF( stdout, "Invalid simultaneous connection count: %d.\n", gGAIStress_ConnectionCount );
- err = kParamErr;
- goto exit;
- }
- if( gGAIStress_DurationMinMs <= 0 )
- {
- FPrintF( stdout, "Invalid minimum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMinMs );
- err = kParamErr;
- goto exit;
- }
- if( gGAIStress_DurationMaxMs <= 0 )
- {
- FPrintF( stdout, "Invalid maximum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMaxMs );
- err = kParamErr;
- goto exit;
- }
- if( gGAIStress_DurationMinMs > gGAIStress_DurationMaxMs )
- {
- FPrintF( stdout, "Invalid minimum and maximum DNSServiceGetAddrInfo() durations: %d ms and %d ms.\n",
- gGAIStress_DurationMinMs, gGAIStress_DurationMaxMs );
- err = kParamErr;
- goto exit;
- }
- if( gGAIStress_RequestCountMax <= 0 )
- {
- FPrintF( stdout, "Invalid maximum request count: %d.\n", gGAIStress_RequestCountMax );
- err = kParamErr;
- goto exit;
- }
-
- // Set flags.
-
- flags = GetDNSSDFlagsFromOpts();
-
- // Set interface index.
-
- err = InterfaceIndexFromArgString( gInterface, &ifIndex );
- require_noerr_quiet( err, exit );
-
- for( i = 0; i < gGAIStress_ConnectionCount; ++i )
- {
- context = (GAIStressContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->flags = flags;
- context->interfaceIndex = ifIndex;
- context->connectionNumber = (unsigned int)( i + 1 );
- context->requestCountMax = (unsigned int) gGAIStress_RequestCountMax;
- context->durationMinMs = (unsigned int) gGAIStress_DurationMinMs;
- context->durationMaxMs = (unsigned int) gGAIStress_DurationMaxMs;
-
- dispatch_async_f( dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
- context = NULL;
- }
-
- if( gGAIStress_TestDurationSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( gGAIStress_TestDurationSecs ), dispatch_get_main_queue(), NULL, Exit );
- }
-
- FPrintF( stdout, "Flags: %#{flags}\n", flags, kDNSServiceFlagsDescriptors );
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
- FPrintF( stdout, "Test duration: " );
- if( gGAIStress_TestDurationSecs == 0 )
- {
- FPrintF( stdout, "∞\n" );
- }
- else
- {
- FPrintF( stdout, "%d s\n", gGAIStress_TestDurationSecs );
- }
- FPrintF( stdout, "Connection count: %d\n", gGAIStress_ConnectionCount );
- FPrintF( stdout, "Request duration min: %d ms\n", gGAIStress_DurationMinMs );
- FPrintF( stdout, "Request duration max: %d ms\n", gGAIStress_DurationMaxMs );
- FPrintF( stdout, "Request count max: %d\n", gGAIStress_RequestCountMax );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL);
- FPrintF( stdout, "---\n" );
-
- dispatch_main();
-
-exit:
- FreeNullSafe( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// GetAddrInfoStressEvent
-//===========================================================================================================================
-
-#define kStressRandStrLen 5
-
-#define kLowercaseAlphaCharSet "abcdefghijklmnopqrstuvwxyz"
-
-static void GetAddrInfoStressEvent( void *inContext )
-{
- GAIStressContext * const context = (GAIStressContext *) inContext;
- OSStatus err;
- DNSServiceRef sdRef;
- unsigned int nextMs;
- char randomStr[ kStressRandStrLen + 1 ];
- char hostname[ kStressRandStrLen + 4 + 1 ];
- Boolean isConnectionNew = false;
- static Boolean printedHeader = false;
-
- if( !context->mainRef || ( context->requestCount >= context->requestCountLimit ) )
- {
- DNSServiceForget( &context->mainRef );
- context->sdRef = NULL;
- context->requestCount = 0;
- context->requestCountLimit = RandomRange( 1, context->requestCountMax );
-
- err = DNSServiceCreateConnection( &context->mainRef );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( context->mainRef, dispatch_get_main_queue() );
- require_noerr( err, exit );
-
- isConnectionNew = true;
- }
-
- RandomString( kLowercaseAlphaCharSet, sizeof_string( kLowercaseAlphaCharSet ), 2, kStressRandStrLen, randomStr );
- SNPrintF( hostname, sizeof( hostname ), "%s.com", randomStr );
-
- nextMs = RandomRange( context->durationMinMs, context->durationMaxMs );
-
- if( !printedHeader )
- {
- FPrintF( stdout, "%-26s Conn Hostname Dur (ms)\n", "Timestamp" );
- printedHeader = true;
- }
- FPrintF( stdout, "%{du:time} %3u%c %9s %8u\n",
- NULL, context->connectionNumber, isConnectionNew ? '*': ' ', hostname, nextMs );
-
- DNSServiceForget( &context->sdRef );
- sdRef = context->mainRef;
- err = DNSServiceGetAddrInfo( &sdRef, context->flags | kDNSServiceFlagsShareConnection, context->interfaceIndex,
- kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, hostname, GetAddrInfoStressCallback, NULL );
- require_noerr( err, exit );
- context->sdRef = sdRef;
-
- context->requestCount++;
-
- dispatch_after_f( dispatch_time_milliseconds( nextMs ), dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// GetAddrInfoStressCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- GetAddrInfoStressCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext )
-{
- Unused( inSDRef );
- Unused( inFlags );
- Unused( inInterfaceIndex );
- Unused( inError );
- Unused( inHostname );
- Unused( inSockAddr );
- Unused( inTTL );
- Unused( inContext );
-}
-
-//===========================================================================================================================
-// DNSQueryCmd
-//===========================================================================================================================
-
-typedef struct
-{
- sockaddr_ip serverAddr;
- uint64_t sendTicks;
- uint8_t * msgPtr;
- size_t msgLen;
- size_t msgOffset;
- const char * name;
- dispatch_source_t readSource;
- SocketRef sock;
- int timeLimitSecs;
- uint16_t queryID;
- uint16_t type;
- Boolean haveTCPLen;
- Boolean useTCP;
- Boolean printRawRData; // True if RDATA results are not to be formatted.
- uint8_t msgBuf[ 512 ];
-
-} DNSQueryContext;
-
-static void DNSQueryPrintPrologue( const DNSQueryContext *inContext );
-static void DNSQueryReadHandler( void *inContext );
-static void DNSQueryCancelHandler( void *inContext );
-
-static void DNSQueryCmd( void )
-{
- OSStatus err;
- DNSQueryContext * context = NULL;
- uint8_t * msgPtr;
- size_t msgLen, sendLen;
-
- // Check command parameters.
-
- if( gDNSQuery_TimeLimitSecs < -1 )
- {
- FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSQuery_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
- if( ( gDNSQuery_Flags < INT16_MIN ) || ( gDNSQuery_Flags > UINT16_MAX ) )
- {
- FPrintF( stdout, "DNS flags-and-codes value is out of the unsigned 16-bit range: 0x%08X.\n", gDNSQuery_Flags );
- err = kParamErr;
- goto exit;
- }
-
- // Create context.
-
- context = (DNSQueryContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->name = gDNSQuery_Name;
- context->sock = kInvalidSocketRef;
- context->timeLimitSecs = gDNSQuery_TimeLimitSecs;
- context->queryID = (uint16_t) Random32();
- context->useTCP = gDNSQuery_UseTCP ? true : false;
- context->printRawRData = gDNSQuery_RawRData ? true : false;
-
-#if( TARGET_OS_DARWIN )
- if( gDNSQuery_Server )
-#endif
- {
- err = StringToSockAddr( gDNSQuery_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
- require_noerr( err, exit );
- }
-#if( TARGET_OS_DARWIN )
- else
- {
- err = GetDefaultDNSServer( &context->serverAddr );
- require_noerr( err, exit );
- }
-#endif
- if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSPort );
-
- err = RecordTypeFromArgString( gDNSQuery_Type, &context->type );
- require_noerr( err, exit );
-
- // Write query message.
-
- check_compile_time_code( sizeof( context->msgBuf ) >= ( kDNSQueryMessageMaxLen + 2 ) );
-
- msgPtr = context->useTCP ? &context->msgBuf[ 2 ] : context->msgBuf;
- err = WriteDNSQueryMessage( msgPtr, context->queryID, (uint16_t) gDNSQuery_Flags, context->name, context->type,
- kDNSServiceClass_IN, &msgLen );
- require_noerr( err, exit );
- check( msgLen <= UINT16_MAX );
-
- if( context->useTCP )
- {
- WriteBig16( context->msgBuf, msgLen );
- sendLen = 2 + msgLen;
- }
- else
- {
- sendLen = msgLen;
- }
-
- DNSQueryPrintPrologue( context );
-
- if( gDNSQuery_Verbose )
- {
- FPrintF( stdout, "DNS message to send:\n\n%{du:dnsmsg}", msgPtr, msgLen );
- FPrintF( stdout, "---\n" );
- }
-
- if( context->useTCP )
- {
- // Create TCP socket.
-
- context->sock = socket( context->serverAddr.sa.sa_family, SOCK_STREAM, IPPROTO_TCP );
- err = map_socket_creation_errno( context->sock );
- require_noerr( err, exit );
-
- err = SocketConnect( context->sock, &context->serverAddr, 5 );
- require_noerr( err, exit );
- }
- else
- {
- // Create UDP socket.
-
- err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &context->sock );
- require_noerr( err, exit );
- }
-
- context->sendTicks = UpTicks();
- err = SocketWriteAll( context->sock, context->msgBuf, sendLen, 5 );
- require_noerr( err, exit );
-
- if( context->timeLimitSecs == 0 ) goto exit;
-
- err = DispatchReadSourceCreate( context->sock, NULL, DNSQueryReadHandler, DNSQueryCancelHandler, context,
- &context->readSource );
- require_noerr( err, exit );
- dispatch_resume( context->readSource );
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
- Exit );
- }
- dispatch_main();
-
-exit:
- if( context )
- {
- dispatch_source_forget( &context->readSource );
- ForgetSocket( &context->sock );
- free( context );
- }
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// DNSQueryPrintPrologue
-//===========================================================================================================================
-
-static void DNSQueryPrintPrologue( const DNSQueryContext *inContext )
-{
- const int timeLimitSecs = inContext->timeLimitSecs;
-
- FPrintF( stdout, "Name: %s\n", inContext->name );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->type ), inContext->type );
- FPrintF( stdout, "Server: %##a\n", &inContext->serverAddr );
- FPrintF( stdout, "Transport: %s\n", inContext->useTCP ? "TCP" : "UDP" );
- FPrintF( stdout, "Time limit: " );
- if( timeLimitSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-// DNSQueryReadHandler
-//===========================================================================================================================
-
-static void DNSQueryReadHandler( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- const uint64_t nowTicks = UpTicks();
- DNSQueryContext * const context = (DNSQueryContext *) inContext;
-
- gettimeofday( &now, NULL );
-
- if( context->useTCP )
- {
- if( !context->haveTCPLen )
- {
- err = SocketReadData( context->sock, &context->msgBuf, 2, &context->msgOffset );
- if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
- require_noerr( err, exit );
-
- context->msgOffset = 0;
- context->msgLen = ReadBig16( context->msgBuf );
- context->haveTCPLen = true;
- if( context->msgLen <= sizeof( context->msgBuf ) )
- {
- context->msgPtr = context->msgBuf;
- }
- else
- {
- context->msgPtr = (uint8_t *) malloc( context->msgLen );
- require_action( context->msgPtr, exit, err = kNoMemoryErr );
- }
- }
-
- err = SocketReadData( context->sock, context->msgPtr, context->msgLen, &context->msgOffset );
- if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
- require_noerr( err, exit );
- context->msgOffset = 0;
- context->haveTCPLen = false;
- }
- else
- {
- sockaddr_ip fromAddr;
-
- context->msgPtr = context->msgBuf;
- err = SocketRecvFrom( context->sock, context->msgPtr, sizeof( context->msgBuf ), &context->msgLen, &fromAddr,
- sizeof( fromAddr ), NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
- }
-
- FPrintF( stdout, "Receive time: %{du:time}\n", &now );
- FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
- FPrintF( stdout, "Message size: %zu\n", context->msgLen );
- FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
- FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgPtr, context->msgLen );
-
- if( ( context->msgLen >= kDNSHeaderLength ) && ( DNSHeaderGetID( (DNSHeader *) context->msgPtr ) == context->queryID ) )
- {
- Exit( kExitReason_ReceivedResponse );
- }
-
-exit:
- if( err ) dispatch_source_forget( &context->readSource );
-}
-
-//===========================================================================================================================
-// DNSQueryCancelHandler
-//===========================================================================================================================
-
-static void DNSQueryCancelHandler( void *inContext )
-{
- DNSQueryContext * const context = (DNSQueryContext *) inContext;
-
- check( !context->readSource );
- ForgetSocket( &context->sock );
- if( context->msgPtr != context->msgBuf ) ForgetMem( &context->msgPtr );
- free( context );
- dispatch_async_f( dispatch_get_main_queue(), NULL, Exit );
-}
-
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-//===========================================================================================================================
-// DNSCryptCmd
-//===========================================================================================================================
-
-#define kDNSCryptPort 443
-
-#define kDNSCryptMinPadLength 8
-#define kDNSCryptMaxPadLength 256
-#define kDNSCryptBlockSize 64
-#define kDNSCryptCertMinimumLength 124
-#define kDNSCryptClientMagicLength 8
-#define kDNSCryptResolverMagicLength 8
-#define kDNSCryptHalfNonceLength 12
-#define kDNSCryptCertMagicLength 4
-
-check_compile_time( ( kDNSCryptHalfNonceLength * 2 ) == crypto_box_NONCEBYTES );
-
-static const uint8_t kDNSCryptCertMagic[ kDNSCryptCertMagicLength ] = { 'D', 'N', 'S', 'C' };
-static const uint8_t kDNSCryptResolverMagic[ kDNSCryptResolverMagicLength ] =
-{
- 0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38
-};
-
-typedef struct
-{
- uint8_t certMagic[ kDNSCryptCertMagicLength ];
- uint8_t esVersion[ 2 ];
- uint8_t minorVersion[ 2 ];
- uint8_t signature[ crypto_sign_BYTES ];
- uint8_t publicKey[ crypto_box_PUBLICKEYBYTES ];
- uint8_t clientMagic[ kDNSCryptClientMagicLength ];
- uint8_t serial[ 4 ];
- uint8_t startTime[ 4 ];
- uint8_t endTime[ 4 ];
- uint8_t extensions[ 1 ]; // Variably-sized extension data.
-
-} DNSCryptCert;
-
-check_compile_time( offsetof( DNSCryptCert, extensions ) == kDNSCryptCertMinimumLength );
-
-typedef struct
-{
- uint8_t clientMagic[ kDNSCryptClientMagicLength ];
- uint8_t clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
- uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
- uint8_t poly1305MAC[ 16 ];
-
-} DNSCryptQueryHeader;
-
-check_compile_time( sizeof( DNSCryptQueryHeader ) == 68 );
-check_compile_time( sizeof( DNSCryptQueryHeader ) >= crypto_box_ZEROBYTES );
-check_compile_time( ( sizeof( DNSCryptQueryHeader ) - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES ) ==
- offsetof( DNSCryptQueryHeader, poly1305MAC ) );
-
-typedef struct
-{
- uint8_t resolverMagic[ kDNSCryptResolverMagicLength ];
- uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
- uint8_t resolverNonce[ kDNSCryptHalfNonceLength ];
- uint8_t poly1305MAC[ 16 ];
-
-} DNSCryptResponseHeader;
-
-check_compile_time( sizeof( DNSCryptResponseHeader ) == 48 );
-check_compile_time( offsetof( DNSCryptResponseHeader, poly1305MAC ) >= crypto_box_BOXZEROBYTES );
-check_compile_time( ( offsetof( DNSCryptResponseHeader, poly1305MAC ) - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES ) ==
- sizeof( DNSCryptResponseHeader ) );
-
-typedef struct
-{
- sockaddr_ip serverAddr;
- uint64_t sendTicks;
- const char * providerName;
- const char * qname;
- const uint8_t * certPtr;
- size_t certLen;
- dispatch_source_t readSource;
- size_t msgLen;
- int timeLimitSecs;
- uint16_t queryID;
- uint16_t qtype;
- Boolean printRawRData;
- uint8_t serverPublicSignKey[ crypto_sign_PUBLICKEYBYTES ];
- uint8_t serverPublicKey[ crypto_box_PUBLICKEYBYTES ];
- uint8_t clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
- uint8_t clientSecretKey[ crypto_box_SECRETKEYBYTES ];
- uint8_t clientMagic[ kDNSCryptClientMagicLength ];
- uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
- uint8_t nmKey[ crypto_box_BEFORENMBYTES ];
- uint8_t msgBuf[ 512 ];
-
-} DNSCryptContext;
-
-static void DNSCryptReceiveCertHandler( void *inContext );
-static void DNSCryptReceiveResponseHandler( void *inContext );
-static void DNSCryptProceed( void *inContext );
-static OSStatus DNSCryptProcessCert( DNSCryptContext *inContext );
-static OSStatus DNSCryptBuildQuery( DNSCryptContext *inContext );
-static OSStatus DNSCryptSendQuery( DNSCryptContext *inContext );
-static void DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen );
-
-static void DNSCryptCmd( void )
-{
- OSStatus err;
- DNSCryptContext * context = NULL;
- size_t writtenBytes;
- size_t totalBytes;
- SocketContext * sockCtx;
- SocketRef sock = kInvalidSocketRef;
- const char * ptr;
-
- // Check command parameters.
-
- if( gDNSCrypt_TimeLimitSecs < -1 )
- {
- FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSCrypt_TimeLimitSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create context.
-
- context = (DNSCryptContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->providerName = gDNSCrypt_ProviderName;
- context->qname = gDNSCrypt_Name;
- context->timeLimitSecs = gDNSCrypt_TimeLimitSecs;
- context->printRawRData = gDNSCrypt_RawRData ? true : false;
-
- err = crypto_box_keypair( context->clientPublicKey, context->clientSecretKey );
- require_noerr( err, exit );
-
- err = HexToData( gDNSCrypt_ProviderKey, kSizeCString, kHexToData_DefaultFlags,
- context->serverPublicSignKey, sizeof( context->serverPublicSignKey ), &writtenBytes, &totalBytes, &ptr );
- if( err || ( *ptr != '\0' ) )
- {
- FPrintF( stderr, "Failed to parse public signing key hex string (%s).\n", gDNSCrypt_ProviderKey );
- goto exit;
- }
- else if( totalBytes != sizeof( context->serverPublicSignKey ) )
- {
- FPrintF( stderr, "Public signing key contains incorrect number of hex bytes (%zu != %zu)\n",
- totalBytes, sizeof( context->serverPublicSignKey ) );
- err = kSizeErr;
- goto exit;
- }
- check( writtenBytes == totalBytes );
-
- err = StringToSockAddr( gDNSCrypt_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
- require_noerr( err, exit );
- if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSCryptPort );
-
- err = RecordTypeFromArgString( gDNSCrypt_Type, &context->qtype );
- require_noerr( err, exit );
-
- // Write query message.
-
- context->queryID = (uint16_t) Random32();
- err = WriteDNSQueryMessage( context->msgBuf, context->queryID, kDNSHeaderFlag_RecursionDesired, context->providerName,
- kDNSServiceType_TXT, kDNSServiceClass_IN, &context->msgLen );
- require_noerr( err, exit );
-
- // Create UDP socket.
-
- err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &sock );
- require_noerr( err, exit );
-
- // Send DNS query.
-
- context->sendTicks = UpTicks();
- err = SocketWriteAll( sock, context->msgBuf, context->msgLen, 5 );
- require_noerr( err, exit );
-
- err = SocketContextCreate( sock, context, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveCertHandler, SocketContextCancelHandler, sockCtx,
- &context->readSource );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSource );
-
- if( context->timeLimitSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
- Exit );
- }
- dispatch_main();
-
-exit:
- if( context ) free( context );
- ForgetSocket( &sock );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// DNSCryptReceiveCertHandler
-//===========================================================================================================================
-
-static void DNSCryptReceiveCertHandler( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- const uint64_t nowTicks = UpTicks();
- SocketContext * const sockCtx = (SocketContext *) inContext;
- DNSCryptContext * const context = (DNSCryptContext *) sockCtx->userContext;
- const DNSHeader * hdr;
- sockaddr_ip fromAddr;
- const uint8_t * ptr;
- const uint8_t * txtPtr;
- size_t txtLen;
- unsigned int answerCount, i;
- uint8_t targetName[ kDomainNameLengthMax ];
-
- gettimeofday( &now, NULL );
-
- dispatch_source_forget( &context->readSource );
-
- err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
- &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
- check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
-
- FPrintF( stdout, "Receive time: %{du:time}\n", &now );
- FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
- FPrintF( stdout, "Message size: %zu\n", context->msgLen );
- FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
- FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgBuf, context->msgLen );
-
- require_action_quiet( context->msgLen >= kDNSHeaderLength, exit, err = kSizeErr );
-
- hdr = (DNSHeader *) context->msgBuf;
- require_action_quiet( DNSHeaderGetID( hdr ) == context->queryID, exit, err = kMismatchErr );
-
- err = DNSMessageGetAnswerSection( context->msgBuf, context->msgLen, &ptr );
- require_noerr( err, exit );
-
- err = DomainNameFromString( targetName, context->providerName, NULL );
- require_noerr( err, exit );
-
- answerCount = DNSHeaderGetAnswerCount( hdr );
- for( i = 0; i < answerCount; ++i )
- {
- uint16_t type;
- uint16_t class;
- uint8_t name[ kDomainNameLengthMax ];
-
- err = DNSMessageExtractRecord( context->msgBuf, context->msgLen, ptr, name, &type, &class, NULL, &txtPtr, &txtLen,
- &ptr );
- require_noerr( err, exit );
-
- if( ( type == kDNSServiceType_TXT ) && ( class == kDNSServiceClass_IN ) && DomainNameEqual( name, targetName ) )
- {
- break;
- }
- }
-
- if( txtLen < ( 1 + kDNSCryptCertMinimumLength ) )
- {
- FPrintF( stderr, "TXT record length is too short (%u < %u)\n", txtLen, kDNSCryptCertMinimumLength + 1 );
- err = kSizeErr;
- goto exit;
- }
- if( txtPtr[ 0 ] < kDNSCryptCertMinimumLength )
- {
- FPrintF( stderr, "TXT record value length is too short (%u < %u)\n", txtPtr[ 0 ], kDNSCryptCertMinimumLength );
- err = kSizeErr;
- goto exit;
- }
-
- context->certLen = txtPtr[ 0 ];
- context->certPtr = &txtPtr[ 1 ];
-
- dispatch_async_f( dispatch_get_main_queue(), context, DNSCryptProceed );
-
-exit:
- if( err ) Exit( NULL );
-}
-
-//===========================================================================================================================
-// DNSCryptReceiveResponseHandler
-//===========================================================================================================================
-
-static void DNSCryptReceiveResponseHandler( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- const uint64_t nowTicks = UpTicks();
- SocketContext * const sockCtx = (SocketContext *) inContext;
- DNSCryptContext * const context = (DNSCryptContext *) sockCtx->userContext;
- sockaddr_ip fromAddr;
- DNSCryptResponseHeader * hdr;
- const uint8_t * end;
- uint8_t * ciphertext;
- uint8_t * plaintext;
- const uint8_t * response;
- uint8_t nonce[ crypto_box_NONCEBYTES ];
-
- gettimeofday( &now, NULL );
-
- dispatch_source_forget( &context->readSource );
-
- err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
- &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
- check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
-
- FPrintF( stdout, "Receive time: %{du:time}\n", &now );
- FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
- FPrintF( stdout, "Message size: %zu\n", context->msgLen );
- FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
-
- if( context->msgLen < sizeof( DNSCryptResponseHeader ) )
- {
- FPrintF( stderr, "DNSCrypt response is too short.\n" );
- err = kSizeErr;
- goto exit;
- }
-
- hdr = (DNSCryptResponseHeader *) context->msgBuf;
-
- if( memcmp( hdr->resolverMagic, kDNSCryptResolverMagic, kDNSCryptResolverMagicLength ) != 0 )
- {
- FPrintF( stderr, "DNSCrypt response resolver magic %#H != %#H\n",
- hdr->resolverMagic, kDNSCryptResolverMagicLength, INT_MAX,
- kDNSCryptResolverMagic, kDNSCryptResolverMagicLength, INT_MAX );
- err = kValueErr;
- goto exit;
- }
-
- if( memcmp( hdr->clientNonce, context->clientNonce, kDNSCryptHalfNonceLength ) != 0 )
- {
- FPrintF( stderr, "DNSCrypt response client nonce mismatch.\n" );
- err = kValueErr;
- goto exit;
- }
-
- memcpy( nonce, hdr->clientNonce, crypto_box_NONCEBYTES );
-
- ciphertext = hdr->poly1305MAC - crypto_box_BOXZEROBYTES;
- memset( ciphertext, 0, crypto_box_BOXZEROBYTES );
-
- plaintext = (uint8_t *)( hdr + 1 ) - crypto_box_ZEROBYTES;
- check( plaintext == ciphertext );
-
- end = context->msgBuf + context->msgLen;
-
- err = crypto_box_open_afternm( plaintext, ciphertext, (size_t)( end - ciphertext ), nonce, context->nmKey );
- require_noerr( err, exit );
-
- response = plaintext + crypto_box_ZEROBYTES;
- FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, response, (size_t)( end - response ) );
- Exit( kExitReason_ReceivedResponse );
-
-exit:
- if( err ) Exit( NULL );
-}
-
-//===========================================================================================================================
-// DNSCryptProceed
-//===========================================================================================================================
-
-static void DNSCryptProceed( void *inContext )
-{
- OSStatus err;
- DNSCryptContext * const context = (DNSCryptContext *) inContext;
-
- err = DNSCryptProcessCert( context );
- require_noerr_quiet( err, exit );
-
- err = DNSCryptBuildQuery( context );
- require_noerr_quiet( err, exit );
-
- err = DNSCryptSendQuery( context );
- require_noerr_quiet( err, exit );
-
-exit:
- if( err ) Exit( NULL );
-}
-
-//===========================================================================================================================
-// DNSCryptProcessCert
-//===========================================================================================================================
-
-static OSStatus DNSCryptProcessCert( DNSCryptContext *inContext )
-{
- OSStatus err;
- const DNSCryptCert * const cert = (DNSCryptCert *) inContext->certPtr;
- const uint8_t * const certEnd = inContext->certPtr + inContext->certLen;
- struct timeval now;
- time_t startTimeSecs, endTimeSecs;
- size_t signedLen;
- uint8_t * tempBuf;
- unsigned long long tempLen;
-
- DNSCryptPrintCertificate( cert, inContext->certLen );
-
- if( memcmp( cert->certMagic, kDNSCryptCertMagic, kDNSCryptCertMagicLength ) != 0 )
- {
- FPrintF( stderr, "DNSCrypt certificate magic %#H != %#H\n",
- cert->certMagic, kDNSCryptCertMagicLength, INT_MAX,
- kDNSCryptCertMagic, kDNSCryptCertMagicLength, INT_MAX );
- err = kValueErr;
- goto exit;
- }
-
- startTimeSecs = (time_t) ReadBig32( cert->startTime );
- endTimeSecs = (time_t) ReadBig32( cert->endTime );
-
- gettimeofday( &now, NULL );
- if( now.tv_sec < startTimeSecs )
- {
- FPrintF( stderr, "DNSCrypt certificate start time is in the future.\n" );
- err = kDateErr;
- goto exit;
- }
- if( now.tv_sec >= endTimeSecs )
- {
- FPrintF( stderr, "DNSCrypt certificate has expired.\n" );
- err = kDateErr;
- goto exit;
- }
-
- signedLen = (size_t)( certEnd - cert->signature );
- tempBuf = (uint8_t *) malloc( signedLen );
- require_action( tempBuf, exit, err = kNoMemoryErr );
- err = crypto_sign_open( tempBuf, &tempLen, cert->signature, signedLen, inContext->serverPublicSignKey );
- free( tempBuf );
- if( err )
- {
- FPrintF( stderr, "DNSCrypt certificate failed verification.\n" );
- err = kAuthenticationErr;
- goto exit;
- }
-
- memcpy( inContext->serverPublicKey, cert->publicKey, crypto_box_PUBLICKEYBYTES );
- memcpy( inContext->clientMagic, cert->clientMagic, kDNSCryptClientMagicLength );
-
- err = crypto_box_beforenm( inContext->nmKey, inContext->serverPublicKey, inContext->clientSecretKey );
- require_noerr( err, exit );
-
- inContext->certPtr = NULL;
- inContext->certLen = 0;
- inContext->msgLen = 0;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSCryptBuildQuery
-//===========================================================================================================================
-
-static OSStatus DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen );
-
-static OSStatus DNSCryptBuildQuery( DNSCryptContext *inContext )
-{
- OSStatus err;
- DNSCryptQueryHeader * const hdr = (DNSCryptQueryHeader *) inContext->msgBuf;
- uint8_t * const queryPtr = (uint8_t *)( hdr + 1 );
- size_t queryLen;
- size_t paddedQueryLen;
- const uint8_t * const msgLimit = inContext->msgBuf + sizeof( inContext->msgBuf );
- const uint8_t * padLimit;
- uint8_t nonce[ crypto_box_NONCEBYTES ];
-
- check_compile_time_code( sizeof( inContext->msgBuf ) >= ( sizeof( DNSCryptQueryHeader ) + kDNSQueryMessageMaxLen ) );
-
- inContext->queryID = (uint16_t) Random32();
- err = WriteDNSQueryMessage( queryPtr, inContext->queryID, kDNSHeaderFlag_RecursionDesired, inContext->qname,
- inContext->qtype, kDNSServiceClass_IN, &queryLen );
- require_noerr( err, exit );
-
- padLimit = &queryPtr[ queryLen + kDNSCryptMaxPadLength ];
- if( padLimit > msgLimit ) padLimit = msgLimit;
-
- err = DNSCryptPadQuery( queryPtr, queryLen, (size_t)( padLimit - queryPtr ), &paddedQueryLen );
- require_noerr( err, exit );
-
- memset( queryPtr - crypto_box_ZEROBYTES, 0, crypto_box_ZEROBYTES );
- RandomBytes( inContext->clientNonce, kDNSCryptHalfNonceLength );
- memcpy( nonce, inContext->clientNonce, kDNSCryptHalfNonceLength );
- memset( &nonce[ kDNSCryptHalfNonceLength ], 0, kDNSCryptHalfNonceLength );
-
- err = crypto_box_afternm( queryPtr - crypto_box_ZEROBYTES, queryPtr - crypto_box_ZEROBYTES,
- paddedQueryLen + crypto_box_ZEROBYTES, nonce, inContext->nmKey );
- require_noerr( err, exit );
-
- memcpy( hdr->clientMagic, inContext->clientMagic, kDNSCryptClientMagicLength );
- memcpy( hdr->clientPublicKey, inContext->clientPublicKey, crypto_box_PUBLICKEYBYTES );
- memcpy( hdr->clientNonce, nonce, kDNSCryptHalfNonceLength );
-
- inContext->msgLen = (size_t)( &queryPtr[ paddedQueryLen ] - inContext->msgBuf );
-
-exit:
- return( err );
-}
-
-static OSStatus DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen )
-{
- OSStatus err;
- size_t paddedLen;
-
- require_action_quiet( ( inMsgLen + kDNSCryptMinPadLength ) <= inMaxLen, exit, err = kSizeErr );
-
- paddedLen = inMsgLen + kDNSCryptMinPadLength +
- arc4random_uniform( (uint32_t)( inMaxLen - ( inMsgLen + kDNSCryptMinPadLength ) + 1 ) );
- paddedLen += ( kDNSCryptBlockSize - ( paddedLen % kDNSCryptBlockSize ) );
- if( paddedLen > inMaxLen ) paddedLen = inMaxLen;
-
- inMsgPtr[ inMsgLen ] = 0x80;
- memset( &inMsgPtr[ inMsgLen + 1 ], 0, paddedLen - ( inMsgLen + 1 ) );
-
- if( outPaddedLen ) *outPaddedLen = paddedLen;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSCryptSendQuery
-//===========================================================================================================================
-
-static OSStatus DNSCryptSendQuery( DNSCryptContext *inContext )
-{
- OSStatus err;
- SocketContext * sockCtx;
- SocketRef sock = kInvalidSocketRef;
-
- check( inContext->msgLen > 0 );
- check( !inContext->readSource );
-
- err = UDPClientSocketOpen( AF_UNSPEC, &inContext->serverAddr, 0, -1, NULL, &sock );
- require_noerr( err, exit );
-
- inContext->sendTicks = UpTicks();
- err = SocketWriteAll( sock, inContext->msgBuf, inContext->msgLen, 5 );
- require_noerr( err, exit );
-
- err = SocketContextCreate( sock, inContext, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveResponseHandler, SocketContextCancelHandler, sockCtx,
- &inContext->readSource );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( inContext->readSource );
-
-exit:
- ForgetSocket( &sock );
- return( err );
-}
-
-//===========================================================================================================================
-// DNSCryptPrintCertificate
-//===========================================================================================================================
-
-#define kCertTimeStrBufLen 32
-
-static char * CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] );
-
-static void DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen )
-{
- time_t startTime, endTime;
- int extLen;
- char timeBuf[ kCertTimeStrBufLen ];
-
- check( inLen >= kDNSCryptCertMinimumLength );
-
- startTime = (time_t) ReadBig32( inCert->startTime );
- endTime = (time_t) ReadBig32( inCert->endTime );
-
- FPrintF( stdout, "DNSCrypt certificate (%zu bytes):\n", inLen );
- FPrintF( stdout, "Cert Magic: %#H\n", inCert->certMagic, kDNSCryptCertMagicLength, INT_MAX );
- FPrintF( stdout, "ES Version: %u\n", ReadBig16( inCert->esVersion ) );
- FPrintF( stdout, "Minor Version: %u\n", ReadBig16( inCert->minorVersion ) );
- FPrintF( stdout, "Signature: %H\n", inCert->signature, crypto_sign_BYTES / 2, INT_MAX );
- FPrintF( stdout, " %H\n", &inCert->signature[ crypto_sign_BYTES / 2 ], crypto_sign_BYTES / 2, INT_MAX );
- FPrintF( stdout, "Public Key: %H\n", inCert->publicKey, sizeof( inCert->publicKey ), INT_MAX );
- FPrintF( stdout, "Client Magic: %H\n", inCert->clientMagic, kDNSCryptClientMagicLength, INT_MAX );
- FPrintF( stdout, "Serial: %u\n", ReadBig32( inCert->serial ) );
- FPrintF( stdout, "Start Time: %u (%s)\n", (uint32_t) startTime, CertTimeStr( startTime, timeBuf ) );
- FPrintF( stdout, "End Time: %u (%s)\n", (uint32_t) endTime, CertTimeStr( endTime, timeBuf ) );
-
- if( inLen > kDNSCryptCertMinimumLength )
- {
- extLen = (int)( inLen - kDNSCryptCertMinimumLength );
- FPrintF( stdout, "Extensions: %.1H\n", inCert->extensions, extLen, extLen );
- }
- FPrintF( stdout, "\n" );
-}
-
-static char * CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] )
-{
- struct tm * tm;
-
- tm = localtime( &inTime );
- if( !tm )
- {
- dlogassert( "localtime() returned a NULL pointer.\n" );
- *inBuffer = '\0';
- }
- else
- {
- strftime( inBuffer, kCertTimeStrBufLen, "%a %b %d %H:%M:%S %Z %Y", tm );
- }
-
- return( inBuffer );
-}
-
-#endif // DNSSDUTIL_INCLUDE_DNSCRYPT
-
-//===========================================================================================================================
-// MDNSQueryCmd
-//===========================================================================================================================
-
-typedef struct
-{
- const char * qnameStr; // Name (QNAME) of the record being queried as a C string.
- dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
- dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
- int localPort; // The port number to which the sockets are bound.
- int receiveSecs; // After send, the amount of time to spend receiving.
- uint32_t ifIndex; // Index of the interface over which to send the query.
- uint16_t qtype; // The type (QTYPE) of the record being queried.
- Boolean isQU; // True if the query is QU, i.e., requests unicast responses.
- Boolean allResponses; // True if all mDNS messages received should be printed.
- Boolean printRawRData; // True if RDATA should be printed as hexdumps.
- Boolean useIPv4; // True if the query should be sent via IPv4 multicast.
- Boolean useIPv6; // True if the query should be sent via IPv6 multicast.
- char ifName[ IF_NAMESIZE + 1 ]; // Name of the interface over which to send the query.
- uint8_t qname[ kDomainNameLengthMax ]; // Buffer to hold the QNAME in DNS label format.
- uint8_t msgBuf[ kMDNSMessageSizeMax ]; // mDNS message buffer.
-
-} MDNSQueryContext;
-
-static void MDNSQueryPrintPrologue( const MDNSQueryContext *inContext );
-static void MDNSQueryReadHandler( void *inContext );
-
-static void MDNSQueryCmd( void )
-{
- OSStatus err;
- MDNSQueryContext * context;
- SocketRef sockV4 = kInvalidSocketRef;
- SocketRef sockV6 = kInvalidSocketRef;
- ssize_t n;
- const char * ifname;
- size_t msgLen;
- unsigned int sendCount;
-
- // Check command parameters.
-
- if( gMDNSQuery_ReceiveSecs < -1 )
- {
- FPrintF( stdout, "Invalid receive time value: %d seconds.\n", gMDNSQuery_ReceiveSecs );
- err = kParamErr;
- goto exit;
- }
-
- context = (MDNSQueryContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->qnameStr = gMDNSQuery_Name;
- context->receiveSecs = gMDNSQuery_ReceiveSecs;
- context->isQU = gMDNSQuery_IsQU ? true : false;
- context->allResponses = gMDNSQuery_AllResponses ? true : false;
- context->printRawRData = gMDNSQuery_RawRData ? true : false;
- context->useIPv4 = ( gMDNSQuery_UseIPv4 || !gMDNSQuery_UseIPv6 ) ? true : false;
- context->useIPv6 = ( gMDNSQuery_UseIPv6 || !gMDNSQuery_UseIPv4 ) ? true : false;
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- ifname = if_indextoname( context->ifIndex, context->ifName );
- require_action( ifname, exit, err = kNameErr );
-
- err = RecordTypeFromArgString( gMDNSQuery_Type, &context->qtype );
- require_noerr( err, exit );
-
- // Set up IPv4 socket.
-
- if( context->useIPv4 )
- {
- err = CreateMulticastSocket( GetMDNSMulticastAddrV4(),
- gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
- ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV4 );
- require_noerr( err, exit );
- }
-
- // Set up IPv6 socket.
-
- if( context->useIPv6 )
- {
- err = CreateMulticastSocket( GetMDNSMulticastAddrV6(),
- gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
- ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV6 );
- require_noerr( err, exit );
- }
-
- // Craft mDNS query message.
-
- check_compile_time_code( sizeof( context->msgBuf ) >= kDNSQueryMessageMaxLen );
- err = WriteDNSQueryMessage( context->msgBuf, kDefaultMDNSMessageID, kDefaultMDNSQueryFlags, context->qnameStr,
- context->qtype, context->isQU ? ( kDNSServiceClass_IN | kQClassUnicastResponseBit ) : kDNSServiceClass_IN, &msgLen );
- require_noerr( err, exit );
-
- // Print prologue.
-
- MDNSQueryPrintPrologue( context );
-
- // Send mDNS query message.
-
- sendCount = 0;
- if( IsValidSocket( sockV4 ) )
- {
- const struct sockaddr * const mcastAddr4 = GetMDNSMulticastAddrV4();
-
- n = sendto( sockV4, context->msgBuf, msgLen, 0, mcastAddr4, SockAddrGetSize( mcastAddr4 ) );
- err = map_socket_value_errno( sockV4, n == (ssize_t) msgLen, n );
- if( err )
- {
- FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
- ForgetSocket( &sockV4 );
- }
- else
- {
- ++sendCount;
- }
- }
- if( IsValidSocket( sockV6 ) )
- {
- const struct sockaddr * const mcastAddr6 = GetMDNSMulticastAddrV6();
-
- n = sendto( sockV6, context->msgBuf, msgLen, 0, mcastAddr6, SockAddrGetSize( mcastAddr6 ) );
- err = map_socket_value_errno( sockV6, n == (ssize_t) msgLen, n );
- if( err )
- {
- FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
- ForgetSocket( &sockV6 );
- }
- else
- {
- ++sendCount;
- }
- }
- require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
-
- // If there's no wait period after the send, then exit.
-
- if( context->receiveSecs == 0 ) goto exit;
-
- // Create dispatch read sources for socket(s).
-
- if( IsValidSocket( sockV4 ) )
- {
- SocketContext * sockCtx;
-
- err = SocketContextCreate( sockV4, context, &sockCtx );
- require_noerr( err, exit );
- sockV4 = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
- &context->readSourceV4 );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSourceV4 );
- }
-
- if( IsValidSocket( sockV6 ) )
- {
- SocketContext * sockCtx;
-
- err = SocketContextCreate( sockV6, context, &sockCtx );
- require_noerr( err, exit );
- sockV6 = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
- &context->readSourceV6 );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSourceV6 );
- }
-
- if( context->receiveSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
- Exit );
- }
- dispatch_main();
-
-exit:
- ForgetSocket( &sockV4 );
- ForgetSocket( &sockV6 );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// MDNSColliderCmd
-//===========================================================================================================================
-
-static void _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError );
-
-static void MDNSColliderCmd( void )
-{
- OSStatus err;
- MDNSColliderRef collider = NULL;
- uint8_t * rdataPtr = NULL;
- size_t rdataLen = 0;
- const char * ifname;
- uint32_t ifIndex;
- MDNSColliderProtocols protocols;
- uint16_t type;
- char ifName[ IF_NAMESIZE + 1 ];
- uint8_t name[ kDomainNameLengthMax ];
-
- err = InterfaceIndexFromArgString( gInterface, &ifIndex );
- require_noerr_quiet( err, exit );
-
- ifname = if_indextoname( ifIndex, ifName );
- if( !ifname )
- {
- FPrintF( stderr, "error: Invalid interface name or index: %s\n", gInterface );
- err = kNameErr;
- goto exit;
- }
-
- err = DomainNameFromString( name, gMDNSCollider_Name, NULL );
- if( err )
- {
- FPrintF( stderr, "error: Invalid record name: %s\n", gMDNSCollider_Name );
- goto exit;
- }
-
- err = RecordTypeFromArgString( gMDNSCollider_Type, &type );
- require_noerr_quiet( err, exit );
-
- if( gMDNSCollider_RecordData )
- {
- err = RecordDataFromArgString( gMDNSCollider_RecordData, &rdataPtr, &rdataLen );
- require_noerr_quiet( err, exit );
- }
-
- err = MDNSColliderCreate( dispatch_get_main_queue(), &collider );
- require_noerr( err, exit );
-
- err = MDNSColliderSetProgram( collider, gMDNSCollider_Program );
- if( err )
- {
- FPrintF( stderr, "error: Failed to set program string: '%s'\n", gMDNSCollider_Program );
- goto exit;
- }
-
- err = MDNSColliderSetRecord( collider, name, type, rdataPtr, rdataLen );
- require_noerr( err, exit );
- ForgetMem( &rdataPtr );
-
- protocols = kMDNSColliderProtocol_None;
- if( gMDNSCollider_UseIPv4 || !gMDNSCollider_UseIPv6 ) protocols |= kMDNSColliderProtocol_IPv4;
- if( gMDNSCollider_UseIPv6 || !gMDNSCollider_UseIPv4 ) protocols |= kMDNSColliderProtocol_IPv6;
- MDNSColliderSetProtocols( collider, protocols );
- MDNSColliderSetInterfaceIndex( collider, ifIndex );
- MDNSColliderSetStopHandler( collider, _MDNSColliderCmdStopHandler, collider );
-
- err = MDNSColliderStart( collider );
- require_noerr( err, exit );
-
- dispatch_main();
-
-exit:
- FreeNullSafe( rdataPtr );
- CFReleaseNullSafe( collider );
- if( err ) exit( 1 );
-}
-
-static void _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError )
-{
- MDNSColliderRef const collider = (MDNSColliderRef) inContext;
-
- CFRelease( collider );
- exit( inError ? 1 : 0 );
-}
-
-//===========================================================================================================================
-// MDNSQueryPrintPrologue
-//===========================================================================================================================
-
-static void MDNSQueryPrintPrologue( const MDNSQueryContext *inContext )
-{
- const int receiveSecs = inContext->receiveSecs;
-
- FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, inContext->ifName );
- FPrintF( stdout, "Name: %s\n", inContext->qnameStr );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->qtype ), inContext->qtype );
- FPrintF( stdout, "Class: IN (%s)\n", inContext->isQU ? "QU" : "QM" );
- FPrintF( stdout, "Local port: %d\n", inContext->localPort );
- FPrintF( stdout, "IP protocols: %?s%?s%?s\n",
- inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
- FPrintF( stdout, "Receive duration: " );
- if( receiveSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
-}
-
-//===========================================================================================================================
-// MDNSQueryReadHandler
-//===========================================================================================================================
-
-static void MDNSQueryReadHandler( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- MDNSQueryContext * const context = (MDNSQueryContext *) sockCtx->userContext;
- size_t msgLen;
- sockaddr_ip fromAddr;
- Boolean foundAnswer = false;
-
- gettimeofday( &now, NULL );
-
- err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &fromAddr,
- sizeof( fromAddr ), NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- if( !context->allResponses && ( msgLen >= kDNSHeaderLength ) )
- {
- const uint8_t * ptr;
- const DNSHeader * const hdr = (DNSHeader *) context->msgBuf;
- unsigned int rrCount, i;
- uint16_t type, class;
- uint8_t name[ kDomainNameLengthMax ];
-
- err = DNSMessageGetAnswerSection( context->msgBuf, msgLen, &ptr );
- require_noerr( err, exit );
-
- if( context->qname[ 0 ] == 0 )
- {
- err = DomainNameAppendString( context->qname, context->qnameStr, NULL );
- require_noerr( err, exit );
- }
-
- rrCount = DNSHeaderGetAnswerCount( hdr ) + DNSHeaderGetAuthorityCount( hdr ) + DNSHeaderGetAdditionalCount( hdr );
- for( i = 0; i < rrCount; ++i )
- {
- err = DNSMessageExtractRecord( context->msgBuf, msgLen, ptr, name, &type, &class, NULL, NULL, NULL, &ptr );
- require_noerr( err, exit );
-
- if( ( ( context->qtype == kDNSServiceType_ANY ) || ( type == context->qtype ) ) &&
- DomainNameEqual( name, context->qname ) )
- {
- foundAnswer = true;
- break;
- }
- }
- }
- if( context->allResponses || foundAnswer )
- {
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "Receive time: %{du:time}\n", &now );
- FPrintF( stdout, "Source: %##a\n", &fromAddr );
- FPrintF( stdout, "Message size: %zu\n\n%#.*{du:dnsmsg}",
- msgLen, context->printRawRData ? 1 : 0, context->msgBuf, msgLen );
- }
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// PIDToUUIDCmd
-//===========================================================================================================================
-
-static void PIDToUUIDCmd( void )
-{
- OSStatus err;
- int n;
- struct proc_uniqidentifierinfo info;
-
- n = proc_pidinfo( gPIDToUUID_PID, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof( info ) );
- require_action_quiet( n == (int) sizeof( info ), exit, err = kUnknownErr );
-
- FPrintF( stdout, "%#U\n", info.p_uuid );
- err = kNoErr;
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// DNSServerCmd
-//===========================================================================================================================
-
-typedef struct DNSServerPrivate * DNSServerRef;
-
-typedef struct
-{
- DNSServerRef server; // Reference to the DNS server.
- dispatch_source_t sigIntSource; // Dispatch SIGINT source.
- dispatch_source_t sigTermSource; // Dispatch SIGTERM source.
- const char * domainOverride; // If non-NULL, the server is to use this domain instead of "d.test.".
-#if( TARGET_OS_DARWIN )
- dispatch_source_t processMonitor; // Process monitor source for process being followed, if any.
- pid_t followPID; // PID of process being followed, if any. (If it exits, we exit).
- Boolean addedResolver; // True if system DNS settings contains a resolver entry for server.
-#endif
- Boolean loopbackOnly; // True if the server should be bound to the loopback interface.
-
-} DNSServerCmdContext;
-
-typedef enum
-{
- kDNSServerEvent_Started = 1,
- kDNSServerEvent_Stopped = 2
-
-} DNSServerEventType;
-
-typedef void ( *DNSServerEventHandler_f )( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
-
-CFTypeID DNSServerGetTypeID( void );
-static OSStatus
- DNSServerCreate(
- dispatch_queue_t inQueue,
- DNSServerEventHandler_f inEventHandler,
- void * inEventContext,
- unsigned int inResponseDelayMs,
- uint32_t inDefaultTTL,
- int inPort,
- Boolean inLoopbackOnly,
- const char * inDomain,
- Boolean inBadUDPMode,
- DNSServerRef * outServer );
-static void DNSServerStart( DNSServerRef inServer );
-static void DNSServerStop( DNSServerRef inServer );
-
-#define ForgetDNSServer( X ) ForgetCustomEx( X, DNSServerStop, CFRelease )
-
-static void DNSServerCmdContextFree( DNSServerCmdContext *inContext );
-static void DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
-static void DNSServerCmdSigIntHandler( void *inContext );
-static void DNSServerCmdSigTermHandler( void *inContext );
-#if( TARGET_OS_DARWIN )
-static void DNSServerCmdFollowedProcessHandler( void *inContext );
-#endif
-
-ulog_define_ex( "com.apple.dnssdutil", DNSServer, kLogLevelInfo, kLogFlags_None, "DNSServer", NULL );
-#define ds_ulog( LEVEL, ... ) ulog( &log_category_from_name( DNSServer ), (LEVEL), __VA_ARGS__ )
-
-static void DNSServerCmd( void )
-{
- OSStatus err;
- DNSServerCmdContext * context = NULL;
-
- if( gDNSServer_Foreground )
- {
- LogControl( "DNSServer:output=file;stdout,DNSServer:flags=time;prefix" );
- }
-
- err = CheckIntegerArgument( gDNSServer_ResponseDelayMs, "response delay (ms)", 0, INT_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gDNSServer_DefaultTTL, "default TTL", 0, INT32_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gDNSServer_Port, "port number", -UINT16_MAX, UINT16_MAX );
- require_noerr_quiet( err, exit );
-
- context = (DNSServerCmdContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->domainOverride = gDNSServer_DomainOverride;
- context->loopbackOnly = gDNSServer_LoopbackOnly ? true : false;
-
-#if( TARGET_OS_DARWIN )
- if( gDNSServer_FollowPID )
- {
- err = StringToPID( gDNSServer_FollowPID, &context->followPID );
- if( err || ( context->followPID < 0 ) )
- {
- FPrintF( stderr, "error: Invalid follow PID: %s\n", gDNSServer_FollowPID );
- err = kParamErr;
- goto exit;
- }
-
- err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
- DNSServerCmdFollowedProcessHandler, NULL, context, &context->processMonitor );
- require_noerr( err, exit );
- dispatch_resume( context->processMonitor );
- }
- else
- {
- context->followPID = -1;
- }
-#endif
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, DNSServerCmdSigIntHandler, context, &context->sigIntSource );
- require_noerr( err, exit );
- dispatch_resume( context->sigIntSource );
-
- signal( SIGTERM, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGTERM, DNSServerCmdSigTermHandler, context, &context->sigTermSource );
- require_noerr( err, exit );
- dispatch_resume( context->sigTermSource );
-
- err = DNSServerCreate( dispatch_get_main_queue(), DNSServerCmdEventHandler, context,
- (unsigned int) gDNSServer_ResponseDelayMs, (uint32_t) gDNSServer_DefaultTTL, gDNSServer_Port, context->loopbackOnly,
- context->domainOverride, gDNSServer_BadUDPMode ? true : false, &context->server );
- require_noerr( err, exit );
-
- DNSServerStart( context->server );
- dispatch_main();
-
-exit:
- FPrintF( stderr, "Failed to start DNS server: %#m\n", err );
- if( context ) DNSServerCmdContextFree( context );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// DNSServerCmdContextFree
-//===========================================================================================================================
-
-static void DNSServerCmdContextFree( DNSServerCmdContext *inContext )
-{
- ForgetCF( &inContext->server );
- dispatch_source_forget( &inContext->sigIntSource );
- dispatch_source_forget( &inContext->sigTermSource );
-#if( TARGET_OS_DARWIN )
- dispatch_source_forget( &inContext->processMonitor );
-#endif
- free( inContext );
-}
-
-//===========================================================================================================================
-// DNSServerCmdEventHandler
-//===========================================================================================================================
-
-#if( TARGET_OS_DARWIN )
-static OSStatus _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort );
-static OSStatus _DNSServerCmdLoopbackResolverRemove( void );
-#endif
-
-static void DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext )
-{
- OSStatus err;
- DNSServerCmdContext * const context = (DNSServerCmdContext *) inContext;
-
- if( inType == kDNSServerEvent_Started )
- {
- #if( TARGET_OS_DARWIN )
- const int port = (int) inEventData;
-
- err = _DNSServerCmdLoopbackResolverAdd( context->domainOverride ? context->domainOverride : "d.test.", port );
- if( err )
- {
- ds_ulog( kLogLevelError, "Failed to add loopback resolver to DNS configuration for \"d.test.\" domain: %#m\n",
- err );
- if( context->loopbackOnly ) ForgetDNSServer( &context->server );
- }
- else
- {
- context->addedResolver = true;
- }
- #endif
- }
- else if( inType == kDNSServerEvent_Stopped )
- {
- const OSStatus stopError = (OSStatus) inEventData;
-
- if( stopError ) ds_ulog( kLogLevelError, "The server stopped unexpectedly with error: %#m.\n", stopError );
-
- err = kNoErr;
- #if( TARGET_OS_DARWIN )
- if( context->addedResolver )
- {
- err = _DNSServerCmdLoopbackResolverRemove();
- if( err )
- {
- ds_ulog( kLogLevelError, "Failed to remove loopback resolver from DNS configuration: %#m\n", err );
- }
- else
- {
- context->addedResolver = false;
- }
- }
- else if( context->loopbackOnly )
- {
- err = kUnknownErr;
- }
- #endif
- DNSServerCmdContextFree( context );
- exit( ( stopError || err ) ? 1 : 0 );
- }
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// _DNSServerCmdLoopbackResolverAdd
-//===========================================================================================================================
-
-static OSStatus _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort )
-{
- OSStatus err;
- SCDynamicStoreRef store;
- CFPropertyListRef plist = NULL;
- CFStringRef key = NULL;
- const uint32_t loopbackV4 = htonl( INADDR_LOOPBACK );
- Boolean success;
-
- store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
- err = map_scerror( store );
- require_noerr( err, exit );
-
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
- "{"
- "%kO="
- "["
- "%s"
- "]"
- "%kO="
- "["
- "%.4a"
- "%.16a"
- "]"
- "%kO=%i"
- "}",
- kSCPropNetDNSSupplementalMatchDomains, inDomain,
- kSCPropNetDNSServerAddresses, &loopbackV4, in6addr_loopback.s6_addr,
- kSCPropNetDNSServerPort, inPort );
- require_noerr( err, exit );
-
- key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
- CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
- require_action( key, exit, err = kUnknownErr );
-
- success = SCDynamicStoreSetValue( store, key, plist );
- require_action( success, exit, err = kUnknownErr );
-
-exit:
- CFReleaseNullSafe( store );
- CFReleaseNullSafe( plist );
- CFReleaseNullSafe( key );
- return( err );
-}
-
-//===========================================================================================================================
-// _DNSServerCmdLoopbackResolverRemove
-//===========================================================================================================================
-
-static OSStatus _DNSServerCmdLoopbackResolverRemove( void )
-{
- OSStatus err;
- SCDynamicStoreRef store;
- CFStringRef key = NULL;
- Boolean success;
-
- store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
- err = map_scerror( store );
- require_noerr( err, exit );
-
- key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
- CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
- require_action( key, exit, err = kUnknownErr );
-
- success = SCDynamicStoreRemoveValue( store, key );
- require_action( success, exit, err = kUnknownErr );
-
-exit:
- CFReleaseNullSafe( store );
- CFReleaseNullSafe( key );
- return( err );
-}
-#endif
-
-//===========================================================================================================================
-// DNSServerCmdSigIntHandler
-//===========================================================================================================================
-
-static void _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal );
-
-static void DNSServerCmdSigIntHandler( void *inContext )
-{
- _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGINT );
-}
-
-//===========================================================================================================================
-// DNSServerCmdSigTermHandler
-//===========================================================================================================================
-
-static void DNSServerCmdSigTermHandler( void *inContext )
-{
- _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGTERM );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// DNSServerCmdFollowedProcessHandler
-//===========================================================================================================================
-
-static void DNSServerCmdFollowedProcessHandler( void *inContext )
-{
- DNSServerCmdContext * const context = (DNSServerCmdContext *) inContext;
-
- if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT ) _DNSServerCmdShutdown( context, 0 );
-}
-#endif
-
-//===========================================================================================================================
-// _DNSServerCmdExternalExit
-//===========================================================================================================================
-
-#define SignalNumberToString( X ) ( \
- ( (X) == SIGINT ) ? "SIGINT" : \
- ( (X) == SIGTERM ) ? "SIGTERM" : \
- "???" )
-
-static void _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal )
-{
- dispatch_source_forget( &inContext->sigIntSource );
- dispatch_source_forget( &inContext->sigTermSource );
-#if( TARGET_OS_DARWIN )
- dispatch_source_forget( &inContext->processMonitor );
-
- if( inSignal == 0 )
- {
- ds_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited\n", (int64_t) inContext->followPID );
- }
- else
-#endif
- {
- ds_ulog( kLogLevelNotice, "Exiting: received signal %d (%s)\n", inSignal, SignalNumberToString( inSignal ) );
- }
-
- ForgetDNSServer( &inContext->server );
-}
-
-//===========================================================================================================================
-// DNSServerCreate
-//===========================================================================================================================
-
-#define kDDotTestDomainName (const uint8_t *) "\x01" "d" "\x04" "test"
-
-typedef struct DNSDelayedResponse DNSDelayedResponse;
-struct DNSDelayedResponse
-{
- DNSDelayedResponse * next;
- sockaddr_ip destAddr;
- uint64_t targetTicks;
- uint8_t * msgPtr;
- size_t msgLen;
-};
-
-struct DNSServerPrivate
-{
- CFRuntimeBase base; // CF object base.
- uint8_t * domain; // Parent domain of server's resource records.
- dispatch_queue_t queue; // Queue for DNS server's events.
- dispatch_source_t readSourceUDPv4; // Read source for IPv4 UDP socket.
- dispatch_source_t readSourceUDPv6; // Read source for IPv6 UDP socket.
- dispatch_source_t readSourceTCPv4; // Read source for IPv4 TCP socket.
- dispatch_source_t readSourceTCPv6; // Read source for IPv6 TCP socket.
- SocketRef sockUDPv4;
- SocketRef sockUDPv6;
- DNSServerEventHandler_f eventHandler;
- void * eventContext;
- DNSDelayedResponse * responseList;
- dispatch_source_t responseTimer;
- unsigned int responseDelayMs;
- uint32_t defaultTTL;
- uint32_t serial; // Serial number for SOA record.
- int port; // Port to use for receiving and sending DNS messages.
- OSStatus stopError;
- Boolean stopped;
- Boolean loopbackOnly;
- Boolean badUDPMode; // True if the server runs in Bad UDP mode.
-};
-
-static void _DNSServerUDPReadHandler( void *inContext );
-static void _DNSServerTCPReadHandler( void *inContext );
-static void _DNSDelayedResponseFree( DNSDelayedResponse *inResponse );
-static void _DNSDelayedResponseFreeList( DNSDelayedResponse *inList );
-
-CF_CLASS_DEFINE( DNSServer );
-
-static OSStatus
- DNSServerCreate(
- dispatch_queue_t inQueue,
- DNSServerEventHandler_f inEventHandler,
- void * inEventContext,
- unsigned int inResponseDelayMs,
- uint32_t inDefaultTTL,
- int inPort,
- Boolean inLoopbackOnly,
- const char * inDomain,
- Boolean inBadUDPMode,
- DNSServerRef * outServer )
-{
- OSStatus err;
- DNSServerRef obj = NULL;
-
- require_action_quiet( inDefaultTTL <= INT32_MAX, exit, err = kRangeErr );
-
- CF_OBJECT_CREATE( DNSServer, obj, err, exit );
-
- ReplaceDispatchQueue( &obj->queue, inQueue );
- obj->eventHandler = inEventHandler;
- obj->eventContext = inEventContext;
- obj->responseDelayMs = inResponseDelayMs;
- obj->defaultTTL = inDefaultTTL;
- obj->port = inPort;
- obj->loopbackOnly = inLoopbackOnly;
- obj->badUDPMode = inBadUDPMode;
-
- if( inDomain )
- {
- err = StringToDomainName( inDomain, &obj->domain, NULL );
- require_noerr_quiet( err, exit );
- }
- else
- {
- err = DomainNameDup( kDDotTestDomainName, &obj->domain, NULL );
- require_noerr_quiet( err, exit );
- }
-
- *outServer = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- CFReleaseNullSafe( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _DNSServerFinalize
-//===========================================================================================================================
-
-static void _DNSServerFinalize( CFTypeRef inObj )
-{
- DNSServerRef const me = (DNSServerRef) inObj;
-
- check( !me->readSourceUDPv4 );
- check( !me->readSourceUDPv6 );
- check( !me->readSourceTCPv4 );
- check( !me->readSourceTCPv6 );
- check( !me->responseTimer );
- ForgetMem( &me->domain );
- dispatch_forget( &me->queue );
-}
-
-//===========================================================================================================================
-// DNSServerStart
-//===========================================================================================================================
-
-static void _DNSServerStart( void *inContext );
-static void _DNSServerStop( void *inContext, OSStatus inError );
-
-static void DNSServerStart( DNSServerRef me )
-{
- CFRetain( me );
- dispatch_async_f( me->queue, me, _DNSServerStart );
-}
-
-static void _DNSServerStart( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- DNSServerRef const me = (DNSServerRef) inContext;
- SocketRef sock = kInvalidSocketRef;
- SocketContext * sockCtx = NULL;
- const uint32_t loopbackV4 = htonl( INADDR_LOOPBACK );
- int year, month, day;
-
- // Create IPv4 UDP socket.
- // Initially, me->port is the port requested by the user. If it's 0, then the user wants any available ephemeral port.
- // If it's negative, then the user would like a port number equal to its absolute value, but will settle for any
- // available ephemeral port, if it's not available. The actual port number that was used will be stored in me->port and
- // used for the remaining sockets.
-
- err = _ServerSocketOpenEx2( AF_INET, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &loopbackV4 : NULL,
- me->port, &me->port, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
- require_noerr( err, exit );
- check( me->port > 0 );
-
- // Create read source for IPv4 UDP socket.
-
- err = SocketContextCreate( sock, me, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
- &me->readSourceUDPv4 );
- require_noerr( err, exit );
- dispatch_resume( me->readSourceUDPv4 );
- me->sockUDPv4 = sockCtx->sock;
- sockCtx = NULL;
-
- // Create IPv6 UDP socket.
-
- err = _ServerSocketOpenEx2( AF_INET6, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &in6addr_loopback : NULL,
- me->port, NULL, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
- require_noerr( err, exit );
-
- // Create read source for IPv6 UDP socket.
-
- err = SocketContextCreate( sock, me, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
- &me->readSourceUDPv6 );
- require_noerr( err, exit );
- dispatch_resume( me->readSourceUDPv6 );
- me->sockUDPv6 = sockCtx->sock;
- sockCtx = NULL;
-
- // Create IPv4 TCP socket.
-
- err = _ServerSocketOpenEx2( AF_INET, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &loopbackV4 : NULL,
- me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
- require_noerr( err, exit );
-
- // Create read source for IPv4 TCP socket.
-
- err = SocketContextCreate( sock, me, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
- &me->readSourceTCPv4 );
- require_noerr( err, exit );
- dispatch_resume( me->readSourceTCPv4 );
- sockCtx = NULL;
-
- // Create IPv6 TCP socket.
-
- err = _ServerSocketOpenEx2( AF_INET6, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &in6addr_loopback : NULL,
- me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
- require_noerr( err, exit );
-
- // Create read source for IPv6 TCP socket.
-
- err = SocketContextCreate( sock, me, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
- &me->readSourceTCPv6 );
- require_noerr( err, exit );
- dispatch_resume( me->readSourceTCPv6 );
- sockCtx = NULL;
-
- ds_ulog( kLogLevelInfo, "Server is using port %d.\n", me->port );
- if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Started, (uintptr_t) me->port, me->eventContext );
-
- // Create the serial number for the server's SOA record in the YYYMMDDnn convention recommended by
- // <https://tools.ietf.org/html/rfc1912#section-2.2> using the current time.
-
- gettimeofday( &now, NULL );
- SecondsToYMD_HMS( ( INT64_C_safe( kDaysToUnixEpoch ) * kSecondsPerDay ) + now.tv_sec, &year, &month, &day,
- NULL, NULL, NULL );
- me->serial = (uint32_t)( ( year * 1000000 ) + ( month * 10000 ) + ( day * 100 ) + 1 );
-
-exit:
- ForgetSocket( &sock );
- if( sockCtx ) SocketContextRelease( sockCtx );
- if( err ) _DNSServerStop( me, err );
-}
-
-//===========================================================================================================================
-// DNSServerStop
-//===========================================================================================================================
-
-static void _DNSServerUserStop( void *inContext );
-static void _DNSServerStop2( void *inContext );
-
-static void DNSServerStop( DNSServerRef me )
-{
- CFRetain( me );
- dispatch_async_f( me->queue, me, _DNSServerUserStop );
-}
-
-static void _DNSServerUserStop( void *inContext )
-{
- DNSServerRef const me = (DNSServerRef) inContext;
-
- _DNSServerStop( me, kNoErr );
- CFRelease( me );
-}
-
-static void _DNSServerStop( void *inContext, OSStatus inError )
-{
- DNSServerRef const me = (DNSServerRef) inContext;
-
- me->stopError = inError;
- dispatch_source_forget( &me->readSourceUDPv4 );
- dispatch_source_forget( &me->readSourceUDPv6 );
- dispatch_source_forget( &me->readSourceTCPv4 );
- dispatch_source_forget( &me->readSourceTCPv6 );
- dispatch_source_forget( &me->responseTimer );
- me->sockUDPv4 = kInvalidSocketRef;
- me->sockUDPv6 = kInvalidSocketRef;
-
- if( me->responseList )
- {
- _DNSDelayedResponseFreeList( me->responseList );
- me->responseList = NULL;
- }
- dispatch_async_f( me->queue, me, _DNSServerStop2 );
-}
-
-static void _DNSServerStop2( void *inContext )
-{
- DNSServerRef const me = (DNSServerRef) inContext;
-
- if( !me->stopped )
- {
- me->stopped = true;
- if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Stopped, (uintptr_t) me->stopError, me->eventContext );
- CFRelease( me );
- }
- CFRelease( me );
-}
-
-//===========================================================================================================================
-// _DNSDelayedResponseFree
-//===========================================================================================================================
-
-static void _DNSDelayedResponseFree( DNSDelayedResponse *inResponse )
-{
- ForgetMem( &inResponse->msgPtr );
- free( inResponse );
-}
-
-//===========================================================================================================================
-// _DNSDelayedResponseFreeList
-//===========================================================================================================================
-
-static void _DNSDelayedResponseFreeList( DNSDelayedResponse *inList )
-{
- DNSDelayedResponse * response;
-
- while( ( response = inList ) != NULL )
- {
- inList = response->next;
- _DNSDelayedResponseFree( response );
- }
-}
-
-//===========================================================================================================================
-// _DNSServerUDPReadHandler
-//===========================================================================================================================
-
-static OSStatus
- _DNSServerAnswerQuery(
- DNSServerRef inServer,
- const uint8_t * inQueryPtr,
- size_t inQueryLen,
- Boolean inForTCP,
- uint8_t ** outResponsePtr,
- size_t * outResponseLen );
-
-#define _DNSServerAnswerQueryForUDP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
- _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, false, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
-
-#define _DNSServerAnswerQueryForTCP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
- _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, true, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
-
-static OSStatus
- _DNSServerScheduleDelayedResponse(
- DNSServerRef inServer,
- const struct sockaddr * inDestAddr,
- uint8_t * inMsgPtr,
- size_t inMsgLen );
-static void _DNSServerUDPDelayedSend( void *inContext );
-
-static void _DNSServerUDPReadHandler( void *inContext )
-{
- OSStatus err;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- DNSServerRef const me = (DNSServerRef) sockCtx->userContext;
- struct timeval now;
- ssize_t n;
- sockaddr_ip clientAddr;
- socklen_t clientAddrLen;
- uint8_t * responsePtr = NULL; // malloc'd
- size_t responseLen;
- uint8_t msg[ 512 ];
-
- gettimeofday( &now, NULL );
-
- // Receive message.
-
- clientAddrLen = (socklen_t) sizeof( clientAddr );
- n = recvfrom( sockCtx->sock, (char *) msg, sizeof( msg ), 0, &clientAddr.sa, &clientAddrLen );
- err = map_socket_value_errno( sockCtx->sock, n >= 0, n );
- require_noerr( err, exit );
-
- ds_ulog( kLogLevelInfo, "UDP server received %zd bytes from %##a at %{du:time}.\n", n, &clientAddr, &now );
-
- if( n < kDNSHeaderLength )
- {
- ds_ulog( kLogLevelInfo, "UDP DNS message is too small (%zd < %d).\n", n, kDNSHeaderLength );
- goto exit;
- }
-
- ds_ulog( kLogLevelInfo, "UDP received message:\n\n%1{du:dnsmsg}", msg, (size_t) n );
-
- // Create response.
-
- err = _DNSServerAnswerQueryForUDP( me, msg, (size_t) n, &responsePtr, &responseLen );
- require_noerr_quiet( err, exit );
-
- // Schedule response.
-
- if( me->responseDelayMs > 0 )
- {
- err = _DNSServerScheduleDelayedResponse( me, &clientAddr.sa, responsePtr, responseLen );
- require_noerr( err, exit );
- responsePtr = NULL;
- }
- else
- {
- ds_ulog( kLogLevelInfo, "UDP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
-
- n = sendto( sockCtx->sock, (char *) responsePtr, responseLen, 0, &clientAddr.sa, clientAddrLen );
- err = map_socket_value_errno( sockCtx->sock, n == (ssize_t) responseLen, n );
- require_noerr( err, exit );
- }
-
-exit:
- FreeNullSafe( responsePtr );
- return;
-}
-
-static OSStatus
- _DNSServerScheduleDelayedResponse(
- DNSServerRef me,
- const struct sockaddr * inDestAddr,
- uint8_t * inMsgPtr,
- size_t inMsgLen )
-{
- OSStatus err;
- DNSDelayedResponse * response;
- DNSDelayedResponse ** responsePtr;
- DNSDelayedResponse * newResponse;
- uint64_t targetTicks;
-
- targetTicks = UpTicks() + MillisecondsToUpTicks( me->responseDelayMs );
-
- newResponse = (DNSDelayedResponse *) calloc( 1, sizeof( *newResponse ) );
- require_action( newResponse, exit, err = kNoMemoryErr );
-
- if( !me->responseList || ( targetTicks < me->responseList->targetTicks ) )
- {
- dispatch_source_forget( &me->responseTimer );
-
- err = DispatchTimerCreate( dispatch_time_milliseconds( me->responseDelayMs ), DISPATCH_TIME_FOREVER,
- ( (uint64_t) me->responseDelayMs ) * kNanosecondsPerMillisecond / 10, me->queue, _DNSServerUDPDelayedSend,
- NULL, me, &me->responseTimer );
- require_noerr( err, exit );
- dispatch_resume( me->responseTimer );
- }
-
- SockAddrCopy( inDestAddr, &newResponse->destAddr );
- newResponse->targetTicks = targetTicks;
- newResponse->msgPtr = inMsgPtr;
- newResponse->msgLen = inMsgLen;
-
- for( responsePtr = &me->responseList; ( response = *responsePtr ) != NULL; responsePtr = &response->next )
- {
- if( newResponse->targetTicks < response->targetTicks ) break;
- }
- newResponse->next = response;
- *responsePtr = newResponse;
- newResponse = NULL;
- err = kNoErr;
-
-exit:
- if( newResponse ) _DNSDelayedResponseFree( newResponse );
- return( err );
-}
-
-static void _DNSServerUDPDelayedSend( void *inContext )
-{
- OSStatus err;
- DNSServerRef const me = (DNSServerRef) inContext;
- DNSDelayedResponse * response;
- SocketRef sock;
- ssize_t n;
- uint64_t nowTicks;
- uint64_t remainingNs;
- DNSDelayedResponse * freeList = NULL;
-
- dispatch_source_forget( &me->responseTimer );
-
- nowTicks = UpTicks();
- while( ( ( response = me->responseList ) != NULL ) && ( response->targetTicks <= nowTicks ) )
- {
- me->responseList = response->next;
-
- ds_ulog( kLogLevelInfo, "UDP sending %zu byte response (delayed):\n\n%1{du:dnsmsg}",
- response->msgLen, response->msgPtr, response->msgLen );
-
- sock = ( response->destAddr.sa.sa_family == AF_INET ) ? me->sockUDPv4 : me->sockUDPv6;
- n = sendto( sock, (char *) response->msgPtr, response->msgLen, 0, &response->destAddr.sa,
- SockAddrGetSize( &response->destAddr ) );
- err = map_socket_value_errno( sock, n == (ssize_t) response->msgLen, n );
- check_noerr( err );
-
- response->next = freeList;
- freeList = response;
- nowTicks = UpTicks();
- }
-
- if( response )
- {
- check( response->targetTicks > nowTicks );
- remainingNs = UpTicksToNanoseconds( response->targetTicks - nowTicks );
- if( remainingNs > INT64_MAX ) remainingNs = INT64_MAX;
-
- err = DispatchTimerCreate( dispatch_time( DISPATCH_TIME_NOW, (int64_t) remainingNs ), DISPATCH_TIME_FOREVER, 0,
- me->queue, _DNSServerUDPDelayedSend, NULL, me, &me->responseTimer );
- require_noerr( err, exit );
- dispatch_resume( me->responseTimer );
- }
-
-exit:
- if( freeList ) _DNSDelayedResponseFreeList( freeList );
-}
-
-//===========================================================================================================================
-// _DNSServerAnswerQuery
-//===========================================================================================================================
-
-#define kLabelPrefix_Alias "alias"
-#define kLabelPrefix_AliasTTL "alias-ttl"
-#define kLabelPrefix_Count "count-"
-#define kLabelPrefix_Tag "tag-"
-#define kLabelPrefix_TTL "ttl-"
-#define kLabel_IPv4 "ipv4"
-#define kLabel_IPv6 "ipv6"
-#define kLabelPrefix_SRV "srv-"
-
-#define kMaxAliasTTLCount ( ( kDomainLabelLengthMax - sizeof_string( kLabelPrefix_AliasTTL ) ) / 2 )
-#define kMaxParsedSRVCount ( kDomainNameLengthMax / ( 1 + sizeof_string( kLabelPrefix_SRV ) + 5 ) )
-
-typedef struct
-{
- uint16_t priority; // Priority from SRV label.
- uint16_t weight; // Weight from SRV label.
- uint16_t port; // Port number from SRV label.
- uint16_t targetLen; // Total length of the target hostname labels that follow an SRV label.
- const uint8_t * targetPtr; // Pointer to the target hostname embedded in a domain name.
-
-} ParsedSRV;
-
-static OSStatus
- _DNSServerInitializeResponseMessage(
- DataBuffer * inDB,
- unsigned int inID,
- unsigned int inFlags,
- const uint8_t * inQName,
- unsigned int inQType,
- unsigned int inQClass );
-static OSStatus
- _DNSServerAnswerQueryDynamically(
- DNSServerRef inServer,
- const uint8_t * inQName,
- unsigned int inQType,
- unsigned int inQClass,
- Boolean inForTCP,
- DataBuffer * inDB );
-static Boolean
- _DNSServerNameIsSRVName(
- DNSServerRef inServer,
- const uint8_t * inName,
- const uint8_t ** outDomainPtr,
- size_t * outDomainLen,
- ParsedSRV inSRVArray[ kMaxParsedSRVCount ],
- size_t * outSRVCount );
-static Boolean
- _DNSServerNameIsHostname(
- DNSServerRef inServer,
- const uint8_t * inName,
- uint32_t * outAliasCount,
- uint32_t inAliasTTLs[ kMaxAliasTTLCount ],
- size_t * outAliasTTLCount,
- unsigned int * outCount,
- unsigned int * outRandCount,
- uint32_t * outTTL,
- Boolean * outHasA,
- Boolean * outHasAAAA,
- Boolean * outHasSOA );
-
-static OSStatus
- _DNSServerAnswerQuery(
- DNSServerRef me,
- const uint8_t * const inQueryPtr,
- const size_t inQueryLen,
- Boolean inForTCP,
- uint8_t ** outResponsePtr,
- size_t * outResponseLen )
-{
- OSStatus err;
- DataBuffer dataBuf;
- const uint8_t * ptr;
- const uint8_t * const queryEnd = &inQueryPtr[ inQueryLen ];
- const DNSHeader * qhdr;
- unsigned int msgID, qflags, qtype, qclass, rflags;
- uint8_t qname[ kDomainNameLengthMax ];
-
- DataBuffer_Init( &dataBuf, NULL, 0, kDNSMaxTCPMessageSize );
-
- require_action_quiet( inQueryLen >= kDNSHeaderLength, exit, err = kUnderrunErr );
-
- qhdr = (const DNSHeader *) inQueryPtr;
- msgID = DNSHeaderGetID( qhdr );
- qflags = DNSHeaderGetFlags( qhdr );
-
- // Minimal checking of the query message's header.
-
- if( ( qflags & kDNSHeaderFlag_Response ) || // The message must be a query, not a response.
- ( DNSFlagsGetOpCode( qflags ) != kDNSOpCode_Query ) || // OPCODE must be QUERY (standard query).
- ( DNSHeaderGetQuestionCount( qhdr ) != 1 ) ) // There should be a single question.
- {
- err = kRequestErr;
- goto exit;
- }
-
- // Get QNAME.
-
- ptr = (const uint8_t *) &qhdr[ 1 ];
- err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, ptr, qname, &ptr );
- require_noerr( err, exit );
-
- // Get QTYPE and QCLASS.
-
- require_action_quiet( ( queryEnd - ptr ) >= 4, exit, err = kUnderrunErr );
- qtype = DNSQuestionFixedFieldsGetType( (const DNSQuestionFixedFields *) ptr );
- qclass = DNSQuestionFixedFieldsGetClass( (const DNSQuestionFixedFields *) ptr );
- ptr += 4;
-
- // Create a tentative response message.
-
- rflags = kDNSHeaderFlag_Response;
- if( qflags & kDNSHeaderFlag_RecursionDesired ) rflags |= kDNSHeaderFlag_RecursionDesired;
- DNSFlagsSetOpCode( rflags, kDNSOpCode_Query );
-
- if( me->badUDPMode && !inForTCP ) msgID = (uint16_t)( msgID + 1 );
- err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
- require_noerr( err, exit );
-
- err = _DNSServerAnswerQueryDynamically( me, qname, qtype, qclass, inForTCP, &dataBuf );
- if( err )
- {
- DNSFlagsSetRCode( rflags, kDNSRCode_ServerFailure );
- err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
- require_noerr( err, exit );
- }
-
- err = DataBuffer_Detach( &dataBuf, outResponsePtr, outResponseLen );
- require_noerr( err, exit );
-
-exit:
- DataBuffer_Free( &dataBuf );
- return( err );
-}
-
-static OSStatus
- _DNSServerInitializeResponseMessage(
- DataBuffer * inDB,
- unsigned int inID,
- unsigned int inFlags,
- const uint8_t * inQName,
- unsigned int inQType,
- unsigned int inQClass )
-{
- OSStatus err;
- DNSHeader header;
-
- DataBuffer_Reset( inDB );
-
- memset( &header, 0, sizeof( header ) );
- DNSHeaderSetID( &header, inID );
- DNSHeaderSetFlags( &header, inFlags );
- DNSHeaderSetQuestionCount( &header, 1 );
-
- err = DataBuffer_Append( inDB, &header, sizeof( header ) );
- require_noerr( err, exit );
-
- err = _DataBuffer_AppendDNSQuestion( inDB, inQName, DomainNameLength( inQName ), (uint16_t) inQType,
- (uint16_t) inQClass );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-static OSStatus
- _DNSServerAnswerQueryDynamically(
- DNSServerRef me,
- const uint8_t * const inQName,
- const unsigned int inQType,
- const unsigned int inQClass,
- const Boolean inForTCP,
- DataBuffer * const inDB )
-{
- OSStatus err;
- DNSHeader * hdr;
- unsigned int flags, rcode;
- uint32_t aliasCount, i;
- uint32_t aliasTTLs[ kMaxAliasTTLCount ];
- size_t aliasTTLCount;
- unsigned int addrCount, randCount;
- uint32_t ttl;
- ParsedSRV srvArray[ kMaxParsedSRVCount ];
- size_t srvCount;
- const uint8_t * srvDomainPtr;
- size_t srvDomainLen;
- unsigned int answerCount;
- Boolean notImplemented, truncated;
- Boolean useAliasTTLs, nameExists, nameHasA, nameHasAAAA, nameHasSRV, nameHasSOA;
- uint8_t namePtr[ 2 ];
- DNSRecordFixedFields fields;
-
- answerCount = 0;
- truncated = false;
- nameExists = false;
- require_action_quiet( inQClass == kDNSServiceClass_IN, done, notImplemented = true );
-
- notImplemented = false;
- aliasCount = 0;
- nameHasA = false;
- nameHasAAAA = false;
- nameHasSOA = false;
- useAliasTTLs = false;
- nameHasSRV = false;
- srvDomainLen = 0;
- srvCount = 0;
-
- if( _DNSServerNameIsHostname( me, inQName, &aliasCount, aliasTTLs, &aliasTTLCount, &addrCount, &randCount, &ttl,
- &nameHasA, &nameHasAAAA, &nameHasSOA ) )
- {
- check( !( ( aliasCount > 0 ) && ( aliasTTLCount > 0 ) ) );
- check( ( addrCount >= 1 ) && ( addrCount <= 255 ) );
- check( ( randCount == 0 ) || ( ( randCount >= addrCount ) && ( randCount <= 255 ) ) );
- check( nameHasA || nameHasAAAA );
-
- if( aliasTTLCount > 0 )
- {
- aliasCount = (uint32_t) aliasTTLCount;
- useAliasTTLs = true;
- }
- nameExists = true;
- }
- else if( _DNSServerNameIsSRVName( me, inQName, &srvDomainPtr, &srvDomainLen, srvArray, &srvCount ) )
- {
- nameHasSRV = true;
- nameExists = true;
- }
- require_quiet( nameExists, done );
-
- if( aliasCount > 0 )
- {
- size_t nameOffset;
- uint8_t rdataLabel[ 1 + kDomainLabelLengthMax + 1 ];
-
- // If aliasCount is non-zero, then the first label of QNAME is either "alias" or "alias-<N>". superPtr is a name
- // compression pointer to the second label of QNAME, i.e., the immediate superdomain name of QNAME. It's used for
- // the RDATA of CNAME records whose canonical name ends with the superdomain name. It may also be used to construct
- // CNAME record names, when the offset to the previous CNAME's RDATA doesn't fit in a compression pointer.
-
- const uint8_t superPtr[ 2 ] = { 0xC0, (uint8_t)( kDNSHeaderLength + 1 + inQName[ 0 ] ) };
-
- // The name of the first CNAME record is equal to QNAME, so nameOffset is set to offset of QNAME.
-
- nameOffset = kDNSHeaderLength;
-
- for( i = aliasCount; i >= 1; --i )
- {
- size_t nameLen;
- size_t rdataLen;
- uint32_t j;
- uint32_t aliasTTL;
- uint8_t nameLabel[ 1 + kDomainLabelLengthMax ];
-
- if( nameOffset <= kDNSCompressionOffsetMax )
- {
- WriteDNSCompressionPtr( namePtr, nameOffset );
- nameLen = sizeof( namePtr );
- }
- else
- {
- memcpy( nameLabel, rdataLabel, 1 + rdataLabel[ 0 ] );
- nameLen = 1 + nameLabel[ 0 ] + sizeof( superPtr );
- }
-
- if( i >= 2 )
- {
- char * dst = (char *) &rdataLabel[ 1 ];
- char * const lim = (char *) &rdataLabel[ countof( rdataLabel ) ];
-
- if( useAliasTTLs )
- {
- err = SNPrintF_Add( &dst, lim, kLabelPrefix_AliasTTL );
- require_noerr( err, exit );
-
- for( j = aliasCount - ( i - 1 ); j < aliasCount; ++j )
- {
- err = SNPrintF_Add( &dst, lim, "-%u", aliasTTLs[ j ] );
- require_noerr( err, exit );
- }
- }
- else
- {
- err = SNPrintF_Add( &dst, lim, kLabelPrefix_Alias "%?{end}-%u", i == 2, i - 1 );
- require_noerr( err, exit );
- }
- rdataLabel[ 0 ] = (uint8_t)( dst - (char *) &rdataLabel[ 1 ] );
- rdataLen = 1 + rdataLabel[ 0 ] + sizeof( superPtr );
- }
- else
- {
- rdataLen = sizeof( superPtr );
- }
-
- if( !inForTCP )
- {
- size_t recordLen = nameLen + sizeof( fields ) + rdataLen;
-
- if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
- {
- truncated = true;
- goto done;
- }
- }
- ++answerCount;
-
- // Set CNAME record's NAME.
-
- if( nameOffset <= kDNSCompressionOffsetMax )
- {
- err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
- require_noerr( err, exit );
- }
- else
- {
- err = DataBuffer_Append( inDB, nameLabel, 1 + nameLabel[ 0 ] );
- require_noerr( err, exit );
-
- err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
- require_noerr( err, exit );
- }
-
- // Set CNAME record's TYPE, CLASS, TTL, and RDLENGTH.
-
- aliasTTL = useAliasTTLs ? aliasTTLs[ aliasCount - i ] : me->defaultTTL;
- DNSRecordFixedFieldsSet( &fields, kDNSServiceType_CNAME, kDNSServiceClass_IN, aliasTTL, (uint16_t) rdataLen );
- err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
-
- // Save offset of CNAME record's RDATA, which may be used for the name of the next CNAME record.
-
- nameOffset = DataBuffer_GetLen( inDB );
-
- // Set CNAME record's RDATA.
-
- if( i >= 2 )
- {
- err = DataBuffer_Append( inDB, rdataLabel, 1 + rdataLabel[ 0 ] );
- require_noerr( err, exit );
- }
- err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
- require_noerr( err, exit );
- }
-
- namePtr[ 0 ] = superPtr[ 0 ];
- namePtr[ 1 ] = superPtr[ 1 ];
- }
- else
- {
- // There are no aliases, so initialize the name compression pointer to point to QNAME.
-
- WriteDNSCompressionPtr( namePtr, kDNSHeaderLength );
- }
-
- if( ( inQType == kDNSServiceType_A ) || ( inQType == kDNSServiceType_AAAA ) )
- {
- uint8_t * lsb; // Pointer to the least significant byte of record data.
- size_t recordLen; // Length of the entire record.
- size_t rdataLen; // Length of record's RDATA.
- uint8_t rdata[ 16 ]; // A buffer that's big enough for either A or AAAA RDATA.
- uint8_t randIntegers[ 255 ]; // Array for random integers in [1, 255].
- const int useBadAddrs = ( me->badUDPMode && !inForTCP ) ? true : false;
-
- if( inQType == kDNSServiceType_A )
- {
- const uint32_t baseAddrV4 = useBadAddrs ? kDNSServerBadBaseAddrV4 : kDNSServerBaseAddrV4;
-
- require_quiet( nameHasA, done );
-
- rdataLen = 4;
- WriteBig32( rdata, baseAddrV4 );
- lsb = &rdata[ 3 ];
- }
- else
- {
- const uint8_t * const baseAddrV6 = useBadAddrs ? kDNSServerBadBaseAddrV6 : kDNSServerBaseAddrV6;
-
- require_quiet( nameHasAAAA, done );
-
- rdataLen = 16;
- memcpy( rdata, baseAddrV6, 16 );
- lsb = &rdata[ 15 ];
- }
-
- if( randCount > 0 )
- {
- // Populate the array with all integers between 1 and <randCount>, inclusive.
-
- for( i = 0; i < randCount; ++i ) randIntegers[ i ] = (uint8_t)( i + 1 );
-
- // Prevent dubious static analyzer warning.
- // Note: _DNSServerNameIsHostname() already enforces randCount >= addrCount. Also, this require_fatal() check
- // needs to be placed right before the next for-loop. Any earlier, and the static analyzer warning will persist
- // for some reason.
-
- require_fatal( addrCount <= randCount, "Invalid Count label values: addrCount %u > randCount %u",
- addrCount, randCount );
-
- // Create a contiguous subarray starting at index 0 that contains <addrCount> randomly chosen integers between
- // 1 and <randCount>, inclusive.
- // Loop invariant 1: Array elements with indexes in [0, i - 1] have been randomly chosen.
- // Loop invariant 2: Array elements with indexes in [i, randCount - 1] are candidates for being chosen.
-
- for( i = 0; i < addrCount; ++i )
- {
- uint8_t tmp;
- uint32_t j;
-
- j = RandomRange( i, randCount - 1 );
- if( i != j )
- {
- tmp = randIntegers[ i ];
- randIntegers[ i ] = randIntegers[ j ];
- randIntegers[ j ] = tmp;
- }
- }
- }
-
- recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
- for( i = 0; i < addrCount; ++i )
- {
- if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
- {
- truncated = true;
- goto done;
- }
-
- // Set record NAME.
-
- err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
- require_noerr( err, exit );
-
- // Set record TYPE, CLASS, TTL, and RDLENGTH.
-
- DNSRecordFixedFieldsSet( &fields, (uint16_t) inQType, kDNSServiceClass_IN, ttl, (uint16_t) rdataLen );
- err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
-
- // Set record RDATA.
-
- *lsb = ( randCount > 0 ) ? randIntegers[ i ] : ( *lsb + 1 );
-
- err = DataBuffer_Append( inDB, rdata, rdataLen );
- require_noerr( err, exit );
-
- ++answerCount;
- }
- }
- else if( inQType == kDNSServiceType_SRV )
- {
- require_quiet( nameHasSRV, done );
-
- DNSRecordFixedFieldsSet( &fields, kDNSServiceType_SRV, kDNSServiceClass_IN, me->defaultTTL, 0 );
-
- for( i = 0; i < srvCount; ++i )
- {
- SRVRecordDataFixedFields fieldsSRV;
- size_t rdataLen;
- size_t recordLen;
- const ParsedSRV * const srv = &srvArray[ i ];
-
- rdataLen = sizeof( fieldsSRV ) + srvDomainLen + srv->targetLen + 1;
- recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
-
- if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
- {
- truncated = true;
- goto done;
- }
-
- // Append record NAME.
-
- err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
- require_noerr( err, exit );
-
- // Append record TYPE, CLASS, TTL, and RDLENGTH.
-
- WriteBig16( fields.rdlength, rdataLen );
- err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
-
- // Append SRV RDATA.
-
- SRVRecordDataFixedFieldsSet( &fieldsSRV, srv->priority, srv->weight, srv->port );
-
- err = DataBuffer_Append( inDB, &fieldsSRV, sizeof( fieldsSRV ) );
- require_noerr( err, exit );
-
- if( srv->targetLen > 0 )
- {
- err = DataBuffer_Append( inDB, srv->targetPtr, srv->targetLen );
- require_noerr( err, exit );
- }
-
- if( srvDomainLen > 0 )
- {
- err = DataBuffer_Append( inDB, srvDomainPtr, srvDomainLen );
- require_noerr( err, exit );
- }
-
- err = DataBuffer_Append( inDB, "", 1 ); // Append root label.
- require_noerr( err, exit );
-
- ++answerCount;
- }
- }
- else if( inQType == kDNSServiceType_SOA )
- {
- size_t nameLen, recordLen;
-
- require_quiet( nameHasSOA, done );
-
- nameLen = DomainNameLength( me->domain );
- if( !inForTCP )
- {
- err = AppendSOARecord( NULL, me->domain, nameLen, 0, 0, 0, kRootLabel, kRootLabel, 0, 0, 0, 0, 0, &recordLen );
- require_noerr( err, exit );
-
- if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
- {
- truncated = true;
- goto done;
- }
- }
-
- err = AppendSOARecord( inDB, me->domain, nameLen, kDNSServiceType_SOA, kDNSServiceClass_IN, me->defaultTTL,
- kRootLabel, kRootLabel, me->serial, 1 * kSecondsPerDay, 2 * kSecondsPerHour, 1000 * kSecondsPerHour,
- me->defaultTTL, NULL );
- require_noerr( err, exit );
-
- ++answerCount;
- }
-
-done:
- hdr = (DNSHeader *) DataBuffer_GetPtr( inDB );
- flags = DNSHeaderGetFlags( hdr );
- if( notImplemented )
- {
- rcode = kDNSRCode_NotImplemented;
- }
- else
- {
- flags |= kDNSHeaderFlag_AuthAnswer;
- if( truncated ) flags |= kDNSHeaderFlag_Truncation;
- rcode = nameExists ? kDNSRCode_NoError : kDNSRCode_NXDomain;
- }
- DNSFlagsSetRCode( flags, rcode );
- DNSHeaderSetFlags( hdr, flags );
- DNSHeaderSetAnswerCount( hdr, answerCount );
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-static Boolean
- _DNSServerNameIsHostname(
- DNSServerRef me,
- const uint8_t * inName,
- uint32_t * outAliasCount,
- uint32_t inAliasTTLs[ kMaxAliasTTLCount ],
- size_t * outAliasTTLCount,
- unsigned int * outCount,
- unsigned int * outRandCount,
- uint32_t * outTTL,
- Boolean * outHasA,
- Boolean * outHasAAAA,
- Boolean * outHasSOA )
-{
- OSStatus err;
- const uint8_t * label;
- const uint8_t * nextLabel;
- uint32_t aliasCount = 0; // Arg from Alias label. Valid values are in [2, 2^31 - 1].
- unsigned int count = 0; // First arg from Count label. Valid values are in [1, 255].
- unsigned int randCount = 0; // Second arg from Count label. Valid values are in [count, 255].
- int32_t ttl = -1; // Arg from TTL label. Valid values are in [0, 2^31 - 1].
- size_t aliasTTLCount = 0; // Count of TTL args from Alias-TTL label.
- int hasTagLabel = false;
- int hasIPv4Label = false;
- int hasIPv6Label = false;
- int isNameValid = false;
-
- for( label = inName; label[ 0 ]; label = nextLabel )
- {
- uint32_t arg;
-
- nextLabel = &label[ 1 + label[ 0 ] ];
-
- // Check if the first label is a valid alias TTL sequence label.
-
- if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_AliasTTL ) == 0 ) )
- {
- const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_AliasTTL ) ];
- const char * const end = (const char *) nextLabel;
- const char * next;
-
- check( label[ 0 ] <= kDomainLabelLengthMax );
-
- while( ptr < end )
- {
- if( *ptr != '-' ) break;
- ++ptr;
- err = DecimalTextToUInt32( ptr, end, &arg, &next );
- if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
- inAliasTTLs[ aliasTTLCount++ ] = arg;
- ptr = next;
- }
- if( ( aliasTTLCount == 0 ) || ( ptr != end ) ) break;
- }
-
- // Check if the first label is a valid alias label.
-
- else if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Alias ) == 0 ) )
- {
- const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Alias ) ];
- const char * const end = (const char *) nextLabel;
-
- if( ptr < end )
- {
- if( *ptr++ != '-' ) break;
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- if( err || ( arg < 2 ) || ( arg > INT32_MAX ) ) break; // Alias count must be in [2, 2^31 - 1].
- aliasCount = arg;
- if( ptr != end ) break;
- }
- else
- {
- aliasCount = 1;
- }
- }
-
- // Check if this label is a valid count label.
-
- else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Count ) == 0 )
- {
- const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Count ) ];
- const char * const end = (const char *) nextLabel;
-
- if( count > 0 ) break; // Count cannot be specified more than once.
-
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- if( err || ( arg < 1 ) || ( arg > 255 ) ) break; // Count must be in [1, 255].
- count = (unsigned int) arg;
-
- if( ptr < end )
- {
- if( *ptr++ != '-' ) break;
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- if( err || ( arg < (uint32_t) count ) || ( arg > 255 ) ) break; // Rand count must be in [count, 255].
- randCount = (unsigned int) arg;
- if( ptr != end ) break;
- }
- }
-
- // Check if this label is a valid TTL label.
-
- else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_TTL ) == 0 )
- {
- const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_TTL ) ];
- const char * const end = (const char *) nextLabel;
-
- if( ttl >= 0 ) break; // TTL cannot be specified more than once.
-
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
- ttl = (int32_t) arg;
- if( ptr != end ) break;
- }
-
- // Check if this label is a valid IPv4 label.
-
- else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv4 ) == 0 )
- {
- if( hasIPv4Label || hasIPv6Label ) break; // Valid names have at most one IPv4 or IPv6 label.
- hasIPv4Label = true;
- }
-
- // Check if this label is a valid IPv6 label.
-
- else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv6 ) == 0 )
- {
- if( hasIPv4Label || hasIPv6Label ) break; // Valid names have at most one IPv4 or IPv6 label.
- hasIPv6Label = true;
- }
-
- // Check if this label is a valid tag label.
-
- else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Tag ) == 0 )
- {
- hasTagLabel = true;
- }
-
- // If this and the remaining labels are equal to "d.test.", then the name exists. Otherwise, this label is invalid.
- // In both cases, there are no more labels to check.
-
- else
- {
- if( DomainNameEqual( label, me->domain ) ) isNameValid = true;
- break;
- }
- }
- require_quiet( isNameValid, exit );
-
- if( outAliasCount ) *outAliasCount = aliasCount;
- if( outAliasTTLCount ) *outAliasTTLCount = aliasTTLCount;
- if( outCount ) *outCount = ( count > 0 ) ? count : 1;
- if( outRandCount ) *outRandCount = randCount;
- if( outTTL ) *outTTL = ( ttl >= 0 ) ? ( (uint32_t) ttl ) : me->defaultTTL;
- if( outHasA ) *outHasA = ( hasIPv4Label || !hasIPv6Label ) ? true : false;
- if( outHasAAAA ) *outHasAAAA = ( hasIPv6Label || !hasIPv4Label ) ? true : false;
- if( outHasSOA )
- {
- *outHasSOA = ( !count && ( ttl < 0 ) && !hasIPv4Label && !hasIPv6Label && !hasTagLabel ) ? true : false;
- }
-
-exit:
- return( isNameValid ? true : false );
-}
-
-static Boolean
- _DNSServerNameIsSRVName(
- DNSServerRef me,
- const uint8_t * inName,
- const uint8_t ** outDomainPtr,
- size_t * outDomainLen,
- ParsedSRV inSRVArray[ kMaxParsedSRVCount ],
- size_t * outSRVCount )
-{
- OSStatus err;
- const uint8_t * label;
- const uint8_t * domainPtr;
- size_t domainLen;
- size_t srvCount;
- uint32_t arg;
- int isNameValid = false;
-
- label = inName;
-
- // Ensure that first label, i.e, the service label, begins with a '_' character.
-
- require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
- label = NextLabel( label );
-
- // Ensure that the second label, i.e., the proto label, begins with a '_' character (usually _tcp or _udp).
-
- require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
- label = NextLabel( label );
-
- // Parse the domain name, if any.
-
- domainPtr = label;
- while( *label )
- {
- if( DomainNameEqual( label, me->domain ) ||
- ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
- label = NextLabel( label );
- }
- require_quiet( *label, exit );
-
- domainLen = (size_t)( label - domainPtr );
-
- // Parse SRV labels, if any.
-
- srvCount = 0;
- while( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 )
- {
- const uint8_t * const nextLabel = NextLabel( label );
- const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_SRV ) ];
- const char * const end = (const char *) nextLabel;
- const uint8_t * target;
- unsigned int priority, weight, port;
-
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- require_quiet( !err && ( arg <= UINT16_MAX ), exit );
- priority = (unsigned int) arg;
-
- require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
- ++ptr;
-
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- require_quiet( !err && ( arg <= UINT16_MAX ), exit );
- weight = (unsigned int) arg;
-
- require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
- ++ptr;
-
- err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
- require_quiet( !err && ( arg <= UINT16_MAX ), exit );
- port = (unsigned int) arg;
-
- require_quiet( ptr == end, exit );
-
- target = nextLabel;
- for( label = nextLabel; *label; label = NextLabel( label ) )
- {
- if( DomainNameEqual( label, me->domain ) ||
- ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
- }
- require_quiet( *label, exit );
-
- if( inSRVArray )
- {
- inSRVArray[ srvCount ].priority = (uint16_t) priority;
- inSRVArray[ srvCount ].weight = (uint16_t) weight;
- inSRVArray[ srvCount ].port = (uint16_t) port;
- inSRVArray[ srvCount ].targetPtr = target;
- inSRVArray[ srvCount ].targetLen = (uint16_t)( label - target );
- }
- ++srvCount;
- }
- require_quiet( DomainNameEqual( label, me->domain ), exit );
- isNameValid = true;
-
- if( outDomainPtr ) *outDomainPtr = domainPtr;
- if( outDomainLen ) *outDomainLen = domainLen;
- if( outSRVCount ) *outSRVCount = srvCount;
-
-exit:
- return( isNameValid ? true : false );
-}
-
-//===========================================================================================================================
-// _DNSServerTCPReadHandler
-//===========================================================================================================================
-
-typedef struct
-{
- DNSServerRef server; // Reference to DNS server object.
- sockaddr_ip clientAddr; // Client's address.
- dispatch_source_t readSource; // Dispatch read source for client socket.
- dispatch_source_t writeSource; // Dispatch write source for client socket.
- size_t offset; // Offset into receive buffer.
- void * msgPtr; // Pointer to dynamically allocated message buffer.
- size_t msgLen; // Length of message buffer.
- Boolean readSuspended; // True if the read source is currently suspended.
- Boolean writeSuspended; // True if the write source is currently suspended.
- Boolean receivedLength; // True if receiving DNS message as opposed to the message length.
- uint8_t lenBuf[ 2 ]; // Buffer for two-octet message length field.
- iovec_t iov[ 2 ]; // IO vector for writing response message.
- iovec_t * iovPtr; // Vector pointer for SocketWriteData().
- int iovCount; // Vector count for SocketWriteData().
-
-} TCPConnectionContext;
-
-static void TCPConnectionStop( TCPConnectionContext *inContext );
-static void TCPConnectionContextFree( TCPConnectionContext *inContext );
-static void TCPConnectionReadHandler( void *inContext );
-static void TCPConnectionWriteHandler( void *inContext );
-
-#define TCPConnectionForget( X ) ForgetCustomEx( X, TCPConnectionStop, TCPConnectionContextFree )
-
-static void _DNSServerTCPReadHandler( void *inContext )
-{
- OSStatus err;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- DNSServerRef const me = (DNSServerRef) sockCtx->userContext;
- TCPConnectionContext * connection;
- socklen_t clientAddrLen;
- SocketRef newSock = kInvalidSocketRef;
- SocketContext * newSockCtx = NULL;
-
- connection = (TCPConnectionContext *) calloc( 1, sizeof( *connection ) );
- require_action( connection, exit, err = kNoMemoryErr );
-
- CFRetain( me );
- connection->server = me;
-
- clientAddrLen = (socklen_t) sizeof( connection->clientAddr );
- newSock = accept( sockCtx->sock, &connection->clientAddr.sa, &clientAddrLen );
- err = map_socket_creation_errno( newSock );
- require_noerr( err, exit );
-
- err = SocketContextCreate( newSock, connection, &newSockCtx );
- require_noerr( err, exit );
- newSock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( newSockCtx->sock, me->queue, TCPConnectionReadHandler, SocketContextCancelHandler,
- newSockCtx, &connection->readSource );
- require_noerr( err, exit );
- SocketContextRetain( newSockCtx );
- dispatch_resume( connection->readSource );
-
- err = DispatchWriteSourceCreate( newSockCtx->sock, me->queue, TCPConnectionWriteHandler, SocketContextCancelHandler,
- newSockCtx, &connection->writeSource );
- require_noerr( err, exit );
- SocketContextRetain( newSockCtx );
- connection->writeSuspended = true;
- connection = NULL;
-
-exit:
- ForgetSocket( &newSock );
- SocketContextRelease( newSockCtx );
- TCPConnectionForget( &connection );
-}
-
-//===========================================================================================================================
-// TCPConnectionStop
-//===========================================================================================================================
-
-static void TCPConnectionStop( TCPConnectionContext *inContext )
-{
- dispatch_source_forget_ex( &inContext->readSource, &inContext->readSuspended );
- dispatch_source_forget_ex( &inContext->writeSource, &inContext->writeSuspended );
-}
-
-//===========================================================================================================================
-// TCPConnectionContextFree
-//===========================================================================================================================
-
-static void TCPConnectionContextFree( TCPConnectionContext *inContext )
-{
- check( !inContext->readSource );
- check( !inContext->writeSource );
- ForgetCF( &inContext->server );
- ForgetMem( &inContext->msgPtr );
- free( inContext );
-}
-
-//===========================================================================================================================
-// TCPConnectionReadHandler
-//===========================================================================================================================
-
-static void TCPConnectionReadHandler( void *inContext )
-{
- OSStatus err;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- TCPConnectionContext * connection = (TCPConnectionContext *) sockCtx->userContext;
- struct timeval now;
- uint8_t * responsePtr = NULL; // malloc'd
- size_t responseLen;
-
- // Receive message length.
-
- if( !connection->receivedLength )
- {
- err = SocketReadData( sockCtx->sock, connection->lenBuf, sizeof( connection->lenBuf ), &connection->offset );
- if( err == EWOULDBLOCK ) goto exit;
- require_noerr( err, exit );
-
- connection->offset = 0;
- connection->msgLen = ReadBig16( connection->lenBuf );
- connection->msgPtr = malloc( connection->msgLen );
- require_action( connection->msgPtr, exit, err = kNoMemoryErr );
- connection->receivedLength = true;
- }
-
- // Receive message.
-
- err = SocketReadData( sockCtx->sock, connection->msgPtr, connection->msgLen, &connection->offset );
- if( err == EWOULDBLOCK ) goto exit;
- require_noerr( err, exit );
-
- gettimeofday( &now, NULL );
- dispatch_suspend( connection->readSource );
- connection->readSuspended = true;
-
- ds_ulog( kLogLevelInfo, "TCP server received %zu bytes from %##a at %{du:time}.\n",
- connection->msgLen, &connection->clientAddr, &now );
-
- if( connection->msgLen < kDNSHeaderLength )
- {
- ds_ulog( kLogLevelInfo, "TCP DNS message is too small (%zu < %d).\n", connection->msgLen, kDNSHeaderLength );
- goto exit;
- }
-
- ds_ulog( kLogLevelInfo, "TCP received message:\n\n%1{du:dnsmsg}", connection->msgPtr, connection->msgLen );
-
- // Create response.
-
- err = _DNSServerAnswerQueryForTCP( connection->server, connection->msgPtr, connection->msgLen, &responsePtr,
- &responseLen );
- require_noerr_quiet( err, exit );
-
- // Send response.
-
- ds_ulog( kLogLevelInfo, "TCP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
-
- free( connection->msgPtr );
- connection->msgPtr = responsePtr;
- connection->msgLen = responseLen;
- responsePtr = NULL;
-
- check( connection->msgLen <= UINT16_MAX );
- WriteBig16( connection->lenBuf, connection->msgLen );
- connection->iov[ 0 ].iov_base = connection->lenBuf;
- connection->iov[ 0 ].iov_len = sizeof( connection->lenBuf );
- connection->iov[ 1 ].iov_base = connection->msgPtr;
- connection->iov[ 1 ].iov_len = connection->msgLen;
-
- connection->iovPtr = connection->iov;
- connection->iovCount = 2;
-
- check( connection->writeSuspended );
- dispatch_resume( connection->writeSource );
- connection->writeSuspended = false;
-
-exit:
- FreeNullSafe( responsePtr );
- if( err && ( err != EWOULDBLOCK ) ) TCPConnectionForget( &connection );
-}
-
-//===========================================================================================================================
-// TCPConnectionWriteHandler
-//===========================================================================================================================
-
-static void TCPConnectionWriteHandler( void *inContext )
-{
- OSStatus err;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- TCPConnectionContext * connection = (TCPConnectionContext *) sockCtx->userContext;
-
- err = SocketWriteData( sockCtx->sock, &connection->iovPtr, &connection->iovCount );
- if( err == EWOULDBLOCK ) goto exit;
- check_noerr( err );
-
- TCPConnectionForget( &connection );
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// MDNSReplierCmd
-//===========================================================================================================================
-
-typedef struct
-{
- uint8_t * hostname; // Used as the base name for hostnames and service names.
- uint8_t * serviceLabel; // Label containing the base service name.
- unsigned int maxInstanceCount; // Maximum number of service instances and hostnames.
- uint64_t * bitmaps; // Array of 64-bit bitmaps for keeping track of needed responses.
- size_t bitmapCount; // Number of 64-bit bitmaps.
- dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
- dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
- uint32_t ifIndex; // Index of the interface to run on.
- unsigned int recordCountA; // Number of A records per hostname.
- unsigned int recordCountAAAA; // Number of AAAA records per hostname.
- unsigned int maxDropCount; // If > 0, the drop rates apply to only the first <maxDropCount> responses.
- double ucastDropRate; // Probability of dropping a unicast response.
- double mcastDropRate; // Probability of dropping a multicast query or response.
- uint8_t * dropCounters; // If maxDropCount > 0, array of <maxInstanceCount> response drop counters.
- Boolean noAdditionals; // True if responses are to not include additional records.
- Boolean useIPv4; // True if the replier is to use IPv4.
- Boolean useIPv6; // True if the replier is to use IPv6.
- uint8_t msgBuf[ kMDNSMessageSizeMax ]; // Buffer for received mDNS message.
-#if( TARGET_OS_DARWIN )
- dispatch_source_t processMonitor; // Process monitor source for process being followed, if any.
- pid_t followPID; // PID of process being followed, if any. (If it exits, we exit).
-#endif
-
-} MDNSReplierContext;
-
-typedef struct MRResourceRecord MRResourceRecord;
-struct MRResourceRecord
-{
- MRResourceRecord * next; // Next item in list.
- uint8_t * name; // Resource record name.
- uint16_t type; // Resource record type.
- uint16_t class; // Resource record class.
- uint32_t ttl; // Resource record TTL.
- uint16_t rdlength; // Resource record data length.
- uint8_t * rdata; // Resource record data.
- const uint8_t * target; // For SRV records, pointer to target in RDATA.
-};
-
-typedef struct MRNameOffsetItem MRNameOffsetItem;
-struct MRNameOffsetItem
-{
- MRNameOffsetItem * next; // Next item in list.
- uint16_t offset; // Offset of domain name in response message.
- uint8_t name[ 1 ]; // Variable-length array for domain name.
-};
-
-#if( TARGET_OS_DARWIN )
-static void _MDNSReplierFollowedProcessHandler( void *inContext );
-#endif
-static void _MDNSReplierReadHandler( void *inContext );
-static OSStatus
- _MDNSReplierAnswerQuery(
- MDNSReplierContext * inContext,
- const uint8_t * inQueryPtr,
- size_t inQueryLen,
- sockaddr_ip * inSender,
- SocketRef inSock,
- unsigned int inIndex );
-static OSStatus
- _MDNSReplierAnswerListAdd(
- MDNSReplierContext * inContext,
- MRResourceRecord ** inAnswerList,
- unsigned int inIndex,
- const uint8_t * inName,
- unsigned int inType,
- unsigned int inClass );
-static void
- _MDNSReplierAnswerListRemovePTR(
- MRResourceRecord ** inAnswerListPtr,
- const uint8_t * inName,
- const uint8_t * inRData );
-static OSStatus
- _MDNSReplierSendOrDropResponse(
- MDNSReplierContext * inContext,
- MRResourceRecord * inAnswerList,
- sockaddr_ip * inQuerier,
- SocketRef inSock,
- unsigned int inIndex,
- Boolean inUnicast );
-static OSStatus
- _MDNSReplierCreateResponse(
- MDNSReplierContext * inContext,
- MRResourceRecord * inAnswerList,
- unsigned int inIndex,
- uint8_t ** outResponsePtr,
- size_t * outResponseLen );
-static OSStatus
- _MDNSReplierAppendNameToResponse(
- DataBuffer * inResponse,
- const uint8_t * inName,
- MRNameOffsetItem ** inNameOffsetListPtr );
-static Boolean
- _MDNSReplierServiceTypeMatch(
- const MDNSReplierContext * inContext,
- const uint8_t * inName,
- unsigned int * outTXTSize,
- unsigned int * outCount );
-static Boolean
- _MDNSReplierServiceInstanceNameMatch(
- const MDNSReplierContext * inContext,
- const uint8_t * inName,
- unsigned int * outIndex,
- unsigned int * outTXTSize,
- unsigned int * outCount );
-static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName );
-static Boolean
- _MDNSReplierHostnameMatch(
- const MDNSReplierContext * inContext,
- const uint8_t * inName,
- unsigned int * outIndex );
-static OSStatus _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT );
-static OSStatus
- _MRResourceRecordCreate(
- uint8_t * inName,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- uint16_t inRDLength,
- uint8_t * inRData,
- MRResourceRecord ** outRecord );
-static void _MRResourceRecordFree( MRResourceRecord *inRecord );
-static void _MRResourceRecordFreeList( MRResourceRecord *inList );
-static OSStatus _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem );
-static void _MRNameOffsetItemFree( MRNameOffsetItem *inItem );
-static void _MRNameOffsetItemFreeList( MRNameOffsetItem *inList );
-
-ulog_define_ex( "com.apple.dnssdutil", MDNSReplier, kLogLevelInfo, kLogFlags_None, "MDNSReplier", NULL );
-#define mr_ulog( LEVEL, ... ) ulog( &log_category_from_name( MDNSReplier ), (LEVEL), __VA_ARGS__ )
-
-static void MDNSReplierCmd( void )
-{
- OSStatus err;
- MDNSReplierContext * context;
- SocketRef sockV4 = kInvalidSocketRef;
- SocketRef sockV6 = kInvalidSocketRef;
- const char * ifname;
- size_t len;
- uint8_t name[ 1 + kDomainLabelLengthMax + 1 ];
- char ifnameBuf[ IF_NAMESIZE + 1 ];
-
- err = CheckIntegerArgument( gMDNSReplier_MaxInstanceCount, "max instance count", 1, UINT16_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSReplier_RecordCountA, "A record count", 0, 255 );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSReplier_RecordCountAAAA, "AAAA record count", 0, 255 );
- require_noerr_quiet( err, exit );
-
- err = CheckDoubleArgument( gMDNSReplier_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
- require_noerr_quiet( err, exit );
-
- err = CheckDoubleArgument( gMDNSReplier_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSReplier_MaxDropCount, "drop count", 0, 255 );
- require_noerr_quiet( err, exit );
-
- if( gMDNSReplier_Foreground )
- {
- LogControl( "MDNSReplier:output=file;stdout,MDNSReplier:flags=time;prefix" );
- }
-
- context = (MDNSReplierContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->maxInstanceCount = (unsigned int) gMDNSReplier_MaxInstanceCount;
- context->recordCountA = (unsigned int) gMDNSReplier_RecordCountA;
- context->recordCountAAAA = (unsigned int) gMDNSReplier_RecordCountAAAA;
- context->maxDropCount = (unsigned int) gMDNSReplier_MaxDropCount;
- context->ucastDropRate = gMDNSReplier_UnicastDropRate;
- context->mcastDropRate = gMDNSReplier_MulticastDropRate;
- context->noAdditionals = gMDNSReplier_NoAdditionals ? true : false;
- context->useIPv4 = ( gMDNSReplier_UseIPv4 || !gMDNSReplier_UseIPv6 ) ? true : false;
- context->useIPv6 = ( gMDNSReplier_UseIPv6 || !gMDNSReplier_UseIPv4 ) ? true : false;
- context->bitmapCount = ( context->maxInstanceCount + 63 ) / 64;
-
-#if( TARGET_OS_DARWIN )
- if( gMDNSReplier_FollowPID )
- {
- err = StringToPID( gMDNSReplier_FollowPID, &context->followPID );
- if( err || ( context->followPID < 0 ) )
- {
- FPrintF( stderr, "error: Invalid follow PID: %s\n", gMDNSReplier_FollowPID );
- goto exit;
- }
-
- err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
- _MDNSReplierFollowedProcessHandler, NULL, context, &context->processMonitor );
- require_noerr( err, exit );
- dispatch_resume( context->processMonitor );
- }
- else
- {
- context->followPID = -1;
- }
-#endif
-
- if( context->maxDropCount > 0 )
- {
- context->dropCounters = (uint8_t *) calloc( context->maxInstanceCount, sizeof( *context->dropCounters ) );
- require_action( context->dropCounters, exit, err = kNoMemoryErr );
- }
-
- context->bitmaps = (uint64_t *) calloc( context->bitmapCount, sizeof( *context->bitmaps ) );
- require_action( context->bitmaps, exit, err = kNoMemoryErr );
-
- // Create the base hostname label.
-
- len = strlen( gMDNSReplier_Hostname );
- if( context->maxInstanceCount > 1 )
- {
- unsigned int maxInstanceCount, digitCount;
-
- // When there's more than one instance, extra bytes are needed to append " (<instance index>)" or
- // "-<instance index>" to the base hostname.
-
- maxInstanceCount = context->maxInstanceCount;
- for( digitCount = 0; maxInstanceCount > 0; ++digitCount ) maxInstanceCount /= 10;
- len += ( 3 + digitCount );
- }
-
- if( len <= kDomainLabelLengthMax )
- {
- uint8_t * dst = &name[ 1 ];
- uint8_t * lim = &name[ countof( name ) ];
-
- SNPrintF_Add( (char **) &dst, (char *) lim, "%s", gMDNSReplier_Hostname );
- name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
-
- err = DomainNameDupLower( name, &context->hostname, NULL );
- require_noerr( err, exit );
- }
- else
- {
- FPrintF( stderr, "error: Base name \"%s\" is too long for max instance count of %u.\n",
- gMDNSReplier_Hostname, context->maxInstanceCount );
- goto exit;
- }
-
- // Create the service label.
-
- len = strlen( gMDNSReplier_ServiceTypeTag ) + 3; // We need three extra bytes for the service type prefix "_t-".
- if( len <= kDomainLabelLengthMax )
- {
- uint8_t * dst = &name[ 1 ];
- uint8_t * lim = &name[ countof( name ) ];
-
- SNPrintF_Add( (char **) &dst, (char *) lim, "_t-%s", gMDNSReplier_ServiceTypeTag );
- name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
-
- err = DomainNameDupLower( name, &context->serviceLabel, NULL );
- require_noerr( err, exit );
- }
- else
- {
- FPrintF( stderr, "error: Service type tag is too long.\n" );
- goto exit;
- }
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
- require_noerr_quiet( err, exit );
-
- ifname = if_indextoname( context->ifIndex, ifnameBuf );
- require_action( ifname, exit, err = kNameErr );
-
- // Set up IPv4 socket.
-
- if( context->useIPv4 )
- {
- err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV4 );
- require_noerr( err, exit );
- }
-
- // Set up IPv6 socket.
-
- if( context->useIPv6 )
- {
- err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV6 );
- require_noerr( err, exit );
- }
-
- // Create dispatch read sources for socket(s).
-
- if( IsValidSocket( sockV4 ) )
- {
- SocketContext * sockCtx;
-
- err = SocketContextCreate( sockV4, context, &sockCtx );
- require_noerr( err, exit );
- sockV4 = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
- &context->readSourceV4 );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSourceV4 );
- }
-
- if( IsValidSocket( sockV6 ) )
- {
- SocketContext * sockCtx;
-
- err = SocketContextCreate( sockV6, context, &sockCtx );
- require_noerr( err, exit );
- sockV6 = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
- &context->readSourceV6 );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSourceV6 );
- }
-
- dispatch_main();
-
-exit:
- ForgetSocket( &sockV4 );
- ForgetSocket( &sockV6 );
- exit( 1 );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// _MDNSReplierFollowedProcessHandler
-//===========================================================================================================================
-
-static void _MDNSReplierFollowedProcessHandler( void *inContext )
-{
- MDNSReplierContext * const context = (MDNSReplierContext *) inContext;
-
- if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT )
- {
- mr_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited.\n", (int64_t) context->followPID );
- exit( 0 );
- }
-}
-#endif
-
-//===========================================================================================================================
-// _MDNSReplierReadHandler
-//===========================================================================================================================
-
-#define ShouldDrop( P ) ( ( (P) > 0.0 ) && ( ( (P) >= 1.0 ) || RandomlyTrue( P ) ) )
-
-static void _MDNSReplierReadHandler( void *inContext )
-{
- OSStatus err;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- MDNSReplierContext * const context = (MDNSReplierContext *) sockCtx->userContext;
- size_t msgLen;
- sockaddr_ip sender;
- const DNSHeader * hdr;
- unsigned int flags, questionCount, i, j;
- const uint8_t * ptr;
- int drop, isMetaQuery;
-
- err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &sender, sizeof( sender ),
- NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- if( msgLen < kDNSHeaderLength )
- {
- mr_ulog( kLogLevelInfo, "Message is too small (%zu < %d).\n", msgLen, kDNSHeaderLength );
- goto exit;
- }
-
- // Perform header field checks.
- // The message ID and most flag bits are silently ignored (see <https://tools.ietf.org/html/rfc6762#section-18>).
-
- hdr = (DNSHeader *) context->msgBuf;
- flags = DNSHeaderGetFlags( hdr );
- require_quiet( ( flags & kDNSHeaderFlag_Response ) == 0, exit ); // Reject responses.
- require_quiet( DNSFlagsGetOpCode( flags ) == kDNSOpCode_Query, exit ); // Reject opcodes other than standard query.
- require_quiet( DNSFlagsGetRCode( flags ) == kDNSRCode_NoError, exit ); // Reject non-zero rcodes.
-
- drop = ( !context->maxDropCount && ShouldDrop( context->mcastDropRate ) ) ? true : false;
-
- mr_ulog( kLogLevelInfo, "Received %zu byte message from %##a%?s:\n\n%#1{du:dnsmsg}",
- msgLen, &sender, drop, " (dropping)", context->msgBuf, msgLen );
-
- // Based on the QNAMEs in the query message, determine from which sets of records we may possibly need answers.
-
- questionCount = DNSHeaderGetQuestionCount( hdr );
- require_quiet( questionCount > 0, exit );
-
- memset( context->bitmaps, 0, context->bitmapCount * sizeof_element( context->bitmaps ) );
-
- isMetaQuery = false;
- ptr = (const uint8_t *) &hdr[ 1 ];
- for( i = 0; i < questionCount; ++i )
- {
- unsigned int count, index;
- uint16_t qtype, qclass;
- uint8_t qname[ kDomainNameLengthMax ];
-
- err = DNSMessageExtractQuestion( context->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
- require_noerr_quiet( err, exit );
-
- if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
-
- if( _MDNSReplierHostnameMatch( context, qname, &index ) ||
- _MDNSReplierServiceInstanceNameMatch( context, qname, &index, NULL, NULL ) )
- {
- if( ( index >= 1 ) && ( index <= context->maxInstanceCount ) )
- {
- context->bitmaps[ ( index - 1 ) / 64 ] |= ( UINT64_C( 1 ) << ( ( index - 1 ) % 64 ) );
- }
- }
- else if( _MDNSReplierServiceTypeMatch( context, qname, NULL, &count ) )
- {
- if( ( count >= 1 ) && ( count <= context->maxInstanceCount ) )
- {
- for( j = 0; j < (unsigned int) context->bitmapCount; ++j )
- {
- if( count < 64 )
- {
- context->bitmaps[ j ] |= ( ( UINT64_C( 1 ) << count ) - 1 );
- break;
- }
- else
- {
- context->bitmaps[ j ] = ~UINT64_C( 0 );
- count -= 64;
- }
- }
- }
- }
- else if( _MDNSReplierAboutRecordNameMatch( context, qname ) )
- {
- isMetaQuery = true;
- }
- }
-
- // Attempt to answer the query message using selected record sets.
-
- if( isMetaQuery )
- {
- err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock, 0 );
- check_noerr( err );
- }
- if( drop ) goto exit;
-
- for( i = 0; i < context->bitmapCount; ++i )
- {
- for( j = 0; ( context->bitmaps[ i ] != 0 ) && ( j < 64 ); ++j )
- {
- const uint64_t bitmask = UINT64_C( 1 ) << j;
-
- if( context->bitmaps[ i ] & bitmask )
- {
- context->bitmaps[ i ] &= ~bitmask;
-
- err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock,
- ( i * 64 ) + j + 1 );
- check_noerr( err );
- }
- }
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _MDNSReplierAnswerQuery
-//===========================================================================================================================
-
-static OSStatus
- _MDNSReplierAnswerQuery(
- MDNSReplierContext * inContext,
- const uint8_t * inQueryPtr,
- size_t inQueryLen,
- sockaddr_ip * inSender,
- SocketRef inSock,
- unsigned int inIndex )
-{
- OSStatus err;
- const DNSHeader * hdr;
- const uint8_t * ptr;
- unsigned int questionCount, answerCount, i;
- MRResourceRecord * ucastAnswerList = NULL;
- MRResourceRecord * mcastAnswerList = NULL;
-
- require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
-
- // Get answers for questions.
-
- check( inQueryLen >= kDNSHeaderLength );
- hdr = (const DNSHeader *) inQueryPtr;
- questionCount = DNSHeaderGetQuestionCount( hdr );
-
- ptr = (const uint8_t *) &hdr[ 1 ];
- for( i = 0; i < questionCount; ++i )
- {
- MRResourceRecord ** answerListPtr;
- uint16_t qtype, qclass;
- uint8_t qname[ kDomainNameLengthMax ];
-
- err = DNSMessageExtractQuestion( inQueryPtr, inQueryLen, ptr, qname, &qtype, &qclass, &ptr );
- require_noerr_quiet( err, exit );
-
- if( qclass & kQClassUnicastResponseBit )
- {
- qclass &= ~kQClassUnicastResponseBit;
- answerListPtr = &ucastAnswerList;
- }
- else
- {
- answerListPtr = &mcastAnswerList;
- }
-
- err = _MDNSReplierAnswerListAdd( inContext, answerListPtr, inIndex, qname, qtype, qclass );
- require_noerr( err, exit );
- }
- require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
-
- // Suppress known answers.
- // Records in the Answer section of the query message are known answers, so remove them from the answer lists.
- // See <https://tools.ietf.org/html/rfc6762#section-7.1>.
-
- answerCount = DNSHeaderGetAnswerCount( hdr );
- for( i = 0; i < answerCount; ++i )
- {
- const uint8_t * rdataPtr;
- const uint8_t * recordPtr;
- uint16_t type, class;
- uint8_t name[ kDomainNameLengthMax ];
- uint8_t instance[ kDomainNameLengthMax ];
-
- recordPtr = ptr;
- err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, ptr, NULL, &type, &class, NULL, NULL, NULL, &ptr );
- require_noerr_quiet( err, exit );
-
- if( ( type != kDNSServiceType_PTR ) || ( class != kDNSServiceClass_IN ) ) continue;
-
- err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, recordPtr, name, NULL, NULL, NULL, &rdataPtr, NULL, NULL );
- require_noerr( err, exit );
-
- err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, rdataPtr, instance, NULL );
- require_noerr_quiet( err, exit );
-
- if( ucastAnswerList ) _MDNSReplierAnswerListRemovePTR( &ucastAnswerList, name, instance );
- if( mcastAnswerList ) _MDNSReplierAnswerListRemovePTR( &mcastAnswerList, name, instance );
- }
- require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
-
- // Send or drop responses.
-
- if( ucastAnswerList )
- {
- err = _MDNSReplierSendOrDropResponse( inContext, ucastAnswerList, inSender, inSock, inIndex, true );
- require_noerr( err, exit );
- }
-
- if( mcastAnswerList )
- {
- err = _MDNSReplierSendOrDropResponse( inContext, mcastAnswerList, inSender, inSock, inIndex, false );
- require_noerr( err, exit );
- }
- err = kNoErr;
-
-exit:
- _MRResourceRecordFreeList( ucastAnswerList );
- _MRResourceRecordFreeList( mcastAnswerList );
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSReplierAnswerListAdd
-//===========================================================================================================================
-
-static OSStatus
- _MDNSReplierAnswerListAdd(
- MDNSReplierContext * inContext,
- MRResourceRecord ** inAnswerList,
- unsigned int inIndex,
- const uint8_t * inName,
- unsigned int inType,
- unsigned int inClass )
-{
- OSStatus err;
- uint8_t * recordName = NULL;
- uint8_t * rdataPtr = NULL;
- size_t rdataLen;
- MRResourceRecord * answer;
- MRResourceRecord ** answerPtr;
- const uint8_t * const hostname = inContext->hostname;
- unsigned int i;
- uint32_t index;
- unsigned int count, txtSize;
-
- require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
- require_action_quiet( inClass == kDNSServiceClass_IN, exit, err = kNoErr );
-
- for( answerPtr = inAnswerList; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
- {
- if( ( answer->type == inType ) && DomainNameEqual( answer->name, inName ) )
- {
- err = kNoErr;
- goto exit;
- }
- }
-
- // Index 0 is reserved for answering queries about the mdnsreplier, while all other index values up to the maximum
- // instance count are for answering queries about service instances.
-
- if( inIndex == 0 )
- {
- if( _MDNSReplierAboutRecordNameMatch( inContext, inName ) )
- {
- int listHasTXT = false;
-
- if( inType == kDNSServiceType_ANY )
- {
- for( answer = *inAnswerList; answer; answer = answer->next )
- {
- if( ( answer->type == kDNSServiceType_TXT ) && DomainNameEqual( answer->name, inName ) )
- {
- listHasTXT = true;
- break;
- }
- }
- }
-
- if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- err = CreateTXTRecordDataFromString( "ready=yes", ',', &rdataPtr, &rdataLen );
- require_noerr( err, exit );
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- }
- else if( inType == kDNSServiceType_NSEC )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_TXT );
- require_noerr( err, exit );
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- }
- }
- }
- else if( _MDNSReplierHostnameMatch( inContext, inName, &index ) && ( index == inIndex ) )
- {
- int listHasA = false;
- int listHasAAAA = false;
-
- if( inType == kDNSServiceType_ANY )
- {
- for( answer = *inAnswerList; answer; answer = answer->next )
- {
- if( answer->type == kDNSServiceType_A )
- {
- if( !listHasA && DomainNameEqual( answer->name, inName ) ) listHasA = true;
- }
- else if( answer->type == kDNSServiceType_AAAA )
- {
- if( !listHasAAAA && DomainNameEqual( answer->name, inName ) ) listHasAAAA = true;
- }
- if( listHasA && listHasAAAA ) break;
- }
- }
-
- if( ( inType == kDNSServiceType_A ) || ( ( inType == kDNSServiceType_ANY ) && !listHasA ) )
- {
- for( i = 1; i <= inContext->recordCountA; ++i )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- rdataLen = 4;
- rdataPtr = (uint8_t *) malloc( rdataLen );
- require_action( rdataPtr, exit, err = kNoMemoryErr );
-
- rdataPtr[ 0 ] = 0;
- WriteBig16( &rdataPtr[ 1 ], inIndex );
- rdataPtr[ 3 ] = (uint8_t) i;
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_A, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- answerPtr = &answer->next;
- }
- }
-
- if( ( inType == kDNSServiceType_AAAA ) || ( ( inType == kDNSServiceType_ANY ) && !listHasAAAA ) )
- {
- for( i = 1; i <= inContext->recordCountAAAA; ++i )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- rdataLen = 16;
- rdataPtr = (uint8_t *) memdup( kMDNSReplierBaseAddrV6, rdataLen );
- require_action( rdataPtr, exit, err = kNoMemoryErr );
-
- WriteBig16( &rdataPtr[ 12 ], inIndex );
- rdataPtr[ 15 ] = (uint8_t) i;
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_AAAA, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- answerPtr = &answer->next;
- }
- }
- else if( inType == kDNSServiceType_NSEC )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- if( ( inContext->recordCountA > 0 ) && ( inContext->recordCountAAAA > 0 ) )
- {
- err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_A, kDNSServiceType_AAAA );
- require_noerr( err, exit );
- }
- else if( inContext->recordCountA > 0 )
- {
- err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_A );
- require_noerr( err, exit );
- }
- else if( inContext->recordCountAAAA > 0 )
- {
- err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_AAAA );
- require_noerr( err, exit );
- }
- else
- {
- err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 0 );
- require_noerr( err, exit );
- }
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- }
- }
- else if( _MDNSReplierServiceTypeMatch( inContext, inName, NULL, &count ) && ( count >= inIndex ) )
- {
- int listHasPTR = false;
-
- if( inType == kDNSServiceType_ANY )
- {
- for( answer = *inAnswerList; answer; answer = answer->next )
- {
- if( ( answer->type == kDNSServiceType_PTR ) && DomainNameEqual( answer->name, inName ) )
- {
- listHasPTR = true;
- break;
- }
- }
- }
-
- if( ( inType == kDNSServiceType_PTR ) || ( ( inType == kDNSServiceType_ANY ) && !listHasPTR ) )
- {
- size_t recordNameLen;
- uint8_t * ptr;
- uint8_t * lim;
-
- err = DomainNameDupLower( inName, &recordName, &recordNameLen );
- require_noerr( err, exit );
-
- rdataLen = 1 + hostname[ 0 ] + 10 + recordNameLen;
- rdataPtr = (uint8_t *) malloc( rdataLen );
- require_action( rdataPtr, exit, err = kNoMemoryErr );
-
- lim = &rdataPtr[ rdataLen ];
-
- ptr = &rdataPtr[ 1 ];
- memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
- ptr += hostname[ 0 ];
- if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, " (%u)", inIndex );
- rdataPtr[ 0 ] = (uint8_t)( ptr - &rdataPtr[ 1 ] );
-
- check( (size_t)( lim - ptr ) >= recordNameLen );
- memcpy( ptr, recordName, recordNameLen );
- ptr += recordNameLen;
-
- rdataLen = (size_t)( ptr - rdataPtr );
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_PTR, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- }
- }
- else if( _MDNSReplierServiceInstanceNameMatch( inContext, inName, &index, &txtSize, &count ) &&
- ( index == inIndex ) && ( count >= inIndex ) )
- {
- int listHasSRV = false;
- int listHasTXT = false;
-
- if( inType == kDNSServiceType_ANY )
- {
- for( answer = *inAnswerList; answer; answer = answer->next )
- {
- if( answer->type == kDNSServiceType_SRV )
- {
- if( !listHasSRV && DomainNameEqual( answer->name, inName ) ) listHasSRV = true;
- }
- else if( answer->type == kDNSServiceType_TXT )
- {
- if( !listHasTXT && DomainNameEqual( answer->name, inName ) ) listHasTXT = true;
- }
- if( listHasSRV && listHasTXT ) break;
- }
- }
-
- if( ( inType == kDNSServiceType_SRV ) || ( ( inType == kDNSServiceType_ANY ) && !listHasSRV ) )
- {
- SRVRecordDataFixedFields * fields;
- uint8_t * ptr;
- uint8_t * lim;
- uint8_t * targetPtr;
-
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- rdataLen = sizeof( SRVRecordDataFixedFields ) + 1 + hostname[ 0 ] + 10 + kLocalNameLen;
- rdataPtr = (uint8_t *) malloc( rdataLen );
- require_action( rdataPtr, exit, err = kNoMemoryErr );
-
- lim = &rdataPtr[ rdataLen ];
-
- fields = (SRVRecordDataFixedFields *) rdataPtr;
- SRVRecordDataFixedFieldsSet( fields, 0, 0, (uint16_t)( kMDNSReplierPortBase + txtSize ) );
-
- targetPtr = (uint8_t *) &fields[ 1 ];
-
- ptr = &targetPtr[ 1 ];
- memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
- ptr += hostname[ 0 ];
- if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, "-%u", inIndex );
- targetPtr[ 0 ] = (uint8_t)( ptr - &targetPtr[ 1 ] );
-
- check( (size_t)( lim - ptr ) >= kLocalNameLen );
- memcpy( ptr, kLocalName, kLocalNameLen );
- ptr += kLocalNameLen;
-
- rdataLen = (size_t)( ptr - rdataPtr );
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_SRV, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- answerPtr = &answer->next;
- }
-
- if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- rdataLen = txtSize;
- err = _MDNSReplierCreateTXTRecord( inName, rdataLen, &rdataPtr );
- require_noerr( err, exit );
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- }
- else if( inType == kDNSServiceType_NSEC )
- {
- err = DomainNameDupLower( inName, &recordName, NULL );
- require_noerr( err, exit );
-
- err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_TXT, kDNSServiceType_SRV );
- require_noerr( err, exit );
-
- err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
- (uint16_t) rdataLen, rdataPtr, &answer );
- require_noerr( err, exit );
- recordName = NULL;
- rdataPtr = NULL;
-
- *answerPtr = answer;
- }
- }
- err = kNoErr;
-
-exit:
- FreeNullSafe( recordName );
- FreeNullSafe( rdataPtr );
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSReplierAnswerListRemovePTR
-//===========================================================================================================================
-
-static void
- _MDNSReplierAnswerListRemovePTR(
- MRResourceRecord ** inAnswerListPtr,
- const uint8_t * inName,
- const uint8_t * inRData )
-{
- MRResourceRecord * answer;
- MRResourceRecord ** answerPtr;
-
- for( answerPtr = inAnswerListPtr; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
- {
- if( ( answer->type == kDNSServiceType_PTR ) && ( answer->class == kDNSServiceClass_IN ) &&
- DomainNameEqual( answer->name, inName ) && DomainNameEqual( answer->rdata, inRData ) ) break;
- }
- if( answer )
- {
- *answerPtr = answer->next;
- _MRResourceRecordFree( answer );
- }
-}
-
-//===========================================================================================================================
-// _MDNSReplierSendOrDropResponse
-//===========================================================================================================================
-
-static OSStatus
- _MDNSReplierSendOrDropResponse(
- MDNSReplierContext * inContext,
- MRResourceRecord * inAnswerList,
- sockaddr_ip * inQuerier,
- SocketRef inSock,
- unsigned int inIndex,
- Boolean inUnicast )
-{
- OSStatus err;
- uint8_t * responsePtr = NULL;
- size_t responseLen;
- const struct sockaddr * destAddr;
- ssize_t n;
- const double dropRate = inUnicast ? inContext->ucastDropRate : inContext->mcastDropRate;
- int drop;
-
- check( inIndex <= inContext->maxInstanceCount );
-
- // If maxDropCount > 0, then the drop rates apply only to the first maxDropCount responses. Otherwise, all messages are
- // subject to their respective drop rate. Also, responses to queries about mDNS replier itself (indicated by index 0),
- // as opposed to those for service instance records, are never dropped.
-
- drop = false;
- if( inIndex > 0 )
- {
- if( inContext->maxDropCount > 0 )
- {
- uint8_t * const dropCount = &inContext->dropCounters[ inIndex - 1 ];
-
- if( *dropCount < inContext->maxDropCount )
- {
- if( ShouldDrop( dropRate ) ) drop = true;
- *dropCount += 1;
- }
- }
- else if( ShouldDrop( dropRate ) )
- {
- drop = true;
- }
- }
-
- err = _MDNSReplierCreateResponse( inContext, inAnswerList, inIndex, &responsePtr, &responseLen );
- require_noerr( err, exit );
-
- if( inUnicast )
- {
- destAddr = &inQuerier->sa;
- }
- else
- {
- destAddr = ( inQuerier->sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
- }
-
- mr_ulog( kLogLevelInfo, "%s %zu byte response to %##a:\n\n%#1{du:dnsmsg}",
- drop ? "Dropping" : "Sending", responseLen, destAddr, responsePtr, responseLen );
-
- if( !drop )
- {
- n = sendto( inSock, (char *) responsePtr, responseLen, 0, destAddr, SockAddrGetSize( destAddr ) );
- err = map_socket_value_errno( inSock, n == (ssize_t) responseLen, n );
- require_noerr( err, exit );
- }
-
-exit:
- FreeNullSafe( responsePtr );
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSReplierCreateResponse
-//===========================================================================================================================
-
-static OSStatus
- _MDNSReplierCreateResponse(
- MDNSReplierContext * inContext,
- MRResourceRecord * inAnswerList,
- unsigned int inIndex,
- uint8_t ** outResponsePtr,
- size_t * outResponseLen )
-{
- OSStatus err;
- DataBuffer responseDB;
- DNSHeader hdr;
- MRResourceRecord * answer;
- uint8_t * responsePtr;
- size_t responseLen, len;
- unsigned int answerCount, recordCount;
- MRNameOffsetItem * nameOffsetList = NULL;
-
- DataBuffer_Init( &responseDB, NULL, 0, SIZE_MAX );
-
- // The current answers in the answer list will make up the response's Answer Record Section.
-
- answerCount = 0;
- for( answer = inAnswerList; answer; answer = answer->next ) { ++answerCount; }
-
- // Unless configured not to, add any additional answers to the answer list for the Additional Record Section.
-
- if( !inContext->noAdditionals )
- {
- for( answer = inAnswerList; answer; answer = answer->next )
- {
- switch( answer->type )
- {
- case kDNSServiceType_PTR:
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_SRV,
- answer->class );
- require_noerr( err, exit );
-
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_TXT,
- answer->class );
- require_noerr( err, exit );
- break;
-
- case kDNSServiceType_SRV:
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_A,
- answer->class );
- require_noerr( err, exit );
-
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_AAAA,
- answer->class );
- require_noerr( err, exit );
-
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
- answer->class );
- require_noerr( err, exit );
- break;
-
- case kDNSServiceType_TXT:
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
- answer->class );
- require_noerr( err, exit );
- break;
-
- case kDNSServiceType_A:
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_AAAA,
- answer->class );
- require_noerr( err, exit );
-
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
- answer->class );
- require_noerr( err, exit );
- break;
-
- case kDNSServiceType_AAAA:
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_A,
- answer->class );
- require_noerr( err, exit );
-
- err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
- answer->class );
- require_noerr( err, exit );
- break;
-
- default:
- break;
- }
- }
- }
-
- // Append a provisional header to the response message.
-
- memset( &hdr, 0, sizeof( hdr ) );
- DNSHeaderSetFlags( &hdr, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
-
- err = DataBuffer_Append( &responseDB, &hdr, sizeof( hdr ) );
- require_noerr( err, exit );
-
- // Append answers to response message.
-
- responseLen = DataBuffer_GetLen( &responseDB );
- recordCount = 0;
- for( answer = inAnswerList; answer; answer = answer->next )
- {
- DNSRecordFixedFields fields;
- unsigned int class;
-
- // Append record NAME.
-
- err = _MDNSReplierAppendNameToResponse( &responseDB, answer->name, &nameOffsetList );
- require_noerr( err, exit );
-
- // Append record TYPE, CLASS, TTL, and provisional RDLENGTH.
-
- class = answer->class;
- if( ( answer->type == kDNSServiceType_SRV ) || ( answer->type == kDNSServiceType_TXT ) ||
- ( answer->type == kDNSServiceType_A ) || ( answer->type == kDNSServiceType_AAAA ) ||
- ( answer->type == kDNSServiceType_NSEC ) )
- {
- class |= kRRClassCacheFlushBit;
- }
-
- DNSRecordFixedFieldsSet( &fields, answer->type, (uint16_t) class, answer->ttl, (uint16_t) answer->rdlength );
- err = DataBuffer_Append( &responseDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
-
- // Append record RDATA.
- // The RDATA of PTR, SRV, and NSEC records contain domain names, which are subject to name compression.
-
- if( ( answer->type == kDNSServiceType_PTR ) || ( answer->type == kDNSServiceType_SRV ) ||
- ( answer->type == kDNSServiceType_NSEC ) )
- {
- size_t rdlength;
- uint8_t * rdLengthPtr;
- const size_t rdLengthOffset = DataBuffer_GetLen( &responseDB ) - 2;
- const size_t rdataOffset = DataBuffer_GetLen( &responseDB );
-
- if( answer->type == kDNSServiceType_PTR )
- {
- err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
- require_noerr( err, exit );
- }
- else if( answer->type == kDNSServiceType_SRV )
- {
- require_fatal( answer->target == &answer->rdata[ 6 ], "Bad SRV record target pointer." );
-
- err = DataBuffer_Append( &responseDB, answer->rdata, (size_t)( answer->target - answer->rdata ) );
- require_noerr( err, exit );
-
- err = _MDNSReplierAppendNameToResponse( &responseDB, answer->target, &nameOffsetList );
- require_noerr( err, exit );
- }
- else
- {
- const size_t nameLen = DomainNameLength( answer->rdata );
-
- err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
- require_noerr( err, exit );
-
- require_fatal( answer->rdlength > nameLen, "Bad NSEC record data length." );
-
- err = DataBuffer_Append( &responseDB, &answer->rdata[ nameLen ], answer->rdlength - nameLen );
- require_noerr( err, exit );
- }
-
- // Set the actual RDLENGTH, which may be less than the original due to name compression.
-
- rdlength = DataBuffer_GetLen( &responseDB ) - rdataOffset;
- check( rdlength <= UINT16_MAX );
-
- rdLengthPtr = DataBuffer_GetPtr( &responseDB ) + rdLengthOffset;
- WriteBig16( rdLengthPtr, rdlength );
- }
- else
- {
- err = DataBuffer_Append( &responseDB, answer->rdata, answer->rdlength );
- require_noerr( err, exit );
- }
-
- if( DataBuffer_GetLen( &responseDB ) > kMDNSMessageSizeMax ) break;
- responseLen = DataBuffer_GetLen( &responseDB );
- ++recordCount;
- }
-
- // Set the response header's Answer and Additional record counts.
- // Note: recordCount may be less than answerCount if including all answerCount records would cause the size of the
- // response message to exceed the maximum mDNS message size.
-
- if( recordCount <= answerCount )
- {
- DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount );
- }
- else
- {
- DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), answerCount );
- DNSHeaderSetAdditionalCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount - answerCount );
- }
-
- err = DataBuffer_Detach( &responseDB, &responsePtr, &len );
- require_noerr( err, exit );
-
- if( outResponsePtr ) *outResponsePtr = responsePtr;
- if( outResponseLen ) *outResponseLen = responseLen;
-
-exit:
- _MRNameOffsetItemFreeList( nameOffsetList );
- DataBuffer_Free( &responseDB );
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSReplierAppendNameToResponse
-//===========================================================================================================================
-
-static OSStatus
- _MDNSReplierAppendNameToResponse(
- DataBuffer * inResponse,
- const uint8_t * inName,
- MRNameOffsetItem ** inNameOffsetListPtr )
-{
- OSStatus err;
- const uint8_t * subname;
- const uint8_t * limit;
- size_t nameOffset;
- MRNameOffsetItem * item;
- uint8_t compressionPtr[ 2 ];
-
- nameOffset = DataBuffer_GetLen( inResponse );
-
- // Find the name's longest subname (more accurately, its longest sub-FQDN) in the name compression list.
-
- for( subname = inName; subname[ 0 ] != 0; subname += ( 1 + subname[ 0 ] ) )
- {
- for( item = *inNameOffsetListPtr; item; item = item->next )
- {
- if( DomainNameEqual( item->name, subname ) ) break;
- }
-
- // If an item was found for this subname, then append a name compression pointer and we're done. Otherwise, append
- // the subname's first label.
-
- if( item )
- {
- WriteDNSCompressionPtr( compressionPtr, item->offset );
-
- err = DataBuffer_Append( inResponse, compressionPtr, sizeof( compressionPtr ) );
- require_noerr( err, exit );
- break;
- }
- else
- {
- err = DataBuffer_Append( inResponse, subname, 1 + subname[ 0 ] );
- require_noerr( err, exit );
- }
- }
-
- // If we made it to the root label, then no subname was able to be compressed. All of the name's labels up to the root
- // label were appended to the response message, so a root label is needed to terminate the complete name.
-
- if( subname[ 0 ] == 0 )
- {
- err = DataBuffer_Append( inResponse, "", 1 );
- require_noerr( err, exit );
- }
-
- // Add subnames that weren't able to be compressed and their offsets to the name compression list.
-
- limit = subname;
- for( subname = inName; subname < limit; subname += ( 1 + subname[ 0 ] ) )
- {
- const size_t subnameOffset = nameOffset + (size_t)( subname - inName );
-
- if( subnameOffset > kDNSCompressionOffsetMax ) break;
-
- err = _MRNameOffsetItemCreate( subname, (uint16_t) subnameOffset, &item );
- require_noerr( err, exit );
-
- item->next = *inNameOffsetListPtr;
- *inNameOffsetListPtr = item;
- }
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSReplierServiceTypeMatch
-//===========================================================================================================================
-
-static Boolean
- _MDNSReplierServiceTypeMatch(
- const MDNSReplierContext * inContext,
- const uint8_t * inName,
- unsigned int * outTXTSize,
- unsigned int * outCount )
-{
- OSStatus err;
- const char * ptr;
- const char * end;
- uint32_t txtSize, count;
- const uint8_t * const serviceLabel = inContext->serviceLabel;
- int nameMatches = false;
-
- require_quiet( inName[ 0 ] >= serviceLabel[ 0 ], exit );
- if( memicmp( &inName[ 1 ], &serviceLabel[ 1 ], serviceLabel[ 0 ] ) != 0 ) goto exit;
-
- ptr = (const char *) &inName[ 1 + serviceLabel[ 0 ] ];
- end = (const char *) &inName[ 1 + inName[ 0 ] ];
-
- require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
- ++ptr;
-
- err = DecimalTextToUInt32( ptr, end, &txtSize, &ptr );
- require_noerr_quiet( err, exit );
- require_quiet( txtSize <= UINT16_MAX, exit );
-
- require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
- ++ptr;
-
- err = DecimalTextToUInt32( ptr, end, &count, &ptr );
- require_noerr_quiet( err, exit );
- require_quiet( count <= UINT16_MAX, exit );
- require_quiet( ptr == end, exit );
-
- if( !DomainNameEqual( (const uint8_t *) ptr, (const uint8_t *) "\x04" "_tcp" "\x05" "local" ) ) goto exit;
- nameMatches = true;
-
- if( outTXTSize ) *outTXTSize = txtSize;
- if( outCount ) *outCount = count;
-
-exit:
- return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-// _MDNSReplierServiceInstanceNameMatch
-//===========================================================================================================================
-
-static Boolean
- _MDNSReplierServiceInstanceNameMatch(
- const MDNSReplierContext * inContext,
- const uint8_t * inName,
- unsigned int * outIndex,
- unsigned int * outTXTSize,
- unsigned int * outCount )
-{
- OSStatus err;
- const uint8_t * ptr;
- const uint8_t * end;
- uint32_t index;
- unsigned int txtSize, count;
- const uint8_t * const hostname = inContext->hostname;
- int nameMatches = false;
-
- require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
- if( memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
-
- ptr = &inName[ 1 + hostname[ 0 ] ];
- end = &inName[ 1 + inName[ 0 ] ];
- if( ptr < end )
- {
- require_quiet( ( end - ptr ) >= 2, exit );
- require_quiet( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ), exit );
- ptr += 2;
-
- err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
- require_noerr_quiet( err, exit );
- require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
-
- require_quiet( ( ( end - ptr ) == 1 ) && ( *ptr == ')' ), exit );
- ++ptr;
- }
- else
- {
- index = 1;
- }
-
- if( !_MDNSReplierServiceTypeMatch( inContext, ptr, &txtSize, &count ) ) goto exit;
- nameMatches = true;
-
- if( outIndex ) *outIndex = index;
- if( outTXTSize ) *outTXTSize = txtSize;
- if( outCount ) *outCount = count;
-
-exit:
- return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-// _MDNSReplierAboutRecordNameMatch
-//===========================================================================================================================
-
-static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName )
-{
- const uint8_t * subname;
- const uint8_t * const hostname = inContext->hostname;
- int nameMatches = false;
-
- if( strnicmpx( &inName[ 1 ], inName[ 0 ], "about" ) != 0 ) goto exit;
- subname = NextLabel( inName );
-
- if( !MemIEqual( &subname[ 1 ], subname[ 0 ], &hostname[ 1 ], hostname[ 0 ] ) ) goto exit;
- subname = NextLabel( subname );
-
- if( !DomainNameEqual( subname, kLocalName ) ) goto exit;
- nameMatches = true;
-
-exit:
- return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-// _MDNSReplierHostnameMatch
-//===========================================================================================================================
-
-static Boolean
- _MDNSReplierHostnameMatch(
- const MDNSReplierContext * inContext,
- const uint8_t * inName,
- unsigned int * outIndex )
-{
- OSStatus err;
- const uint8_t * ptr;
- const uint8_t * end;
- uint32_t index;
- const uint8_t * const hostname = inContext->hostname;
- int nameMatches = false;
-
- require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
- if( memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
-
- ptr = &inName[ 1 + hostname[ 0 ] ];
- end = &inName[ 1 + inName[ 0 ] ];
- if( ptr < end )
- {
- require_quiet( *ptr == '-', exit );
- ++ptr;
-
- err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
- require_noerr_quiet( err, exit );
- require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
- require_quiet( ptr == end, exit );
- }
- else
- {
- index = 1;
- }
-
- if( !DomainNameEqual( ptr, kLocalName ) ) goto exit;
- nameMatches = true;
-
- if( outIndex ) *outIndex = index;
-
-exit:
- return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-// _MDNSReplierCreateTXTRecord
-//===========================================================================================================================
-
-static OSStatus _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT )
-{
- OSStatus err;
- uint8_t * txt;
- uint8_t * ptr;
- size_t i, wholeCount, remCount;
- uint32_t hash;
- int n;
- uint8_t txtStr[ 16 ];
-
- require_action_quiet( inSize > 0, exit, err = kSizeErr );
-
- txt = (uint8_t *) malloc( inSize );
- require_action( txt, exit, err = kNoMemoryErr );
-
- hash = FNV1( inRecordName, DomainNameLength( inRecordName ) );
-
- txtStr[ 0 ] = 15;
- n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
- check( n == 15 );
-
- ptr = txt;
- wholeCount = inSize / 16;
- for( i = 0; i < wholeCount; ++i )
- {
- memcpy( ptr, txtStr, 16 );
- ptr += 16;
- }
-
- remCount = inSize % 16;
- if( remCount > 0 )
- {
- txtStr[ 0 ] = (uint8_t)( remCount - 1 );
- memcpy( ptr, txtStr, remCount );
- ptr += remCount;
- }
- check( ptr == &txt[ inSize ] );
-
- *outTXT = txt;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _MRResourceRecordCreate
-//===========================================================================================================================
-
-static OSStatus
- _MRResourceRecordCreate(
- uint8_t * inName,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- uint16_t inRDLength,
- uint8_t * inRData,
- MRResourceRecord ** outRecord )
-{
- OSStatus err;
- MRResourceRecord * obj;
-
- obj = (MRResourceRecord *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = inName;
- obj->type = inType;
- obj->class = inClass;
- obj->ttl = inTTL;
- obj->rdlength = inRDLength;
- obj->rdata = inRData;
-
- if( inType == kDNSServiceType_SRV )
- {
- require_action_quiet( obj->rdlength > sizeof( SRVRecordDataFixedFields ), exit, err = kMalformedErr );
- obj->target = obj->rdata + sizeof( SRVRecordDataFixedFields );
- }
-
- *outRecord = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- FreeNullSafe( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _MRResourceRecordFree
-//===========================================================================================================================
-
-static void _MRResourceRecordFree( MRResourceRecord *inRecord )
-{
- ForgetMem( &inRecord->name );
- ForgetMem( &inRecord->rdata );
- free( inRecord );
-}
-
-//===========================================================================================================================
-// _MRResourceRecordFreeList
-//===========================================================================================================================
-
-static void _MRResourceRecordFreeList( MRResourceRecord *inList )
-{
- MRResourceRecord * record;
-
- while( ( record = inList ) != NULL )
- {
- inList = record->next;
- _MRResourceRecordFree( record );
- }
-}
-
-//===========================================================================================================================
-// _MRNameOffsetItemCreate
-//===========================================================================================================================
-
-static OSStatus _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem )
-{
- OSStatus err;
- MRNameOffsetItem * obj;
- size_t nameLen;
-
- require_action_quiet( inOffset <= kDNSCompressionOffsetMax, exit, err = kSizeErr );
-
- nameLen = DomainNameLength( inName );
- obj = (MRNameOffsetItem *) calloc( 1, offsetof( MRNameOffsetItem, name ) + nameLen );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->offset = inOffset;
- memcpy( obj->name, inName, nameLen );
-
- *outItem = obj;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _MRNameOffsetItemFree
-//===========================================================================================================================
-
-static void _MRNameOffsetItemFree( MRNameOffsetItem *inItem )
-{
- free( inItem );
-}
-
-//===========================================================================================================================
-// _MRNameOffsetItemFreeList
-//===========================================================================================================================
-
-static void _MRNameOffsetItemFreeList( MRNameOffsetItem *inList )
-{
- MRNameOffsetItem * item;
-
- while( ( item = inList ) != NULL )
- {
- inList = item->next;
- _MRNameOffsetItemFree( item );
- }
-}
-
-//===========================================================================================================================
-// GAIPerfCmd
-//===========================================================================================================================
-
-#define kGAIPerfGAITimeLimitMs 500 // Allow at most 500 ms for a DNSServiceGetAddrInfo() operation to complete.
-#define kGAIPerfStandardTTL ( 1 * kSecondsPerHour )
-
-typedef struct GAITesterPrivate * GAITesterRef;
-typedef struct GAITestCase GAITestCase;
-
-typedef struct
-{
- const char * name; // Domain name that was resolved.
- uint64_t connectionTimeUs; // Time in microseconds that it took to create a DNS-SD connection.
- uint64_t firstTimeUs; // Time in microseconds that it took to get the first address result.
- uint64_t timeUs; // Time in microseconds that it took to get all expected address results.
- OSStatus error;
-
-} GAITestItemResult;
-
-typedef void ( *GAITesterStopHandler_f )( void *inContext, OSStatus inError );
-typedef void
- ( *GAITesterResultsHandler_f )(
- const char * inCaseTitle,
- NanoTime64 inCaseStartTime,
- NanoTime64 inCaseEndTime,
- const GAITestItemResult * inResultArray,
- size_t inResultCount,
- void * inContext );
-
-typedef unsigned int GAITestAddrType;
-#define kGAITestAddrType_None 0
-#define kGAITestAddrType_IPv4 ( 1U << 0 )
-#define kGAITestAddrType_IPv6 ( 1U << 1 )
-#define kGAITestAddrType_Both ( kGAITestAddrType_IPv4 | kGAITestAddrType_IPv6 )
-
-#define GAITestAddrTypeIsValid( X ) \
- ( ( (X) & kGAITestAddrType_Both ) && ( ( (X) & ~kGAITestAddrType_Both ) == 0 ) )
-
-typedef struct
-{
- GAITesterRef tester; // GAI tester object.
- CFMutableArrayRef testCaseResults; // Array of test case results.
- unsigned int callDelayMs; // Amount of time to wait before calling DNSServiceGetAddrInfo().
- unsigned int serverDelayMs; // Amount of additional time to have server delay its responses.
- unsigned int defaultIterCount; // Default test case iteration count.
- dispatch_source_t sigIntSource; // Dispatch source for SIGINT.
- dispatch_source_t sigTermSource; // Dispatch source for SIGTERM.
- char * outputFilePath; // File to write test results to. If NULL, then write to stdout.
- OutputFormatType outputFormat; // Format of test results output.
- Boolean appendNewline; // True if a newline character should be appended to JSON output.
- Boolean skipPathEval; // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
- Boolean badUDPMode; // True if the test DNS server is to run in Bad UDP mode.
- Boolean testFailed; // True if at least one test case iteration failed.
-
-} GAIPerfContext;
-
-static void GAIPerfContextFree( GAIPerfContext *inContext );
-static OSStatus GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext );
-static OSStatus GAIPerfAddBasicTestCases( GAIPerfContext *inContext );
-static void GAIPerfTesterStopHandler( void *inContext, OSStatus inError );
-static void
- GAIPerfResultsHandler(
- const char * inCaseTitle,
- NanoTime64 inCaseStartTime,
- NanoTime64 inCaseEndTime,
- const GAITestItemResult * inResultArray,
- size_t inResultCount,
- void * inContext );
-static void GAIPerfSignalHandler( void *inContext );
-
-CFTypeID GAITesterGetTypeID( void );
-static OSStatus
- GAITesterCreate(
- dispatch_queue_t inQueue,
- int inCallDelayMs,
- int inServerDelayMs,
- int inServerDefaultTTL,
- Boolean inSkipPathEvaluation,
- Boolean inBadUDPMode,
- GAITesterRef * outTester );
-static void GAITesterStart( GAITesterRef inTester );
-static void GAITesterStop( GAITesterRef inTester );
-static OSStatus GAITesterAddTestCase( GAITesterRef inTester, GAITestCase *inCase );
-static void
- GAITesterSetStopHandler(
- GAITesterRef inTester,
- GAITesterStopHandler_f inEventHandler,
- void * inEventContext );
-static void
- GAITesterSetResultsHandler(
- GAITesterRef inTester,
- GAITesterResultsHandler_f inResultsHandler,
- void * inResultsContext );
-
-static OSStatus GAITestCaseCreate( const char *inTitle, GAITestCase **outCase );
-static void GAITestCaseFree( GAITestCase *inCase );
-static OSStatus
- GAITestCaseAddItem(
- GAITestCase * inCase,
- unsigned int inAliasCount,
- unsigned int inAddressCount,
- int inTTL,
- GAITestAddrType inHasAddrs,
- GAITestAddrType inWantAddrs,
- unsigned int inTimeLimitMs,
- unsigned int inItemCount );
-static OSStatus
- GAITestCaseAddLocalHostItem(
- GAITestCase * inCase,
- GAITestAddrType inWantAddrs,
- unsigned int inTimeLimitMs,
- unsigned int inItemCount );
-
-static void GAIPerfCmd( void )
-{
- OSStatus err;
- GAIPerfContext * context = NULL;
-
- err = CheckRootUser();
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gGAIPerf_CallDelayMs, "call delay (ms)", 0, INT_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gGAIPerf_ServerDelayMs, "server delay (ms)", 0, INT_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gGAIPerf_IterationCount, "iteration count", 1, INT_MAX );
- require_noerr_quiet( err, exit );
-
- context = (GAIPerfContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->testCaseResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( context->testCaseResults, exit, err = kNoMemoryErr );
-
- context->callDelayMs = (unsigned int) gGAIPerf_CallDelayMs;
- context->serverDelayMs = (unsigned int) gGAIPerf_ServerDelayMs;
- context->defaultIterCount = (unsigned int) gGAIPerf_IterationCount;
- context->appendNewline = gGAIPerf_OutputAppendNewline ? true : false;
- context->skipPathEval = gGAIPerf_SkipPathEvalulation ? true : false;
- context->badUDPMode = gGAIPerf_BadUDPMode ? true : false;
-
- if( gGAIPerf_OutputFilePath )
- {
- context->outputFilePath = strdup( gGAIPerf_OutputFilePath );
- require_action( context->outputFilePath, exit, err = kNoMemoryErr );
- }
-
- context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gGAIPerf_OutputFormat, &err,
- kOutputFormatStr_JSON, kOutputFormatType_JSON,
- kOutputFormatStr_XML, kOutputFormatType_XML,
- kOutputFormatStr_Binary, kOutputFormatType_Binary,
- NULL );
- require_noerr_quiet( err, exit );
-
- err = GAITesterCreate( dispatch_get_main_queue(), (int) context->callDelayMs, (int) context->serverDelayMs,
- kGAIPerfStandardTTL, context->skipPathEval, context->badUDPMode, &context->tester );
- require_noerr( err, exit );
-
- check( gGAIPerf_TestSuite );
- if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Basic ) == 0 )
- {
- err = GAIPerfAddBasicTestCases( context );
- require_noerr( err, exit );
- }
- else if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Advanced ) == 0 )
- {
- err = GAIPerfAddAdvancedTestCases( context );
- require_noerr( err, exit );
- }
- else
- {
- FPrintF( stderr, "error: Invalid test suite name: %s.\n", gGAIPerf_TestSuite );
- err = kParamErr;
- goto exit;
- }
-
- GAITesterSetStopHandler( context->tester, GAIPerfTesterStopHandler, context );
- GAITesterSetResultsHandler( context->tester, GAIPerfResultsHandler, context );
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, GAIPerfSignalHandler, context, &context->sigIntSource );
- require_noerr( err, exit );
- dispatch_resume( context->sigIntSource );
-
- signal( SIGTERM, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGTERM, GAIPerfSignalHandler, context, &context->sigTermSource );
- require_noerr( err, exit );
- dispatch_resume( context->sigTermSource );
-
- GAITesterStart( context->tester );
- dispatch_main();
-
-exit:
- if( context ) GAIPerfContextFree( context );
- exit( 1 );
-}
-
-//===========================================================================================================================
-// GAIPerfContextFree
-//===========================================================================================================================
-
-static void GAIPerfContextFree( GAIPerfContext *inContext )
-{
- ForgetCF( &inContext->tester );
- ForgetCF( &inContext->testCaseResults );
- ForgetMem( &inContext->outputFilePath );
- dispatch_source_forget( &inContext->sigIntSource );
- dispatch_source_forget( &inContext->sigTermSource );
- free( inContext );
-}
-
-//===========================================================================================================================
-// GAIPerfAddAdvancedTestCases
-//===========================================================================================================================
-
-#define kTestCaseTitleBufferSize 128
-
-static void
- _GAIPerfWriteTestCaseTitle(
- char inBuffer[ kTestCaseTitleBufferSize ],
- unsigned int inCNAMERecordCount,
- unsigned int inARecordCount,
- unsigned int inAAAARecordCount,
- GAITestAddrType inRequested,
- unsigned int inIterationCount,
- Boolean inIterationsAreUnique );
-static void
- _GAIPerfWriteLocalHostTestCaseTitle(
- char inBuffer[ kTestCaseTitleBufferSize ],
- GAITestAddrType inRequested,
- unsigned int inIterationCount );
-
-#define kGAIPerfAdvancedTestSuite_MaxAliasCount 4
-#define kGAIPerfAdvancedTestSuite_MaxAddrCount 8
-
-static OSStatus GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext )
-{
- OSStatus err;
- unsigned int aliasCount, addressCount, i;
- GAITestCase * testCase = NULL;
- char title[ kTestCaseTitleBufferSize ];
-
- aliasCount = 0;
- while( aliasCount <= kGAIPerfAdvancedTestSuite_MaxAliasCount )
- {
- for( addressCount = 1; addressCount <= kGAIPerfAdvancedTestSuite_MaxAddrCount; addressCount *= 2 )
- {
- // Add a test case to resolve a domain name with
- //
- // <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
- //
- // to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which
- // requires server queries.
-
- _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
- inContext->defaultIterCount, true );
-
- err = GAITestCaseCreate( title, &testCase );
- require_noerr( err, exit );
-
- for( i = 0; i < inContext->defaultIterCount; ++i )
- {
- err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
- kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs, 1 );
- require_noerr( err, exit );
- }
-
- err = GAITesterAddTestCase( inContext->tester, testCase );
- require_noerr( err, exit );
- testCase = NULL;
-
- // Add a test case to resolve a domain name with
- //
- // <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
- //
- // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique domain name, which requires a server
- // query. The subsequent iterations resolve the same domain name as the preliminary iteration, which should
- // ideally require no server queries, i.e., the results should come from the cache.
-
- _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
- inContext->defaultIterCount, false );
-
- err = GAITestCaseCreate( title, &testCase );
- require_noerr( err, exit );
-
- err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
- kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs, inContext->defaultIterCount + 1 );
- require_noerr( err, exit );
-
- err = GAITesterAddTestCase( inContext->tester, testCase );
- require_noerr( err, exit );
- testCase = NULL;
- }
-
- aliasCount = ( aliasCount == 0 ) ? 1 : ( 2 * aliasCount );
- }
-
- // Finally, add a test case to resolve localhost to its IPv4 and IPv6 addresses.
-
- _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
-
- err = GAITestCaseCreate( title, &testCase );
- require_noerr( err, exit );
-
- err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs,
- inContext->defaultIterCount );
- require_noerr( err, exit );
-
- err = GAITesterAddTestCase( inContext->tester, testCase );
- require_noerr( err, exit );
- testCase = NULL;
-
-exit:
- if( testCase ) GAITestCaseFree( testCase );
- return( err );
-}
-
-//===========================================================================================================================
-// _GAIPerfWriteTestCaseTitle
-//===========================================================================================================================
-
-#define GAITestAddrTypeToRequestKeyValue( X ) ( \
- ( (X) == kGAITestAddrType_Both ) ? "ipv4\\,ipv6" : \
- ( (X) == kGAITestAddrType_IPv4 ) ? "ipv4" : \
- ( (X) == kGAITestAddrType_IPv6 ) ? "ipv6" : \
- "" )
-
-static void
- _GAIPerfWriteTestCaseTitle(
- char inBuffer[ kTestCaseTitleBufferSize ],
- unsigned int inCNAMERecordCount,
- unsigned int inARecordCount,
- unsigned int inAAAARecordCount,
- GAITestAddrType inRequested,
- unsigned int inIterationCount,
- Boolean inIterationsAreUnique )
-{
- SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=dynamic,cname=%u,a=%u,aaaa=%u,req=%s,iterations=%u%?s",
- inCNAMERecordCount, inARecordCount, inAAAARecordCount, GAITestAddrTypeToRequestKeyValue( inRequested ),
- inIterationCount, inIterationsAreUnique, ",unique" );
-}
-
-//===========================================================================================================================
-// _GAIPerfWriteLocalHostTestCaseTitle
-//===========================================================================================================================
-
-static void
- _GAIPerfWriteLocalHostTestCaseTitle(
- char inBuffer[ kTestCaseTitleBufferSize ],
- GAITestAddrType inRequested,
- unsigned int inIterationCount )
-{
- SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=localhost,req=%s,iterations=%u",
- GAITestAddrTypeToRequestKeyValue( inRequested ), inIterationCount );
-}
-
-//===========================================================================================================================
-// GAIPerfAddBasicTestCases
-//===========================================================================================================================
-
-#define kGAIPerfBasicTestSuite_AliasCount 2
-#define kGAIPerfBasicTestSuite_AddrCount 4
-
-static OSStatus GAIPerfAddBasicTestCases( GAIPerfContext *inContext )
-{
- OSStatus err;
- GAITestCase * testCase = NULL;
- char title[ kTestCaseTitleBufferSize ];
- unsigned int i;
-
- // Test Case #1:
- // Resolve a domain name with
- //
- // 2 CNAME records, 4 A records, and 4 AAAA records
- //
- // to its IPv4 and IPv6 addresses. Each of the iterations resolves a unique domain name, which requires server
- // queries.
-
- _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
- kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
- inContext->defaultIterCount, true );
-
- err = GAITestCaseCreate( title, &testCase );
- require_noerr( err, exit );
-
- for( i = 0; i < inContext->defaultIterCount; ++i )
- {
- err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
- kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs, 1 );
- require_noerr( err, exit );
- }
-
- err = GAITesterAddTestCase( inContext->tester, testCase );
- require_noerr( err, exit );
- testCase = NULL;
-
- // Test Case #2:
- // Resolve a domain name with
- //
- // 2 CNAME records, 4 A records, and 4 AAAA records
- //
- // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which
- // requires server queries. Each of the subsequent iterations resolves the same domain name as the preliminary
- // iteration, which should ideally require no additional server queries, i.e., the results should come from the cache.
-
- _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
- kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
- inContext->defaultIterCount, false );
-
- err = GAITestCaseCreate( title, &testCase );
- require_noerr( err, exit );
-
- err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
- kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs,
- inContext->defaultIterCount + 1 );
- require_noerr( err, exit );
-
- err = GAITesterAddTestCase( inContext->tester, testCase );
- require_noerr( err, exit );
- testCase = NULL;
-
- // Test Case #3:
- // Each iteration resolves localhost to its IPv4 and IPv6 addresses.
-
- _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
-
- err = GAITestCaseCreate( title, &testCase );
- require_noerr( err, exit );
-
- err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs,
- inContext->defaultIterCount );
- require_noerr( err, exit );
-
- err = GAITesterAddTestCase( inContext->tester, testCase );
- require_noerr( err, exit );
- testCase = NULL;
-
-exit:
- if( testCase ) GAITestCaseFree( testCase );
- return( err );
-}
-
-//===========================================================================================================================
-// GAIPerfTesterStopHandler
-//===========================================================================================================================
-
-#define kGAIPerfResultsKey_Info CFSTR( "info" )
-#define kGAIPerfResultsKey_TestCases CFSTR( "testCases" )
-#define kGAIPerfResultsKey_Success CFSTR( "success" )
-
-#define kGAIPerfInfoKey_CallDelay CFSTR( "callDelayMs" )
-#define kGAIPerfInfoKey_ServerDelay CFSTR( "serverDelayMs" )
-#define kGAIPerfInfoKey_SkippedPathEval CFSTR( "skippedPathEval" )
-#define kGAIPerfInfoKey_UsedBadUDPMode CFSTR( "usedBadUPDMode" )
-
-static void GAIPerfTesterStopHandler( void *inContext, OSStatus inError )
-{
- OSStatus err;
- GAIPerfContext * const context = (GAIPerfContext *) inContext;
- CFPropertyListRef plist;
- int exitCode;
-
- err = inError;
- require_noerr_quiet( err, exit );
-
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
- "{"
- "%kO=" // info
- "{"
- "%kO=%lli" // callDelayMs
- "%kO=%lli" // serverDelayMs
- "%kO=%b" // skippedPathEval
- "%kO=%b" // usedBadUPDMode
- "}"
- "%kO=%O" // testCases
- "%kO=%b" // success
- "}",
- kGAIPerfResultsKey_Info,
- kGAIPerfInfoKey_CallDelay, (int64_t) context->callDelayMs,
- kGAIPerfInfoKey_ServerDelay, (int64_t) context->serverDelayMs,
- kGAIPerfInfoKey_SkippedPathEval, context->skipPathEval,
- kGAIPerfInfoKey_UsedBadUDPMode, context->badUDPMode,
- kGAIPerfResultsKey_TestCases, context->testCaseResults,
- kGAIPerfResultsKey_Success, !context->testFailed );
- require_noerr( err, exit );
-
- err = OutputPropertyList( plist, context->outputFormat, context->appendNewline, context->outputFilePath );
- CFRelease( plist );
- require_noerr( err, exit );
-
-exit:
- exitCode = err ? 1 : ( context->testFailed ? 2 : 0 );
- GAIPerfContextFree( context );
- exit( exitCode );
-}
-
-//===========================================================================================================================
-// GAIPerfResultsHandler
-//===========================================================================================================================
-
-// Keys for test case dictionary
-
-#define kGAIPerfTestCaseKey_Title CFSTR( "title" )
-#define kGAIPerfTestCaseKey_StartTime CFSTR( "startTime" )
-#define kGAIPerfTestCaseKey_EndTime CFSTR( "endTime" )
-#define kGAIPerfTestCaseKey_Results CFSTR( "results" )
-#define kGAIPerfTestCaseKey_FirstStats CFSTR( "firstStats" )
-#define kGAIPerfTestCaseKey_ConnectionStats CFSTR( "connectionStats" )
-#define kGAIPerfTestCaseKey_Stats CFSTR( "stats" )
-
-// Keys for test case results array entry dictionaries
-
-#define kGAIPerfTestCaseResultKey_Name CFSTR( "name" )
-#define kGAIPerfTestCaseResultKey_ConnectionTime CFSTR( "connectionTimeUs" )
-#define kGAIPerfTestCaseResultKey_FirstTime CFSTR( "firstTimeUs" )
-#define kGAIPerfTestCaseResultKey_Time CFSTR( "timeUs" )
-
-// Keys for test case stats dictionaries
-
-#define kGAIPerfTestCaseStatsKey_Count CFSTR( "count" )
-#define kGAIPerfTestCaseStatsKey_Min CFSTR( "min" )
-#define kGAIPerfTestCaseStatsKey_Max CFSTR( "max" )
-#define kGAIPerfTestCaseStatsKey_Mean CFSTR( "mean" )
-#define kGAIPerfTestCaseStatsKey_StdDev CFSTR( "sd" )
-
-typedef struct
-{
- double min;
- double max;
- double mean;
- double stdDev;
-
-} GAIPerfStats;
-
-#define GAIPerfStatsInit( X ) \
- do { (X)->min = DBL_MAX; (X)->max = DBL_MIN; (X)->mean = 0.0; (X)->stdDev = 0.0; } while( 0 )
-
-static void
- GAIPerfResultsHandler(
- const char * inCaseTitle,
- NanoTime64 inCaseStartTime,
- NanoTime64 inCaseEndTime,
- const GAITestItemResult * inResultArray,
- size_t inResultCount,
- void * inContext )
-{
- OSStatus err;
- GAIPerfContext * const context = (GAIPerfContext *) inContext;
- int namesAreDynamic, namesAreUnique;
- const char * ptr;
- size_t count, startIndex;
- CFMutableArrayRef results = NULL;
- GAIPerfStats stats, firstStats, connStats;
- double sum, firstSum, connSum;
- size_t keyValueLen, i;
- char keyValue[ 16 ]; // Size must be at least strlen( "name=dynamic" ) + 1 bytes.
- char startTimeStr[ 32 ];
- char endTimeStr[ 32 ];
- const GAITestItemResult * result;
-
- // If this test case resolves the same "d.test." name in each iteration (title contains the "name=dynamic" key-value
- // pair, but not the "unique" key), then don't count the first iteration, whose purpose is to populate the cache with
- // the domain name's CNAME, A, and AAAA records.
-
- namesAreDynamic = false;
- namesAreUnique = false;
- ptr = inCaseTitle;
- while( ParseQuotedEscapedString( ptr, NULL, ",", keyValue, sizeof( keyValue ), &keyValueLen, NULL, &ptr ) )
- {
- if( strnicmpx( keyValue, keyValueLen, "name=dynamic" ) == 0 )
- {
- namesAreDynamic = true;
- }
- else if( strnicmpx( keyValue, keyValueLen, "unique" ) == 0 )
- {
- namesAreUnique = true;
- }
- if( namesAreDynamic && namesAreUnique ) break;
- }
-
- startIndex = ( ( inResultCount > 0 ) && namesAreDynamic && !namesAreUnique ) ? 1 : 0;
- results = CFArrayCreateMutable( NULL, (CFIndex)( inResultCount - startIndex ), &kCFTypeArrayCallBacks );
- require_action( results, exit, err = kNoMemoryErr );
-
- GAIPerfStatsInit( &stats );
- GAIPerfStatsInit( &firstStats );
- GAIPerfStatsInit( &connStats );
-
- sum = 0.0;
- firstSum = 0.0;
- connSum = 0.0;
- count = 0;
- for( i = startIndex; i < inResultCount; ++i )
- {
- double value;
-
- result = &inResultArray[ i ];
-
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, results,
- "{"
- "%kO=%s" // name
- "%kO=%lli" // connectionTimeUs
- "%kO=%lli" // firstTimeUs
- "%kO=%lli" // timeUs
- "%kO=%lli" // error
- "}",
- kGAIPerfTestCaseResultKey_Name, result->name,
- kGAIPerfTestCaseResultKey_ConnectionTime, (int64_t) result->connectionTimeUs,
- kGAIPerfTestCaseResultKey_FirstTime, (int64_t) result->firstTimeUs,
- kGAIPerfTestCaseResultKey_Time, (int64_t) result->timeUs,
- CFSTR( "error" ), (int64_t) result->error );
- require_noerr( err, exit );
-
- if( !result->error )
- {
- value = (double) result->timeUs;
- if( value < stats.min ) stats.min = value;
- if( value > stats.max ) stats.max = value;
- sum += value;
-
- value = (double) result->firstTimeUs;
- if( value < firstStats.min ) firstStats.min = value;
- if( value > firstStats.max ) firstStats.max = value;
- firstSum += value;
-
- value = (double) result->connectionTimeUs;
- if( value < connStats.min ) connStats.min = value;
- if( value > connStats.max ) connStats.max = value;
- connSum += value;
-
- ++count;
- }
- else
- {
- context->testFailed = true;
- }
- }
-
- if( count > 0 )
- {
- stats.mean = sum / count;
- firstStats.mean = firstSum / count;
- connStats.mean = connSum / count;
-
- sum = 0.0;
- firstSum = 0.0;
- connSum = 0.0;
- for( i = startIndex; i < inResultCount; ++i )
- {
- double diff;
-
- result = &inResultArray[ i ];
- if( result->error ) continue;
-
- diff = stats.mean - (double) result->timeUs;
- sum += ( diff * diff );
-
- diff = firstStats.mean - (double) result->firstTimeUs;
- firstSum += ( diff * diff );
-
- diff = connStats.mean - (double) result->connectionTimeUs;
- connSum += ( diff * diff );
- }
- stats.stdDev = sqrt( sum / count );
- firstStats.stdDev = sqrt( firstSum / count );
- connStats.stdDev = sqrt( connSum / count );
- }
-
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->testCaseResults,
- "{"
- "%kO=%s"
- "%kO=%s"
- "%kO=%s"
- "%kO=%O"
- "%kO="
- "{"
- "%kO=%lli"
- "%kO=%f"
- "%kO=%f"
- "%kO=%f"
- "%kO=%f"
- "}"
- "%kO="
- "{"
- "%kO=%lli"
- "%kO=%f"
- "%kO=%f"
- "%kO=%f"
- "%kO=%f"
- "}"
- "%kO="
- "{"
- "%kO=%lli"
- "%kO=%f"
- "%kO=%f"
- "%kO=%f"
- "%kO=%f"
- "}"
- "}",
- kGAIPerfTestCaseKey_Title, inCaseTitle,
- kGAIPerfTestCaseKey_StartTime, _NanoTime64ToDateString( inCaseStartTime, startTimeStr, sizeof( startTimeStr ) ),
- kGAIPerfTestCaseKey_EndTime, _NanoTime64ToDateString( inCaseEndTime, endTimeStr, sizeof( endTimeStr ) ),
- kGAIPerfTestCaseKey_Results, results,
- kGAIPerfTestCaseKey_Stats,
- kGAIPerfTestCaseStatsKey_Count, (int64_t) count,
- kGAIPerfTestCaseStatsKey_Min, stats.min,
- kGAIPerfTestCaseStatsKey_Max, stats.max,
- kGAIPerfTestCaseStatsKey_Mean, stats.mean,
- kGAIPerfTestCaseStatsKey_StdDev, stats.stdDev,
- kGAIPerfTestCaseKey_FirstStats,
- kGAIPerfTestCaseStatsKey_Count, (int64_t) count,
- kGAIPerfTestCaseStatsKey_Min, firstStats.min,
- kGAIPerfTestCaseStatsKey_Max, firstStats.max,
- kGAIPerfTestCaseStatsKey_Mean, firstStats.mean,
- kGAIPerfTestCaseStatsKey_StdDev, firstStats.stdDev,
- kGAIPerfTestCaseKey_ConnectionStats,
- kGAIPerfTestCaseStatsKey_Count, (int64_t) count,
- kGAIPerfTestCaseStatsKey_Min, connStats.min,
- kGAIPerfTestCaseStatsKey_Max, connStats.max,
- kGAIPerfTestCaseStatsKey_Mean, connStats.mean,
- kGAIPerfTestCaseStatsKey_StdDev, connStats.stdDev );
- require_noerr( err, exit );
-
-exit:
- CFReleaseNullSafe( results );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// GAIPerfSignalHandler
-//===========================================================================================================================
-
-static void GAIPerfSignalHandler( void *inContext )
-{
- GAIPerfContext * const context = (GAIPerfContext *) inContext;
-
- if( !context->tester ) exit( 1 );
- GAITesterStop( context->tester );
- context->tester = NULL;
-}
-
-//===========================================================================================================================
-// GAITesterCreate
-//===========================================================================================================================
-
-// A character set of lower-case alphabet characters and digits and a string length of six allows for 36^6 = 2,176,782,336
-// possible strings to use in the Tag label.
-
-#define kGAITesterTagStringLen 6
-
-typedef struct GAITestItem GAITestItem;
-struct GAITestItem
-{
- GAITestItem * next; // Next test item in list.
- char * name; // Domain name to resolve.
- uint64_t connectionTimeUs; // Time in microseconds that it took to create a DNS-SD connection.
- uint64_t firstTimeUs; // Time in microseconds that it took to get the first address result.
- uint64_t timeUs; // Time in microseconds that it took to get all expected address results.
- unsigned int addressCount; // Address count of the domain name, i.e., the Count label argument.
- OSStatus error; // Current status/error.
- unsigned int timeLimitMs; // Time limit in milliseconds for the test item's completion.
- Boolean hasV4; // True if the domain name has one or more IPv4 addresses.
- Boolean hasV6; // True if the domain name has one or more IPv6 addresses.
- Boolean wantV4; // True if DNSServiceGetAddrInfo() should be called to get IPv4 addresses.
- Boolean wantV6; // True if DNSServiceGetAddrInfo() should be called to get IPv6 addresses.
-};
-
-struct GAITestCase
-{
- GAITestCase * next; // Next test case in list.
- GAITestItem * itemList; // List of test items.
- char * title; // Title of the test case.
-};
-
-struct GAITesterPrivate
-{
- CFRuntimeBase base; // CF object base.
- dispatch_queue_t queue; // Serial work queue.
- DNSServiceRef connection; // Reference to the shared DNS-SD connection.
- DNSServiceRef getAddrInfo; // Reference to the current DNSServiceGetAddrInfo operation.
- GAITestCase * caseList; // List of test cases.
- GAITestCase * currentCase; // Pointer to the current test case.
- GAITestItem * currentItem; // Pointer to the current test item.
- NanoTime64 caseStartTime; // Start time of current test case in Unix time as nanoseconds.
- NanoTime64 caseEndTime; // End time of current test case in Unix time as nanoseconds.
- int callDelayMs; // Amount of time to wait before calling DNSServiceGetAddrInfo().
- Boolean skipPathEval; // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
- Boolean stopped; // True if the tester has been stopped.
- Boolean badUDPMode; // True if the test DNS server is to run in Bad UDP mode.
- dispatch_source_t timer; // Timer for enforcing a test item's time limit.
- pcap_t * pcap; // Captures traffic between mDNSResponder and test DNS server.
- pid_t serverPID; // PID of the test DNS server.
- int serverDelayMs; // Additional time to have the server delay its responses by.
- int serverDefaultTTL; // Default TTL for the server's records.
- GAITesterStopHandler_f stopHandler; // User's stop handler.
- void * stopContext; // User's event handler context.
- GAITesterResultsHandler_f resultsHandler; // User's results handler.
- void * resultsContext; // User's results handler context.
-
- // Variables for current test item.
-
- uint64_t bitmapV4; // Bitmap of IPv4 results that have yet to be received.
- uint64_t bitmapV6; // Bitmap of IPv6 results that have yet to be received.
- uint64_t startTicks; // Start ticks of DNSServiceGetAddrInfo().
- uint64_t connTicks; // Ticks when the connection was created.
- uint64_t firstTicks; // Ticks when the first DNSServiceGetAddrInfo result was received.
- uint64_t endTicks; // Ticks when the last DNSServiceGetAddrInfo result was received.
- Boolean gotFirstResult; // True if the first result has been received.
-};
-
-CF_CLASS_DEFINE( GAITester );
-
-static void _GAITesterStartNextTest( GAITesterRef inTester );
-static OSStatus _GAITesterCreatePacketCapture( pcap_t **outPCap );
-static void _GAITesterFirstGAITimeout( void *inContext );
-static void _GAITesterTimeout( void *inContext );
-static void DNSSD_API
- _GAITesterFirstGAICallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext );
-static void DNSSD_API
- _GAITesterGetAddrInfoCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext );
-static void _GAITesterCompleteCurrentTest( GAITesterRef inTester, OSStatus inError );
-
-#define ForgetPacketCapture( X ) ForgetCustom( X, pcap_close )
-
-static OSStatus
- GAITestItemCreate(
- const char * inName,
- unsigned int inAddressCount,
- GAITestAddrType inHasAddrs,
- GAITestAddrType inWantAddrs,
- unsigned int inTimeLimitMs,
- GAITestItem ** outItem );
-static OSStatus GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem );
-static void GAITestItemFree( GAITestItem *inItem );
-
-static OSStatus
- GAITesterCreate(
- dispatch_queue_t inQueue,
- int inCallDelayMs,
- int inServerDelayMs,
- int inServerDefaultTTL,
- Boolean inSkipPathEvaluation,
- Boolean inBadUDPMode,
- GAITesterRef * outTester )
-{
- OSStatus err;
- GAITesterRef obj = NULL;
-
- CF_OBJECT_CREATE( GAITester, obj, err, exit );
-
- ReplaceDispatchQueue( &obj->queue, inQueue );
- obj->callDelayMs = inCallDelayMs;
- obj->serverPID = -1;
- obj->serverDelayMs = inServerDelayMs;
- obj->serverDefaultTTL = inServerDefaultTTL;
- obj->skipPathEval = inSkipPathEvaluation;
- obj->badUDPMode = inBadUDPMode;
-
- *outTester = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- CFReleaseNullSafe( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _GAITesterFinalize
-//===========================================================================================================================
-
-static void _GAITesterFinalize( CFTypeRef inObj )
-{
- GAITesterRef const me = (GAITesterRef) inObj;
- GAITestCase * testCase;
-
- check( !me->getAddrInfo );
- check( !me->connection );
- check( !me->timer );
- dispatch_forget( &me->queue );
- while( ( testCase = me->caseList ) != NULL )
- {
- me->caseList = testCase->next;
- GAITestCaseFree( testCase );
- }
-}
-
-//===========================================================================================================================
-// GAITesterStart
-//===========================================================================================================================
-
-static void _GAITesterStart( void *inContext );
-static void _GAITesterStop( GAITesterRef me, OSStatus inError );
-
-static void GAITesterStart( GAITesterRef me )
-{
- CFRetain( me );
- dispatch_async_f( me->queue, me, _GAITesterStart );
-}
-
-#define kGAITesterFirstGAITimeoutSecs 4
-
-static void _GAITesterStart( void *inContext )
-{
- OSStatus err;
- GAITesterRef const me = (GAITesterRef) inContext;
- DNSServiceFlags flags;
- char name[ 64 ];
- char tag[ kGAITesterTagStringLen + 1 ];
-
- err = SpawnCommand( &me->serverPID, "dnssdutil server --loopback --follow %lld%?s%?d%?s%?d%?s",
- (int64_t) getpid(),
- me->serverDefaultTTL >= 0, " --defaultTTL ",
- me->serverDefaultTTL >= 0, me->serverDefaultTTL,
- me->serverDelayMs >= 0, " --responseDelay ",
- me->serverDelayMs >= 0, me->serverDelayMs,
- me->badUDPMode, " --badUDPMode" );
- require_noerr_quiet( err, exit );
-
- SNPrintF( name, sizeof( name ), "tag-gaitester-probe-%s.ipv4.d.test",
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
-
- flags = 0;
- if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
-
- err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, kDNSServiceProtocol_IPv4, name,
- _GAITesterFirstGAICallback, me );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( me->getAddrInfo, me->queue );
- require_noerr( err, exit );
-
- err = DispatchTimerOneShotCreate( dispatch_time_seconds( kGAITesterFirstGAITimeoutSecs ),
- UINT64_C_safe( kGAITesterFirstGAITimeoutSecs ) * kNanosecondsPerSecond / 10, me->queue,
- _GAITesterFirstGAITimeout, me, &me->timer );
- require_noerr( err, exit );
- dispatch_resume( me->timer );
-
-exit:
- if( err ) _GAITesterStop( me, err );
-}
-
-//===========================================================================================================================
-// GAITesterStop
-//===========================================================================================================================
-
-static void _GAITesterUserStop( void *inContext );
-
-static void GAITesterStop( GAITesterRef me )
-{
- CFRetain( me );
- dispatch_async_f( me->queue, me, _GAITesterUserStop );
-}
-
-static void _GAITesterUserStop( void *inContext )
-{
- GAITesterRef const me = (GAITesterRef) inContext;
-
- _GAITesterStop( me, kCanceledErr );
- CFRelease( me );
-}
-
-static void _GAITesterStop( GAITesterRef me, OSStatus inError )
-{
- OSStatus err;
-
- ForgetPacketCapture( &me->pcap );
- dispatch_source_forget( &me->timer );
- DNSServiceForget( &me->getAddrInfo );
- DNSServiceForget( &me->connection );
- if( me->serverPID != -1 )
- {
- err = kill( me->serverPID, SIGTERM );
- err = map_global_noerr_errno( err );
- check_noerr( err );
- me->serverPID = -1;
- }
-
- if( !me->stopped )
- {
- me->stopped = true;
- if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
- CFRelease( me );
- }
-}
-
-//===========================================================================================================================
-// GAITesterAddTestCase
-//===========================================================================================================================
-
-static OSStatus GAITesterAddTestCase( GAITesterRef me, GAITestCase *inCase )
-{
- OSStatus err;
- GAITestCase ** ptr;
-
- require_action_quiet( inCase->itemList, exit, err = kCountErr );
-
- for( ptr = &me->caseList; *ptr; ptr = &( *ptr )->next ) {}
- *ptr = inCase;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// GAITesterSetStopHandler
-//===========================================================================================================================
-
-static void GAITesterSetStopHandler( GAITesterRef me, GAITesterStopHandler_f inStopHandler, void *inStopContext )
-{
- me->stopHandler = inStopHandler;
- me->stopContext = inStopContext;
-}
-
-//===========================================================================================================================
-// GAITesterSetResultsHandler
-//===========================================================================================================================
-
-static void GAITesterSetResultsHandler( GAITesterRef me, GAITesterResultsHandler_f inResultsHandler, void *inResultsContext )
-{
- me->resultsHandler = inResultsHandler;
- me->resultsContext = inResultsContext;
-}
-
-//===========================================================================================================================
-// _GAITesterStartNextTest
-//===========================================================================================================================
-
-static void _GAITesterStartNextTest( GAITesterRef me )
-{
- OSStatus err;
- GAITestItem * item;
- DNSServiceFlags flags;
- DNSServiceProtocol protocols;
- int done = false;
-
- if( me->currentItem ) me->currentItem = me->currentItem->next;
-
- if( !me->currentItem )
- {
- if( me->currentCase )
- {
- // No more test items means that the current test case has completed.
-
- me->caseEndTime = NanoTimeGetCurrent();
-
- if( me->resultsHandler )
- {
- size_t resultCount, i;
- GAITestItemResult * resultArray;
-
- resultCount = 0;
- for( item = me->currentCase->itemList; item; item = item->next ) ++resultCount;
- check( resultCount > 0 );
-
- resultArray = (GAITestItemResult *) calloc( resultCount, sizeof( *resultArray ) );
- require_action( resultArray, exit, err = kNoMemoryErr );
-
- item = me->currentCase->itemList;
- for( i = 0; i < resultCount; ++i )
- {
- resultArray[ i ].name = item->name;
- resultArray[ i ].connectionTimeUs = item->connectionTimeUs;
- resultArray[ i ].firstTimeUs = item->firstTimeUs;
- resultArray[ i ].timeUs = item->timeUs;
- resultArray[ i ].error = item->error;
- item = item->next;
- }
- me->resultsHandler( me->currentCase->title, me->caseStartTime, me->caseEndTime, resultArray, resultCount,
- me->resultsContext );
- ForgetMem( &resultArray );
- }
-
- me->currentCase = me->currentCase->next;
- if( !me->currentCase )
- {
- done = true;
- err = kNoErr;
- goto exit;
- }
- }
- else
- {
- me->currentCase = me->caseList;
- }
- require_action_quiet( me->currentCase->itemList, exit, err = kInternalErr );
- me->currentItem = me->currentCase->itemList;
- }
-
- item = me->currentItem;
- check( ( item->addressCount >= 1 ) && ( item->addressCount <= 64 ) );
-
- if( !item->wantV4 ) me->bitmapV4 = 0;
- else if( !item->hasV4 ) me->bitmapV4 = 1;
- else if( item->addressCount < 64 ) me->bitmapV4 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
- else me->bitmapV4 = ~UINT64_C( 0 );
-
- if( !item->wantV6 ) me->bitmapV6 = 0;
- else if( !item->hasV6 ) me->bitmapV6 = 1;
- else if( item->addressCount < 64 ) me->bitmapV6 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
- else me->bitmapV6 = ~UINT64_C( 0 );
- check( ( me->bitmapV4 != 0 ) || ( me->bitmapV6 != 0 ) );
- me->gotFirstResult = false;
-
- // Perform preliminary tasks if this is the start of a new test case.
-
- if( item == me->currentCase->itemList )
- {
- // Flush mDNSResponder's cache.
-
- err = systemf( NULL, "killall -HUP mDNSResponder" );
- require_noerr( err, exit );
- sleep( 1 );
-
- me->caseStartTime = NanoTimeGetCurrent();
- me->caseEndTime = kNanoTime_Invalid;
- }
-
- // Start a packet capture.
-
- check( !me->pcap );
- err = _GAITesterCreatePacketCapture( &me->pcap );
- require_noerr( err, exit );
-
- // Start timer for test item's time limit.
-
- check( !me->timer );
- if( item->timeLimitMs > 0 )
- {
- unsigned int timeLimitMs;
-
- timeLimitMs = item->timeLimitMs;
- if( me->callDelayMs > 0 ) timeLimitMs += (unsigned int) me->callDelayMs;
- if( me->serverDelayMs > 0 ) timeLimitMs += (unsigned int) me->serverDelayMs;
-
- err = DispatchTimerCreate( dispatch_time_milliseconds( timeLimitMs ), DISPATCH_TIME_FOREVER,
- ( (uint64_t) timeLimitMs ) * kNanosecondsPerMillisecond / 10,
- me->queue, _GAITesterTimeout, NULL, me, &me->timer );
- require_noerr( err, exit );
- dispatch_resume( me->timer );
- }
-
- // Call DNSServiceGetAddrInfo().
-
- if( me->callDelayMs > 0 ) usleep( ( (useconds_t) me->callDelayMs ) * kMicrosecondsPerMillisecond );
-
- flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
- if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
-
- protocols = 0;
- if( item->wantV4 ) protocols |= kDNSServiceProtocol_IPv4;
- if( item->wantV6 ) protocols |= kDNSServiceProtocol_IPv6;
-
- me->startTicks = UpTicks();
-
- check( !me->connection );
- err = DNSServiceCreateConnection( &me->connection );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( me->connection, me->queue );
- require_noerr( err, exit );
-
- me->connTicks = UpTicks();
-
- check( !me->getAddrInfo );
- me->getAddrInfo = me->connection;
- err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, protocols, item->name,
- _GAITesterGetAddrInfoCallback, me );
- require_noerr( err, exit );
-
-exit:
- if( err || done ) _GAITesterStop( me, err );
-}
-
-//===========================================================================================================================
-// _GAITesterCreatePacketCapture
-//===========================================================================================================================
-
-static OSStatus _GAITesterCreatePacketCapture( pcap_t **outPCap )
-{
- OSStatus err;
- pcap_t * pcap;
- struct bpf_program program;
- char errBuf[ PCAP_ERRBUF_SIZE ];
-
- pcap = pcap_create( "lo0", errBuf );
- require_action_string( pcap, exit, err = kUnknownErr, errBuf );
-
- err = pcap_set_buffer_size( pcap, 512 * kBytesPerKiloByte );
- require_noerr_action( err, exit, err = kUnknownErr );
-
- err = pcap_set_snaplen( pcap, 512 );
- require_noerr_action( err, exit, err = kUnknownErr );
-
- err = pcap_set_immediate_mode( pcap, 0 );
- require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-
- err = pcap_activate( pcap );
- require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-
- err = pcap_setdirection( pcap, PCAP_D_INOUT );
- require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-
- err = pcap_setnonblock( pcap, 1, errBuf );
- require_noerr_action_string( err, exit, err = kUnknownErr, errBuf );
-
- err = pcap_compile( pcap, &program, "udp port 53", 1, PCAP_NETMASK_UNKNOWN );
- require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-
- err = pcap_setfilter( pcap, &program );
- pcap_freecode( &program );
- require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-
- *outPCap = pcap;
- pcap = NULL;
-
-exit:
- if( pcap ) pcap_close( pcap );
- return( err );
-}
-
-//===========================================================================================================================
-// _GAITesterFirstGAITimeout
-//===========================================================================================================================
-
-static void _GAITesterFirstGAITimeout( void *inContext )
-{
- GAITesterRef const me = (GAITesterRef) inContext;
-
- _GAITesterStop( me, kNoResourcesErr );
-}
-
-//===========================================================================================================================
-// _GAITesterTimeout
-//===========================================================================================================================
-
-static void _GAITesterTimeout( void *inContext )
-{
- GAITesterRef const me = (GAITesterRef) inContext;
-
- _GAITesterCompleteCurrentTest( me, kTimeoutErr );
-}
-
-//===========================================================================================================================
-// _GAITesterFirstGAICallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _GAITesterFirstGAICallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext )
-{
- GAITesterRef const me = (GAITesterRef) inContext;
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inHostname );
- Unused( inSockAddr );
- Unused( inTTL );
-
- if( ( inFlags & kDNSServiceFlagsAdd ) && !inError )
- {
- dispatch_source_forget( &me->timer );
- DNSServiceForget( &me->getAddrInfo );
-
- _GAITesterStartNextTest( me );
- }
-}
-
-//===========================================================================================================================
-// _GAITesterGetAddrInfoCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _GAITesterGetAddrInfoCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- GAITesterRef const me = (GAITesterRef) inContext;
- GAITestItem * const item = me->currentItem;
- const sockaddr_ip * const sip = (const sockaddr_ip *) inSockAddr;
- uint64_t nowTicks;
- uint64_t * bitmapPtr;
- uint64_t bitmask;
- int hasAddr;
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inHostname );
- Unused( inTTL );
-
- nowTicks = UpTicks();
-
- require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
-
- // Check if we were expecting an IP address result of this type.
-
- if( sip->sa.sa_family == AF_INET )
- {
- bitmapPtr = &me->bitmapV4;
- hasAddr = item->hasV4;
- }
- else if( sip->sa.sa_family == AF_INET6 )
- {
- bitmapPtr = &me->bitmapV6;
- hasAddr = item->hasV6;
- }
- else
- {
- err = kTypeErr;
- goto exit;
- }
-
- bitmask = 0;
- if( hasAddr )
- {
- uint32_t addrOffset;
-
- require_noerr_action_quiet( inError, exit, err = inError );
-
- if( sip->sa.sa_family == AF_INET )
- {
- const uint32_t addrV4 = ntohl( sip->v4.sin_addr.s_addr );
-
- if( strcasecmp( item->name, "localhost." ) == 0 )
- {
- if( addrV4 == INADDR_LOOPBACK ) bitmask = 1;
- }
- else
- {
- addrOffset = addrV4 - kDNSServerBaseAddrV4;
- if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
- {
- bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
- }
- }
- }
- else
- {
- const uint8_t * const addrV6 = sip->v6.sin6_addr.s6_addr;
-
- if( strcasecmp( item->name, "localhost." ) == 0 )
- {
- if( memcmp( addrV6, in6addr_loopback.s6_addr, 16 ) == 0 ) bitmask = 1;
- }
- else if( memcmp( addrV6, kDNSServerBaseAddrV6, 15 ) == 0 )
- {
- addrOffset = addrV6[ 15 ];
- if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
- {
- bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
- }
- }
- }
- }
- else
- {
- require_action_quiet( inError == kDNSServiceErr_NoSuchRecord, exit, err = inError ? inError : kUnexpectedErr );
- bitmask = 1;
- }
- require_action_quiet( bitmask != 0, exit, err = kValueErr );
- require_action_quiet( *bitmapPtr & bitmask, exit, err = kDuplicateErr );
-
- *bitmapPtr &= ~bitmask;
- if( !me->gotFirstResult )
- {
- me->firstTicks = nowTicks;
- me->gotFirstResult = true;
- }
- err = kNoErr;
-
-exit:
- if( err || ( ( me->bitmapV4 == 0 ) && ( me->bitmapV6 == 0 ) ) )
- {
- me->endTicks = nowTicks;
- _GAITesterCompleteCurrentTest( me, err );
- }
-}
-
-//===========================================================================================================================
-// _GAITesterCompleteCurrentTest
-//===========================================================================================================================
-
-static OSStatus
- _GAITesterGetDNSMessageFromPacket(
- const uint8_t * inPacketPtr,
- size_t inPacketLen,
- const uint8_t ** outMsgPtr,
- size_t * outMsgLen );
-
-static void _GAITesterCompleteCurrentTest( GAITesterRef me, OSStatus inError )
-{
- OSStatus err;
- GAITestItem * const item = me->currentItem;
- struct timeval timeStamps[ 4 ];
- struct timeval * tsPtr;
- struct timeval * tsQA = NULL;
- struct timeval * tsQAAAA = NULL;
- struct timeval * tsRA = NULL;
- struct timeval * tsRAAAA = NULL;
- struct timeval * t1;
- struct timeval * t2;
- int64_t idleTimeUs;
- uint8_t name[ kDomainNameLengthMax ];
-
- dispatch_source_forget( &me->timer );
- DNSServiceForget( &me->getAddrInfo );
- DNSServiceForget( &me->connection );
-
- item->error = inError;
- if( item->error )
- {
- err = kNoErr;
- goto exit;
- }
-
- err = DomainNameFromString( name, item->name, NULL );
- require_noerr( err, exit );
-
- tsPtr = &timeStamps[ 0 ];
- for( ;; )
- {
- int status;
- struct pcap_pkthdr * pktHdr;
- const uint8_t * packet;
- const uint8_t * msgPtr;
- size_t msgLen;
- const DNSHeader * hdr;
- unsigned int flags;
- const uint8_t * ptr;
- uint16_t qtype, qclass;
- uint8_t qname[ kDomainNameLengthMax ];
-
- status = pcap_next_ex( me->pcap, &pktHdr, &packet );
- if( status != 1 ) break;
- if( _GAITesterGetDNSMessageFromPacket( packet, pktHdr->caplen, &msgPtr, &msgLen ) != kNoErr ) continue;
- if( msgLen < kDNSHeaderLength ) continue;
-
- hdr = (const DNSHeader *) msgPtr;
- flags = DNSHeaderGetFlags( hdr );
- if( DNSFlagsGetOpCode( flags ) != kDNSOpCode_Query ) continue;
- if( DNSHeaderGetQuestionCount( hdr ) < 1 ) continue;
-
- ptr = (const uint8_t *) &hdr[ 1 ];
- if( DNSMessageExtractQuestion( msgPtr, msgLen, ptr, qname, &qtype, &qclass, NULL ) != kNoErr ) continue;
- if( qclass != kDNSServiceClass_IN ) continue;
- if( !DomainNameEqual( qname, name ) ) continue;
-
- if( item->wantV4 && ( qtype == kDNSServiceType_A ) )
- {
- if( flags & kDNSHeaderFlag_Response )
- {
- if( tsQA && !tsRA )
- {
- tsRA = tsPtr++;
- *tsRA = pktHdr->ts;
- }
- }
- else if( !tsQA )
- {
- tsQA = tsPtr++;
- *tsQA = pktHdr->ts;
- }
- }
- else if( item->wantV6 && ( qtype == kDNSServiceType_AAAA ) )
- {
- if( flags & kDNSHeaderFlag_Response )
- {
- if( tsQAAAA && !tsRAAAA )
- {
- tsRAAAA = tsPtr++;
- *tsRAAAA = pktHdr->ts;
- }
- }
- else if( !tsQAAAA )
- {
- tsQAAAA = tsPtr++;
- *tsQAAAA = pktHdr->ts;
- }
- }
- }
-
- // t1 is the time when the last query was sent.
-
- if( tsQA && tsQAAAA ) t1 = TIMEVAL_GT( *tsQA, *tsQAAAA ) ? tsQA : tsQAAAA;
- else t1 = tsQA ? tsQA : tsQAAAA;
-
- // t2 is when the first response was received.
-
- if( tsRA && tsRAAAA ) t2 = TIMEVAL_LT( *tsRA, *tsRAAAA ) ? tsRA : tsRAAAA;
- else t2 = tsRA ? tsRA : tsRAAAA;
-
- if( t1 && t2 )
- {
- idleTimeUs = TIMEVAL_USEC64_DIFF( *t2, *t1 );
- if( idleTimeUs < 0 ) idleTimeUs = 0;
- }
- else
- {
- idleTimeUs = 0;
- }
-
- item->connectionTimeUs = UpTicksToMicroseconds( me->connTicks - me->startTicks );
- item->firstTimeUs = UpTicksToMicroseconds( me->firstTicks - me->connTicks ) - (uint64_t) idleTimeUs;
- item->timeUs = UpTicksToMicroseconds( me->endTicks - me->connTicks ) - (uint64_t) idleTimeUs;
-
-exit:
- ForgetPacketCapture( &me->pcap );
- if( err ) _GAITesterStop( me, err );
- else _GAITesterStartNextTest( me );
-}
-
-//===========================================================================================================================
-// _GAITesterGetDNSMessageFromPacket
-//===========================================================================================================================
-
-#define kHeaderSizeNullLink 4
-#define kHeaderSizeIPv4Min 20
-#define kHeaderSizeIPv6 40
-#define kHeaderSizeUDP 8
-
-#define kIPProtocolUDP 0x11
-
-static OSStatus
- _GAITesterGetDNSMessageFromPacket(
- const uint8_t * inPacketPtr,
- size_t inPacketLen,
- const uint8_t ** outMsgPtr,
- size_t * outMsgLen )
-{
- OSStatus err;
- const uint8_t * nullLink;
- uint32_t addressFamily;
- const uint8_t * ip;
- int ipHeaderLen;
- int protocol;
- const uint8_t * msg;
- const uint8_t * const end = &inPacketPtr[ inPacketLen ];
-
- nullLink = &inPacketPtr[ 0 ];
- require_action_quiet( ( end - nullLink ) >= kHeaderSizeNullLink, exit, err = kUnderrunErr );
- addressFamily = ReadHost32( &nullLink[ 0 ] );
-
- ip = &nullLink[ kHeaderSizeNullLink ];
- if( addressFamily == AF_INET )
- {
- require_action_quiet( ( end - ip ) >= kHeaderSizeIPv4Min, exit, err = kUnderrunErr );
- ipHeaderLen = ( ip[ 0 ] & 0x0F ) * 4;
- protocol = ip[ 9 ];
- }
- else if( addressFamily == AF_INET6 )
- {
- require_action_quiet( ( end - ip ) >= kHeaderSizeIPv6, exit, err = kUnderrunErr );
- ipHeaderLen = kHeaderSizeIPv6;
- protocol = ip[ 6 ];
- }
- else
- {
- err = kTypeErr;
- goto exit;
- }
- require_action_quiet( protocol == kIPProtocolUDP, exit, err = kTypeErr );
- require_action_quiet( ( end - ip ) >= ( ipHeaderLen + kHeaderSizeUDP ), exit, err = kUnderrunErr );
-
- msg = &ip[ ipHeaderLen + kHeaderSizeUDP ];
-
- *outMsgPtr = msg;
- *outMsgLen = (size_t)( end - msg );
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// GAITestCaseCreate
-//===========================================================================================================================
-
-static OSStatus GAITestCaseCreate( const char *inTitle, GAITestCase **outCase )
-{
- OSStatus err;
- GAITestCase * obj;
-
- obj = (GAITestCase *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->title = strdup( inTitle );
- require_action( obj->title, exit, err = kNoMemoryErr );
-
- *outCase = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) GAITestCaseFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// GAITestCaseFree
-//===========================================================================================================================
-
-static void GAITestCaseFree( GAITestCase *inCase )
-{
- GAITestItem * item;
-
- while( ( item = inCase->itemList ) != NULL )
- {
- inCase->itemList = item->next;
- GAITestItemFree( item );
- }
- ForgetMem( &inCase->title );
- free( inCase );
-}
-
-//===========================================================================================================================
-// GAITestCaseAddItem
-//===========================================================================================================================
-
-static OSStatus
- GAITestCaseAddItem(
- GAITestCase * inCase,
- unsigned int inAliasCount,
- unsigned int inAddressCount,
- int inTTL,
- GAITestAddrType inHasAddrs,
- GAITestAddrType inWantAddrs,
- unsigned int inTimeLimitMs,
- unsigned int inItemCount )
-{
- OSStatus err;
- GAITestItem * item;
- GAITestItem * item2;
- GAITestItem * newItemList = NULL;
- GAITestItem ** itemPtr;
- char * ptr;
- char * end;
- unsigned int i;
- char name[ 64 ];
- char tag[ kGAITesterTagStringLen + 1 ];
-
- require_action_quiet( inItemCount > 0, exit, err = kNoErr );
-
- // Limit address count to 64 because we use 64-bit bitmaps for keeping track of addresses.
-
- require_action_quiet( ( inAddressCount >= 1 ) && ( inAddressCount <= 64 ), exit, err = kCountErr );
- require_action_quiet( ( inAliasCount >= 0 ) && ( inAliasCount <= INT32_MAX ), exit, err = kCountErr );
- require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
-
- ptr = &name[ 0 ];
- end = &name[ countof( name ) ];
-
- // Add Alias label.
-
- if( inAliasCount == 1 ) SNPrintF_Add( &ptr, end, "alias." );
- else if( inAliasCount >= 2 ) SNPrintF_Add( &ptr, end, "alias-%u.", inAliasCount );
-
- // Add Count label.
-
- SNPrintF_Add( &ptr, end, "count-%u.", inAddressCount );
-
- // Add TTL label.
-
- if( inTTL >= 0 ) SNPrintF_Add( &ptr, end, "ttl-%d.", inTTL );
-
- // Add Tag label.
-
- SNPrintF_Add( &ptr, end, "tag-%s.",
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
-
- // Add IPv4 or IPv6 label if necessary.
-
- if( inHasAddrs == kGAITestAddrType_IPv4 ) SNPrintF_Add( &ptr, end, "ipv4." );
- else if( inHasAddrs == kGAITestAddrType_IPv6 ) SNPrintF_Add( &ptr, end, "ipv6." );
-
- // Finally, add the d.test. labels.
-
- SNPrintF_Add( &ptr, end, "d.test." );
-
- // Create item.
-
- err = GAITestItemCreate( name, inAddressCount, inHasAddrs, inWantAddrs, inTimeLimitMs, &item );
- require_noerr( err, exit );
-
- newItemList = item;
- itemPtr = &item->next;
-
- // Create repeat items.
-
- for( i = 1; i < inItemCount; ++i )
- {
- err = GAITestItemDup( item, &item2 );
- require_noerr( err, exit );
-
- *itemPtr = item2;
- itemPtr = &item2->next;
- }
-
- // Append to test case's item list.
-
- for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
- *itemPtr = newItemList;
- newItemList = NULL;
-
-exit:
- while( ( item = newItemList ) != NULL )
- {
- newItemList = item->next;
- GAITestItemFree( item );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// GAITestCaseAddLocalHostItem
-//===========================================================================================================================
-
-static OSStatus
- GAITestCaseAddLocalHostItem(
- GAITestCase * inCase,
- GAITestAddrType inWantAddrs,
- unsigned int inTimeLimitMs,
- unsigned int inItemCount )
-{
- OSStatus err;
- GAITestItem * item;
- GAITestItem * item2;
- GAITestItem * newItemList = NULL;
- GAITestItem ** itemPtr;
- unsigned int i;
-
- require_action_quiet( inItemCount > 1, exit, err = kNoErr );
-
- err = GAITestItemCreate( "localhost.", 1, kGAITestAddrType_Both, inWantAddrs, inTimeLimitMs, &item );
- require_noerr( err, exit );
-
- newItemList = item;
- itemPtr = &item->next;
-
- // Create repeat items.
-
- for( i = 1; i < inItemCount; ++i )
- {
- err = GAITestItemDup( item, &item2 );
- require_noerr( err, exit );
-
- *itemPtr = item2;
- itemPtr = &item2->next;
- }
-
- for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
- *itemPtr = newItemList;
- newItemList = NULL;
-
-exit:
- while( ( item = newItemList ) != NULL )
- {
- newItemList = item->next;
- GAITestItemFree( item );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// GAITestItemCreate
-//===========================================================================================================================
-
-static OSStatus
- GAITestItemCreate(
- const char * inName,
- unsigned int inAddressCount,
- GAITestAddrType inHasAddrs,
- GAITestAddrType inWantAddrs,
- unsigned int inTimeLimitMs,
- GAITestItem ** outItem )
-{
- OSStatus err;
- GAITestItem * obj = NULL;
-
- require_action_quiet( inAddressCount >= 1, exit, err = kCountErr );
- require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
- require_action_quiet( GAITestAddrTypeIsValid( inWantAddrs ), exit, err = kValueErr );
-
- obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- obj->addressCount = inAddressCount;
- obj->hasV4 = ( inHasAddrs & kGAITestAddrType_IPv4 ) ? true : false;
- obj->hasV6 = ( inHasAddrs & kGAITestAddrType_IPv6 ) ? true : false;
- obj->wantV4 = ( inWantAddrs & kGAITestAddrType_IPv4 ) ? true : false;
- obj->wantV6 = ( inWantAddrs & kGAITestAddrType_IPv6 ) ? true : false;
- obj->error = kInProgressErr;
- obj->timeLimitMs = inTimeLimitMs;
-
- *outItem = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) GAITestItemFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// GAITestItemDup
-//===========================================================================================================================
-
-static OSStatus GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem )
-{
- OSStatus err;
- GAITestItem * obj;
-
- obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- *obj = *inItem;
- obj->next = NULL;
- if( inItem->name )
- {
- obj->name = strdup( inItem->name );
- require_action( obj->name, exit, err = kNoMemoryErr );
- }
-
- *outItem = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) GAITestItemFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// GAITestItemFree
-//===========================================================================================================================
-
-static void GAITestItemFree( GAITestItem *inItem )
-{
- ForgetMem( &inItem->name );
- free( inItem );
-}
-
-//===========================================================================================================================
-// MDNSDiscoveryTestCmd
-//===========================================================================================================================
-
-#define kMDNSDiscoveryTestFirstQueryTimeoutSecs 4
-
-typedef struct
-{
- DNSServiceRef query; // Reference to DNSServiceQueryRecord for replier's "about" TXT record.
- dispatch_source_t queryTimer; // Used to time out the "about" TXT record query.
- NanoTime64 startTime; // When the test started.
- NanoTime64 endTime; // When the test ended.
- pid_t replierPID; // PID of mDNS replier.
- uint32_t ifIndex; // Index of interface to run the replier on.
- unsigned int instanceCount; // Desired number of service instances.
- unsigned int txtSize; // Desired size of each service instance's TXT record data.
- unsigned int recordCountA; // Desired number of A records per replier hostname.
- unsigned int recordCountAAAA; // Desired number of AAAA records per replier hostname.
- unsigned int maxDropCount; // Replier's --maxDropCount option argument.
- double ucastDropRate; // Replier's probability of dropping a unicast response.
- double mcastDropRate; // Replier's probability of dropping a multicast query or response.
- Boolean noAdditionals; // True if the replier is to not include additional records in responses.
- Boolean useIPv4; // True if the replier is to use IPv4.
- Boolean useIPv6; // True if the replier is to use IPv6.
- Boolean flushedCache; // True if mDNSResponder's record cache was flushed before testing.
- char * replierCommand; // Command used to run the replier.
- char * serviceType; // Type of services to browse for.
- ServiceBrowserRef browser; // Service browser.
- unsigned int browseTimeSecs; // Amount of time to spend browsing in seconds.
- const char * outputFilePath; // File to write test results to. If NULL, then write to stdout.
- OutputFormatType outputFormat; // Format of test results output.
- Boolean outputAppendNewline; // True if a newline character should be appended to JSON output.
- char hostname[ 32 + 1 ]; // Base hostname that the replier is to use for instance and host names.
- char tag[ 4 + 1 ]; // Tag that the replier is to use in its service types.
-
-} MDNSDiscoveryTestContext;
-
-static OSStatus GetAnyMDNSInterface( char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex );
-static void _MDNSDiscoveryTestFirstQueryTimeout( void *inContext );
-static void DNSSD_API
- _MDNSDiscoveryTestAboutQueryCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-static void
- _MDNSDiscoveryTestServiceBrowserCallback(
- ServiceBrowserResults * inResults,
- OSStatus inError,
- void * inContext );
-static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen );
-
-static void MDNSDiscoveryTestCmd( void )
-{
- OSStatus err;
- MDNSDiscoveryTestContext * context;
- char queryName[ sizeof_field( MDNSDiscoveryTestContext, hostname ) + 15 ];
-
- context = (MDNSDiscoveryTestContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- err = CheckIntegerArgument( gMDNSDiscoveryTest_InstanceCount, "instance count", 1, UINT16_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSDiscoveryTest_TXTSize, "TXT size", 1, UINT16_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSDiscoveryTest_BrowseTimeSecs, "browse time (seconds)", 1, INT_MAX );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountA, "A record count", 0, 64 );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountAAAA, "AAAA record count", 0, 64 );
- require_noerr_quiet( err, exit );
-
- err = CheckDoubleArgument( gMDNSDiscoveryTest_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
- require_noerr_quiet( err, exit );
-
- err = CheckDoubleArgument( gMDNSDiscoveryTest_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
- require_noerr_quiet( err, exit );
-
- err = CheckIntegerArgument( gMDNSDiscoveryTest_MaxDropCount, "drop count", 0, 255 );
- require_noerr_quiet( err, exit );
-
- context->replierPID = -1;
- context->instanceCount = (unsigned int) gMDNSDiscoveryTest_InstanceCount;
- context->txtSize = (unsigned int) gMDNSDiscoveryTest_TXTSize;
- context->browseTimeSecs = (unsigned int) gMDNSDiscoveryTest_BrowseTimeSecs;
- context->recordCountA = (unsigned int) gMDNSDiscoveryTest_RecordCountA;
- context->recordCountAAAA = (unsigned int) gMDNSDiscoveryTest_RecordCountAAAA;
- context->ucastDropRate = gMDNSDiscoveryTest_UnicastDropRate;
- context->mcastDropRate = gMDNSDiscoveryTest_MulticastDropRate;
- context->maxDropCount = (unsigned int) gMDNSDiscoveryTest_MaxDropCount;
- context->outputFilePath = gMDNSDiscoveryTest_OutputFilePath;
- context->outputAppendNewline = gMDNSDiscoveryTest_OutputAppendNewline ? true : false;
- context->noAdditionals = gMDNSDiscoveryTest_NoAdditionals ? true : false;
- context->useIPv4 = ( gMDNSDiscoveryTest_UseIPv4 || !gMDNSDiscoveryTest_UseIPv6 ) ? true : false;
- context->useIPv6 = ( gMDNSDiscoveryTest_UseIPv6 || !gMDNSDiscoveryTest_UseIPv4 ) ? true : false;
-
- if( gMDNSDiscoveryTest_Interface )
- {
- err = InterfaceIndexFromArgString( gMDNSDiscoveryTest_Interface, &context->ifIndex );
- require_noerr_quiet( err, exit );
- }
- else
- {
- err = GetAnyMDNSInterface( NULL, &context->ifIndex );
- require_noerr_quiet( err, exit );
- }
-
- context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gMDNSDiscoveryTest_OutputFormat, &err,
- kOutputFormatStr_JSON, kOutputFormatType_JSON,
- kOutputFormatStr_XML, kOutputFormatType_XML,
- kOutputFormatStr_Binary, kOutputFormatType_Binary,
- NULL );
- require_noerr_quiet( err, exit );
-
- if( gMDNSDiscoveryTest_FlushCache )
- {
- err = CheckRootUser();
- require_noerr_quiet( err, exit );
-
- err = systemf( NULL, "killall -HUP mDNSResponder" );
- require_noerr( err, exit );
- sleep( 1 );
- context->flushedCache = true;
- }
-
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->hostname ) - 1,
- context->hostname );
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->tag ) - 1, context->tag );
-
- ASPrintF( &context->serviceType, "_t-%s-%u-%u._tcp", context->tag, context->txtSize, context->instanceCount );
- require_action( context->serviceType, exit, err = kUnknownErr );
-
- err = ASPrintF( &context->replierCommand,
- "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount %u "
- "--countA %u --countAAAA %u --udrop %.1f --mdrop %.1f --maxDropCount %u %?s%?s%?s",
- (int64_t) getpid(),
- context->ifIndex,
- context->hostname,
- context->tag,
- context->instanceCount,
- context->recordCountA,
- context->recordCountAAAA,
- context->ucastDropRate,
- context->mcastDropRate,
- context->maxDropCount,
- context->noAdditionals, " --noAdditionals",
- context->useIPv4, " --ipv4",
- context->useIPv6, " --ipv6" );
- require_action_quiet( context->replierCommand, exit, err = kUnknownErr );
-
- err = SpawnCommand( &context->replierPID, "%s", context->replierCommand );
- require_noerr_quiet( err, exit );
-
- // Query for the replier's about TXT record. A response means it's fully up and running.
-
- SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->hostname );
- err = DNSServiceQueryRecord( &context->query, kDNSServiceFlagsForceMulticast, context->ifIndex, queryName,
- kDNSServiceType_TXT, kDNSServiceClass_IN, _MDNSDiscoveryTestAboutQueryCallback, context );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( context->query, dispatch_get_main_queue() );
- require_noerr( err, exit );
-
- err = DispatchTimerCreate( dispatch_time_seconds( kMDNSDiscoveryTestFirstQueryTimeoutSecs ),
- DISPATCH_TIME_FOREVER, UINT64_C_safe( kMDNSDiscoveryTestFirstQueryTimeoutSecs ) * kNanosecondsPerSecond / 10, NULL,
- _MDNSDiscoveryTestFirstQueryTimeout, NULL, context, &context->queryTimer );
- require_noerr( err, exit );
- dispatch_resume( context->queryTimer );
-
- context->startTime = NanoTimeGetCurrent();
- dispatch_main();
-
-exit:
- exit( 1 );
-}
-
-//===========================================================================================================================
-// _MDNSDiscoveryTestFirstQueryTimeout
-//===========================================================================================================================
-
-static void _MDNSDiscoveryTestFirstQueryTimeout( void *inContext )
-{
- MDNSDiscoveryTestContext * const context = (MDNSDiscoveryTestContext *) inContext;
-
- dispatch_source_forget( &context->queryTimer );
-
- FPrintF( stderr, "error: Query for mdnsreplier's \"about\" TXT record timed out.\n" );
- exit( 1 );
-}
-
-//===========================================================================================================================
-// _MDNSDiscoveryTestAboutQueryCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _MDNSDiscoveryTestAboutQueryCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- MDNSDiscoveryTestContext * const context = (MDNSDiscoveryTestContext *) inContext;
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inFullName );
- Unused( inType );
- Unused( inClass );
- Unused( inRDataLen );
- Unused( inRDataPtr );
- Unused( inTTL );
-
- err = inError;
- require_noerr( err, exit );
- require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
-
- DNSServiceForget( &context->query );
- dispatch_source_forget( &context->queryTimer );
-
- err = ServiceBrowserCreate( dispatch_get_main_queue(), 0, "local.", context->browseTimeSecs, false, &context->browser );
- require_noerr( err, exit );
-
- err = ServiceBrowserAddServiceType( context->browser, context->serviceType );
- require_noerr( err, exit );
-
- ServiceBrowserSetCallback( context->browser, _MDNSDiscoveryTestServiceBrowserCallback, context );
- ServiceBrowserStart( context->browser );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// _MDNSDiscoveryTestServiceBrowserCallback
-//===========================================================================================================================
-
-#define kMDNSDiscoveryTestResultsKey_ReplierInfo CFSTR( "replierInfo" )
-#define kMDNSDiscoveryTestResultsKey_StartTime CFSTR( "startTime" )
-#define kMDNSDiscoveryTestResultsKey_EndTime CFSTR( "endTime" )
-#define kMDNSDiscoveryTestResultsKey_BrowseTimeSecs CFSTR( "browseTimeSecs" )
-#define kMDNSDiscoveryTestResultsKey_ServiceType CFSTR( "serviceType" )
-#define kMDNSDiscoveryTestResultsKey_FlushedCache CFSTR( "flushedCache" )
-#define kMDNSDiscoveryTestResultsKey_UnexpectedInstances CFSTR( "unexpectedInstances" )
-#define kMDNSDiscoveryTestResultsKey_MissingInstances CFSTR( "missingInstances" )
-#define kMDNSDiscoveryTestResultsKey_IncorrectInstances CFSTR( "incorrectInstances" )
-#define kMDNSDiscoveryTestResultsKey_Success CFSTR( "success" )
-#define kMDNSDiscoveryTestResultsKey_TotalResolveTime CFSTR( "totalResolveTimeUs" )
-
-#define kMDNSDiscoveryTestReplierInfoKey_Command CFSTR( "command" )
-#define kMDNSDiscoveryTestReplierInfoKey_InstanceCount CFSTR( "instanceCount" )
-#define kMDNSDiscoveryTestReplierInfoKey_TXTSize CFSTR( "txtSize" )
-#define kMDNSDiscoveryTestReplierInfoKey_RecordCountA CFSTR( "recordCountA" )
-#define kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA CFSTR( "recordCountAAAA" )
-#define kMDNSDiscoveryTestReplierInfoKey_Hostname CFSTR( "hostname" )
-#define kMDNSDiscoveryTestReplierInfoKey_NoAdditionals CFSTR( "noAdditionals" )
-#define kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate CFSTR( "ucastDropRate" )
-#define kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate CFSTR( "mcastDropRate" )
-#define kMDNSDiscoveryTestReplierInfoKey_MaxDropCount CFSTR( "maxDropCount" )
-
-#define kMDNSDiscoveryTestUnexpectedInstanceKey_Name CFSTR( "name" )
-#define kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex CFSTR( "interfaceIndex" )
-
-#define kMDNSDiscoveryTestIncorrectInstanceKey_Name CFSTR( "name" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve CFSTR( "didResolve" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname CFSTR( "badHostname" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_BadPort CFSTR( "badPort" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT CFSTR( "badTXT" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs CFSTR( "unexpectedAddrs" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs CFSTR( "missingAddrs" )
-
-static void _MDNSDiscoveryTestServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
-{
- OSStatus err;
- MDNSDiscoveryTestContext * const context = (MDNSDiscoveryTestContext *) inContext;
- const SBRDomain * domain;
- const SBRServiceType * type;
- const SBRServiceInstance * instance;
- const SBRServiceInstance ** instanceArray = NULL;
- const SBRIPAddress * ipaddr;
- size_t hostnameLen;
- const char * ptr;
- const char * end;
- unsigned int i;
- uint32_t u32;
- CFMutableArrayRef unexpectedInstances;
- CFMutableArrayRef missingInstances;
- CFMutableArrayRef incorrectInstances;
- CFMutableDictionaryRef plist = NULL;
- CFMutableDictionaryRef badDict = NULL;
- CFMutableArrayRef unexpectedAddrs = NULL;
- CFMutableArrayRef missingAddrs = NULL;
- uint64_t maxResolveTimeUs;
- int success = false;
- char startTimeStr[ 32 ];
- char endTimeStr[ 32 ];
-
- context->endTime = NanoTimeGetCurrent();
-
- err = inError;
- require_noerr( err, exit );
-
- _NanoTime64ToDateString( context->startTime, startTimeStr, sizeof( startTimeStr ) );
- _NanoTime64ToDateString( context->endTime, endTimeStr, sizeof( endTimeStr ) );
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
- "{"
- "%kO="
- "{"
- "%kO=%s" // replierCommand
- "%kO=%lli" // txtSize
- "%kO=%lli" // instanceCount
- "%kO=%lli" // recordCountA
- "%kO=%lli" // recordCountAAAA
- "%kO=%s" // hostname
- "%kO=%b" // noAdditionals
- "%kO=%f" // ucastDropRate
- "%kO=%f" // mcastDropRate
- "%kO=%i" // maxDropCount
- "}"
- "%kO=%s" // startTime
- "%kO=%s" // endTime
- "%kO=%lli" // browseTimeSecs
- "%kO=%s" // serviceType
- "%kO=%b" // flushedCache
- "%kO=[%@]" // unexpectedInstances
- "%kO=[%@]" // missingInstances
- "%kO=[%@]" // incorrectInstances
- "}",
- kMDNSDiscoveryTestResultsKey_ReplierInfo,
- kMDNSDiscoveryTestReplierInfoKey_Command, context->replierCommand,
- kMDNSDiscoveryTestReplierInfoKey_InstanceCount, (int64_t) context->instanceCount,
- kMDNSDiscoveryTestReplierInfoKey_TXTSize, (int64_t) context->txtSize,
- kMDNSDiscoveryTestReplierInfoKey_RecordCountA, (int64_t) context->recordCountA,
- kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA, (int64_t) context->recordCountAAAA,
- kMDNSDiscoveryTestReplierInfoKey_Hostname, context->hostname,
- kMDNSDiscoveryTestReplierInfoKey_NoAdditionals, context->noAdditionals,
- kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate, context->ucastDropRate,
- kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate, context->mcastDropRate,
- kMDNSDiscoveryTestReplierInfoKey_MaxDropCount, context->maxDropCount,
- kMDNSDiscoveryTestResultsKey_StartTime, startTimeStr,
- kMDNSDiscoveryTestResultsKey_EndTime, endTimeStr,
- kMDNSDiscoveryTestResultsKey_BrowseTimeSecs, (int64_t) context->browseTimeSecs,
- kMDNSDiscoveryTestResultsKey_ServiceType, context->serviceType,
- kMDNSDiscoveryTestResultsKey_FlushedCache, context->flushedCache,
- kMDNSDiscoveryTestResultsKey_UnexpectedInstances, &unexpectedInstances,
- kMDNSDiscoveryTestResultsKey_MissingInstances, &missingInstances,
- kMDNSDiscoveryTestResultsKey_IncorrectInstances, &incorrectInstances );
- require_noerr( err, exit );
-
- for( domain = inResults->domainList; domain && ( strcasecmp( domain->name, "local.") != 0 ); domain = domain->next ) {}
- require_action( domain, exit, err = kInternalErr );
-
- for( type = domain->typeList; type && ( strcasecmp( type->name, context->serviceType ) != 0 ); type = type->next ) {}
- require_action( type, exit, err = kInternalErr );
-
- instanceArray = (const SBRServiceInstance **) calloc( context->instanceCount, sizeof( *instanceArray ) );
- require_action( instanceArray, exit, err = kNoMemoryErr );
-
- hostnameLen = strlen( context->hostname );
- for( instance = type->instanceList; instance; instance = instance->next )
- {
- unsigned int instanceNumber = 0;
-
- if( strcmp_prefix( instance->name, context->hostname ) == 0 )
- {
- ptr = &instance->name[ hostnameLen ];
- if( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ) )
- {
- ptr += 2;
- for( end = ptr; isdigit_safe( *end ); ++end ) {}
- if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
- {
- if( ( u32 >= 2 ) && ( u32 <= context->instanceCount ) && ( ptr[ 0 ] == ')' ) && ( ptr[ 1 ] == '\0' ) )
- {
- instanceNumber = u32;
- }
- }
- }
- else if( *ptr == '\0' )
- {
- instanceNumber = 1;
- }
- }
- if( ( instanceNumber != 0 ) && ( instance->ifIndex == context->ifIndex ) )
- {
- check( !instanceArray[ instanceNumber - 1 ] );
- instanceArray[ instanceNumber - 1 ] = instance;
- }
- else
- {
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedInstances,
- "{"
- "%kO=%s"
- "%kO=%lli"
- "}",
- kMDNSDiscoveryTestUnexpectedInstanceKey_Name, instance->name,
- kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex, (int64_t) instance->ifIndex );
- require_noerr( err, exit );
- }
- }
-
- maxResolveTimeUs = 0;
- for( i = 1; i <= context->instanceCount; ++i )
- {
- int isHostnameValid;
- int isTXTValid;
-
- instance = instanceArray[ i - 1 ];
- if( !instance )
- {
- if( i == 1 )
- {
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", context->hostname );
- require_noerr( err, exit );
- }
- else
- {
- char * instanceName = NULL;
-
- ASPrintF( &instanceName, "%s (%u)", context->hostname, i );
- require_action( instanceName, exit, err = kUnknownErr );
-
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", instanceName );
- free( instanceName );
- require_noerr( err, exit );
- }
- continue;
- }
-
- if( !instance->hostname )
- {
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, incorrectInstances,
- "{"
- "%kO=%s"
- "%kO=%b"
- "}",
- kMDNSDiscoveryTestIncorrectInstanceKey_Name, instance->name,
- kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve, false );
- require_noerr( err, exit );
- continue;
- }
-
- badDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
- require_action( badDict, exit, err = kNoMemoryErr );
-
- isHostnameValid = false;
- if( strcmp_prefix( instance->hostname, context->hostname ) == 0 )
- {
- ptr = &instance->hostname[ hostnameLen ];
- if( i == 1 )
- {
- if( strcmp( ptr, ".local." ) == 0 ) isHostnameValid = true;
- }
- else if( *ptr == '-' )
- {
- ++ptr;
- for( end = ptr; isdigit_safe( *end ); ++end ) {}
- if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
- {
- if( ( u32 == i ) && ( strcmp( ptr, ".local." ) == 0 ) ) isHostnameValid = true;
- }
- }
- }
- if( !isHostnameValid )
- {
- err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname, instance->hostname,
- kSizeCString );
- require_noerr( err, exit );
- }
-
- if( instance->port != (uint16_t)( kMDNSReplierPortBase + context->txtSize ) )
- {
- err = CFDictionarySetInt64( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadPort, instance->port );
- require_noerr( err, exit );
- }
-
- isTXTValid = false;
- if( instance->txtLen == context->txtSize )
- {
- uint8_t name[ kDomainNameLengthMax ];
-
- err = DomainNameFromString( name, instance->name, NULL );
- require_noerr( err, exit );
-
- err = DomainNameAppendString( name, type->name, NULL );
- require_noerr( err, exit );
-
- err = DomainNameAppendString( name, "local", NULL );
- require_noerr( err, exit );
-
- if( _MDNSDiscoveryTestTXTRecordIsValid( name, instance->txtPtr, instance->txtLen ) ) isTXTValid = true;
- }
- if( !isTXTValid )
- {
- char * hexStr = NULL;
-
- ASPrintF( &hexStr, "%.4H", instance->txtPtr, (int) instance->txtLen, (int) instance->txtLen );
- require_action( hexStr, exit, err = kUnknownErr );
-
- err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT, hexStr, kSizeCString );
- free( hexStr );
- require_noerr( err, exit );
- }
-
- if( isHostnameValid )
- {
- uint64_t addrV4Bitmap, addrV6Bitmap, bitmask, resolveTimeUs;
- unsigned int j;
- uint8_t addrV4[ 4 ];
- uint8_t addrV6[ 16 ];
-
- if( context->recordCountA < 64 ) addrV4Bitmap = ( UINT64_C( 1 ) << context->recordCountA ) - 1;
- else addrV4Bitmap = ~UINT64_C( 0 );
-
- if( context->recordCountAAAA < 64 ) addrV6Bitmap = ( UINT64_C( 1 ) << context->recordCountAAAA ) - 1;
- else addrV6Bitmap = ~UINT64_C( 0 );
-
- addrV4[ 0 ] = 0;
- WriteBig16( &addrV4[ 1 ], i );
- addrV4[ 3 ] = 0;
-
- memcpy( addrV6, kMDNSReplierBaseAddrV6, 16 );
- WriteBig16( &addrV6[ 12 ], i );
-
- unexpectedAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( unexpectedAddrs, exit, err = kNoMemoryErr );
-
- resolveTimeUs = 0;
- for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
- {
- const uint8_t * addrPtr;
- unsigned int lsb;
- int isAddrValid = false;
-
- if( ipaddr->sip.sa.sa_family == AF_INET )
- {
- addrPtr = (const uint8_t *) &ipaddr->sip.v4.sin_addr.s_addr;
- lsb = addrPtr[ 3 ];
- if( ( memcmp( addrPtr, addrV4, 3 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountA ) )
- {
- bitmask = UINT64_C( 1 ) << ( lsb - 1 );
- addrV4Bitmap &= ~bitmask;
- isAddrValid = true;
- }
- }
- else if( ipaddr->sip.sa.sa_family == AF_INET6 )
- {
- addrPtr = ipaddr->sip.v6.sin6_addr.s6_addr;
- lsb = addrPtr[ 15 ];
- if( ( memcmp( addrPtr, addrV6, 15 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountAAAA ) )
- {
- bitmask = UINT64_C( 1 ) << ( lsb - 1 );
- addrV6Bitmap &= ~bitmask;
- isAddrValid = true;
- }
- }
- if( isAddrValid )
- {
- if( ipaddr->resolveTimeUs > resolveTimeUs ) resolveTimeUs = ipaddr->resolveTimeUs;
- }
- else
- {
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedAddrs, "%##a", &ipaddr->sip );
- require_noerr( err, exit );
- }
- }
-
- resolveTimeUs += ( instance->discoverTimeUs + instance->resolveTimeUs );
- if( resolveTimeUs > maxResolveTimeUs ) maxResolveTimeUs = resolveTimeUs;
-
- if( CFArrayGetCount( unexpectedAddrs ) > 0 )
- {
- CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs, unexpectedAddrs );
- }
- ForgetCF( &unexpectedAddrs );
-
- missingAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( missingAddrs, exit, err = kNoMemoryErr );
-
- for( j = 1; addrV4Bitmap != 0; ++j )
- {
- bitmask = UINT64_C( 1 ) << ( j - 1 );
- if( addrV4Bitmap & bitmask )
- {
- addrV4Bitmap &= ~bitmask;
- addrV4[ 3 ] = (uint8_t) j;
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.4a", addrV4 );
- require_noerr( err, exit );
- }
- }
- for( j = 1; addrV6Bitmap != 0; ++j )
- {
- bitmask = UINT64_C( 1 ) << ( j - 1 );
- if( addrV6Bitmap & bitmask )
- {
- addrV6Bitmap &= ~bitmask;
- addrV6[ 15 ] = (uint8_t) j;
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.16a", addrV6 );
- require_noerr( err, exit );
- }
- }
-
- if( CFArrayGetCount( missingAddrs ) > 0 )
- {
- CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs, missingAddrs );
- }
- ForgetCF( &missingAddrs );
- }
-
- if( CFDictionaryGetCount( badDict ) > 0 )
- {
- err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_Name, instance->name,
- kSizeCString );
- require_noerr( err, exit );
-
- CFDictionarySetBoolean( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve, true );
- CFArrayAppendValue( incorrectInstances, badDict );
- }
- ForgetCF( &badDict );
- }
-
- if( ( CFArrayGetCount( unexpectedInstances ) == 0 ) &&
- ( CFArrayGetCount( missingInstances ) == 0 ) &&
- ( CFArrayGetCount( incorrectInstances ) == 0 ) )
- {
- err = CFDictionarySetInt64( plist, kMDNSDiscoveryTestResultsKey_TotalResolveTime, (int64_t) maxResolveTimeUs );
- require_noerr( err, exit );
- success = true;
- }
- else
- {
- success = false;
- }
- CFDictionarySetBoolean( plist, kMDNSDiscoveryTestResultsKey_Success, success );
-
- err = OutputPropertyList( plist, context->outputFormat, context->outputAppendNewline, context->outputFilePath );
- require_noerr_quiet( err, exit );
-
-exit:
- ForgetCF( &context->browser );
- if( context->replierPID != -1 )
- {
- kill( context->replierPID, SIGTERM );
- context->replierPID = -1;
- }
- FreeNullSafe( instanceArray );
- CFReleaseNullSafe( plist );
- CFReleaseNullSafe( badDict );
- CFReleaseNullSafe( unexpectedAddrs );
- CFReleaseNullSafe( missingAddrs );
- exit( err ? 1 : ( success ? 0 : 2 ) );
-}
-
-//===========================================================================================================================
-// _MDNSDiscoveryTestTXTRecordIsValid
-//===========================================================================================================================
-
-static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen )
-{
- uint32_t hash;
- int n;
- const uint8_t * ptr;
- size_t i, wholeCount, remCount;
- uint8_t txtStr[ 16 ];
-
- if( inTXTLen == 0 ) return( false );
-
- hash = FNV1( inRecordName, DomainNameLength( inRecordName ) );
-
- txtStr[ 0 ] = 15;
- n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
- check( n == 15 );
-
- ptr = inTXTPtr;
- wholeCount = inTXTLen / 16;
- for( i = 0; i < wholeCount; ++i )
- {
- if( memcmp( ptr, txtStr, 16 ) != 0 ) return( false );
- ptr += 16;
- }
-
- remCount = inTXTLen % 16;
- if( remCount > 0 )
- {
- txtStr[ 0 ] = (uint8_t)( remCount - 1 );
- if( memcmp( ptr, txtStr, remCount ) != 0 ) return( false );
- ptr += remCount;
- }
- check( ptr == &inTXTPtr[ inTXTLen ] );
- return( true );
-}
-
-//===========================================================================================================================
-// DotLocalTestCmd
-//===========================================================================================================================
-
-#define kDotLocalTestPreparationTimeLimitSecs 5
-#define kDotLocalTestSubTestDurationSecs 5
-
-// Constants for SRV record query subtest.
-
-#define kDotLocalTestSRV_Priority 1
-#define kDotLocalTestSRV_Weight 0
-#define kDotLocalTestSRV_Port 80
-#define kDotLocalTestSRV_TargetName ( (const uint8_t *) "\x03" "www" "\x07" "example" "\x03" "com" )
-#define kDotLocalTestSRV_TargetStr "www.example.com."
-#define kDotLocalTestSRV_ResultStr "1 0 80 " kDotLocalTestSRV_TargetStr
-
-typedef enum
-{
- kDotLocalTestState_Unset = 0,
- kDotLocalTestState_Preparing = 1,
- kDotLocalTestState_GAIMDNSOnly = 2,
- kDotLocalTestState_GAIDNSOnly = 3,
- kDotLocalTestState_GAIBoth = 4,
- kDotLocalTestState_GAINeither = 5,
- kDotLocalTestState_GAINoSuchRecord = 6,
- kDotLocalTestState_QuerySRV = 7,
- kDotLocalTestState_Done = 8
-
-} DotLocalTestState;
-
-typedef struct
-{
- const char * testDesc; // Description of the current subtest.
- char * queryName; // Query name for GetAddrInfo or QueryRecord operation.
- dispatch_source_t timer; // Timer used for limiting the time for each subtest.
- NanoTime64 startTime; // Timestamp of when the subtest started.
- NanoTime64 endTime; // Timestamp of when the subtest ended.
- CFMutableArrayRef correctResults; // Operation results that were expected.
- CFMutableArrayRef duplicateResults; // Operation results that were expected, but were already received.
- CFMutableArrayRef unexpectedResults; // Operation results that were unexpected.
- OSStatus error; // Subtest's error code.
- uint32_t addrDNSv4; // If hasDNSv4 is true, the expected DNS IPv4 address for queryName.
- uint32_t addrMDNSv4; // If hasMDNSv4 is true, the expected MDNS IPv4 address for queryName.
- uint8_t addrDNSv6[ 16 ]; // If hasDNSv6 is true, the expected DNS IPv6 address for queryName.
- uint8_t addrMDNSv6[ 16 ]; // If hasMDNSv6 is true, the expected MDNS IPv6 address for queryName.
- Boolean hasDNSv4; // True if queryName has a DNS IPv4 address.
- Boolean hasDNSv6; // True if queryName has a DNS IPv6 address.
- Boolean hasMDNSv4; // True if queryName has an MDNS IPv4 address.
- Boolean hasMDNSv6; // True if queryName has an MDNS IPv6 address.
- Boolean needDNSv4; // True if operation is expecting, but hasn't received a DNS IPv4 result.
- Boolean needDNSv6; // True if operation is expecting, but hasn't received a DNS IPv6 result.
- Boolean needMDNSv4; // True if operation is expecting, but hasn't received an MDNS IPv4 result.
- Boolean needMDNSv6; // True if operation is expecting, but hasn't received an MDNS IPv6 result.
- Boolean needSRV; // True if operation is expecting, but hasn't received an SRV result.
-
-} DotLocalSubtest;
-
-typedef struct
-{
- dispatch_source_t timer; // Timer used for limiting the time for each state/subtest.
- DotLocalSubtest * subtest; // Current subtest's state.
- DNSServiceRef connection; // Shared connection for DNS-SD operations.
- DNSServiceRef op; // Reference for the current DNS-SD operation.
- DNSServiceRef op2; // Reference for mdnsreplier probe query used during preparing state.
- DNSRecordRef localSOARef; // Reference returned by DNSServiceRegisterRecord() for local. SOA record.
- char * replierCmd; // Command used to invoke the mdnsreplier.
- char * serverCmd; // Command used to invoke the test DNS server.
- CFMutableArrayRef reportsGAI; // Reports for subtests that use DNSServiceGetAddrInfo.
- CFMutableArrayRef reportsQuerySRV; // Reports for subtests that use DNSServiceQueryRecord for SRV records.
- NanoTime64 startTime; // Timestamp for when the test started.
- NanoTime64 endTime; // Timestamp for when the test ended.
- DotLocalTestState state; // The test's current state.
- pid_t replierPID; // PID of spawned mdnsreplier.
- pid_t serverPID; // PID of spawned test DNS server.
- uint32_t ifIndex; // Interface index used for mdnsreplier.
- char * outputFilePath; // File to write test results to. If NULL, then write to stdout.
- OutputFormatType outputFormat; // Format of test results output.
- Boolean appendNewline; // True if a newline character should be appended to JSON output.
- Boolean registeredSOA; // True if the dummy local. SOA record was successfully registered.
- Boolean serverIsReady; // True if response was received for test DNS server probe query.
- Boolean replierIsReady; // True if response was received for mdnsreplier probe query.
- Boolean testFailed; // True if at least one subtest failed.
- char labelStr[ 20 + 1 ]; // Unique label string used for for making the query names used by subtests.
- // The format of this string is "dotlocal-test-<six random chars>".
-} DotLocalTestContext;
-
-static void _DotLocalTestStateMachine( DotLocalTestContext *inContext );
-static void DNSSD_API
- _DotLocalTestProbeQueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-static void DNSSD_API
- _DotLocalTestRegisterRecordCallback(
- DNSServiceRef inSDRef,
- DNSRecordRef inRecordRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- void * inContext );
-static void _DotLocalTestTimerHandler( void *inContext );
-static void DNSSD_API
- _DotLocalTestGAICallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext );
-static void DNSSD_API
- _DotLocalTestQueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-
-static void DotLocalTestCmd( void )
-{
- OSStatus err;
- DotLocalTestContext * context;
- uint8_t * rdataPtr;
- size_t rdataLen;
- DNSServiceFlags flags;
- char queryName[ 64 ];
- char randBuf[ 6 + 1 ]; // Large enough for four and six character random strings below.
-
- context = (DotLocalTestContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->startTime = NanoTimeGetCurrent();
- context->endTime = kNanoTime_Invalid;
-
- context->state = kDotLocalTestState_Preparing;
-
- if( gDotLocalTest_Interface )
- {
- err = InterfaceIndexFromArgString( gDotLocalTest_Interface, &context->ifIndex );
- require_noerr_quiet( err, exit );
- }
- else
- {
- err = GetAnyMDNSInterface( NULL, &context->ifIndex );
- require_noerr_quiet( err, exit );
- }
-
- if( gDotLocalTest_OutputFilePath )
- {
- context->outputFilePath = strdup( gDotLocalTest_OutputFilePath );
- require_action( context->outputFilePath, exit, err = kNoMemoryErr );
- }
-
- context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gDotLocalTest_OutputFormat, &err,
- kOutputFormatStr_JSON, kOutputFormatType_JSON,
- kOutputFormatStr_XML, kOutputFormatType_XML,
- kOutputFormatStr_Binary, kOutputFormatType_Binary,
- NULL );
- require_noerr_quiet( err, exit );
-
- context->appendNewline = gDotLocalTest_OutputAppendNewline ? true : false;
-
- context->reportsGAI = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( context->reportsGAI, exit, err = kNoMemoryErr );
-
- context->reportsQuerySRV = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( context->reportsQuerySRV, exit, err = kNoMemoryErr );
-
- SNPrintF( context->labelStr, sizeof( context->labelStr ), "dotlocal-test-%s",
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 6, randBuf ) );
-
- // Spawn an mdnsreplier.
-
- err = ASPrintF( &context->replierCmd,
- "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount 2 --countA 1"
- " --countAAAA 1",
- (int64_t) getpid(), context->ifIndex, context->labelStr,
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 4, randBuf ) );
- require_action_quiet( context->replierCmd, exit, err = kUnknownErr );
-
- err = SpawnCommand( &context->replierPID, "%s", context->replierCmd );
- require_noerr( err, exit );
-
- // Spawn a test DNS server
-
- err = ASPrintF( &context->serverCmd,
- "dnssdutil server --loopback --follow %lld --port 0 --defaultTTL 300 --domain %s.local.",
- (int64_t) getpid(), context->labelStr );
- require_action_quiet( context->serverCmd, exit, err = kUnknownErr );
-
- err = SpawnCommand( &context->serverPID, "%s", context->serverCmd );
- require_noerr( err, exit );
-
- // Create a shared DNS-SD connection.
-
- err = DNSServiceCreateConnection( &context->connection );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( context->connection, dispatch_get_main_queue() );
- require_noerr( err, exit );
-
- // Create probe query for DNS server, i.e., query for any name that has an A record.
-
- SNPrintF( queryName, sizeof( queryName ), "tag-dotlocal-test-probe.ipv4.%s.local.", context->labelStr );
-
- flags = kDNSServiceFlagsShareConnection;
-#if( TARGET_OS_WATCH )
- flags |= kDNSServiceFlagsPathEvaluationDone;
-#endif
-
- context->op = context->connection;
- err = DNSServiceQueryRecord( &context->op, flags, kDNSServiceInterfaceIndexAny, queryName, kDNSServiceType_A,
- kDNSServiceClass_IN, _DotLocalTestProbeQueryRecordCallback, context );
- require_noerr( err, exit );
-
- // Create probe query for mdnsreplier's "about" TXT record.
-
- SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->labelStr );
-
- flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsForceMulticast;
-#if( TARGET_OS_WATCH )
- flags |= kDNSServiceFlagsPathEvaluationDone;
-#endif
-
- context->op2 = context->connection;
- err = DNSServiceQueryRecord( &context->op2, flags, context->ifIndex, queryName, kDNSServiceType_TXT, kDNSServiceClass_IN,
- _DotLocalTestProbeQueryRecordCallback, context );
- require_noerr( err, exit );
-
- // Register a dummy local. SOA record.
-
- err = CreateSOARecordData( kRootLabel, kRootLabel, 1976040101, 1 * kSecondsPerDay, 2 * kSecondsPerHour,
- 1000 * kSecondsPerHour, 2 * kSecondsPerDay, &rdataPtr, &rdataLen );
- require_noerr( err, exit );
-
- err = DNSServiceRegisterRecord( context->connection, &context->localSOARef, kDNSServiceFlagsUnique,
- kDNSServiceInterfaceIndexLocalOnly, "local.", kDNSServiceType_SOA, kDNSServiceClass_IN, 1,
- rdataPtr, 1 * kSecondsPerHour, _DotLocalTestRegisterRecordCallback, context );
- require_noerr( err, exit );
-
- // Start timer for probe responses and SOA record registration.
-
- err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestPreparationTimeLimitSecs ),
- INT64_C_safe( kDotLocalTestPreparationTimeLimitSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
- _DotLocalTestTimerHandler, context, &context->timer );
- require_noerr( err, exit );
- dispatch_resume( context->timer );
-
- dispatch_main();
-
-exit:
- if( err ) ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-// _DotLocalTestStateMachine
-//===========================================================================================================================
-
-static OSStatus _DotLocalSubtestCreate( DotLocalSubtest **outSubtest );
-static void _DotLocalSubtestFree( DotLocalSubtest *inSubtest );
-static OSStatus _DotLocalTestStartSubtest( DotLocalTestContext *inContext );
-static OSStatus _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext );
-static void _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext ) ATTRIBUTE_NORETURN;
-
-static void _DotLocalTestStateMachine( DotLocalTestContext *inContext )
-{
- OSStatus err;
- DotLocalTestState nextState;
-
- DNSServiceForget( &inContext->op );
- DNSServiceForget( &inContext->op2 );
- dispatch_source_forget( &inContext->timer );
-
- switch( inContext->state )
- {
- case kDotLocalTestState_Preparing: nextState = kDotLocalTestState_GAIMDNSOnly; break;
- case kDotLocalTestState_GAIMDNSOnly: nextState = kDotLocalTestState_GAIDNSOnly; break;
- case kDotLocalTestState_GAIDNSOnly: nextState = kDotLocalTestState_GAIBoth; break;
- case kDotLocalTestState_GAIBoth: nextState = kDotLocalTestState_GAINeither; break;
- case kDotLocalTestState_GAINeither: nextState = kDotLocalTestState_GAINoSuchRecord; break;
- case kDotLocalTestState_GAINoSuchRecord: nextState = kDotLocalTestState_QuerySRV; break;
- case kDotLocalTestState_QuerySRV: nextState = kDotLocalTestState_Done; break;
- default: err = kStateErr; goto exit;
- }
-
- if( inContext->state == kDotLocalTestState_Preparing )
- {
- if( !inContext->registeredSOA || !inContext->serverIsReady || !inContext->replierIsReady )
- {
- FPrintF( stderr, "Preparation timed out: Registered SOA? %s. Server ready? %s. mdnsreplier ready? %s.\n",
- YesNoStr( inContext->registeredSOA ),
- YesNoStr( inContext->serverIsReady ),
- YesNoStr( inContext->replierIsReady ) );
- err = kNotPreparedErr;
- goto exit;
- }
- }
- else
- {
- err = _DotLocalTestFinalizeSubtest( inContext );
- require_noerr( err, exit );
- }
-
- inContext->state = nextState;
- if( inContext->state == kDotLocalTestState_Done ) _DotLocalTestFinalizeAndExit( inContext );
- err = _DotLocalTestStartSubtest( inContext );
-
-exit:
- if( err ) ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-// _DotLocalSubtestCreate
-//===========================================================================================================================
-
-static OSStatus _DotLocalSubtestCreate( DotLocalSubtest **outSubtest )
-{
- OSStatus err;
- DotLocalSubtest * obj;
-
- obj = (DotLocalSubtest *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->correctResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( obj->correctResults, exit, err = kNoMemoryErr );
-
- obj->duplicateResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( obj->duplicateResults, exit, err = kNoMemoryErr );
-
- obj->unexpectedResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
- require_action( obj->unexpectedResults, exit, err = kNoMemoryErr );
-
- *outSubtest = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _DotLocalSubtestFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _DotLocalSubtestFree
-//===========================================================================================================================
-
-static void _DotLocalSubtestFree( DotLocalSubtest *inSubtest )
-{
- ForgetMem( &inSubtest->queryName );
- ForgetCF( &inSubtest->correctResults );
- ForgetCF( &inSubtest->duplicateResults );
- ForgetCF( &inSubtest->unexpectedResults );
- free( inSubtest );
-}
-
-//===========================================================================================================================
-// _DotLocalTestStartSubtest
-//===========================================================================================================================
-
-static OSStatus _DotLocalTestStartSubtest( DotLocalTestContext *inContext )
-{
- OSStatus err;
- DotLocalSubtest * subtest = NULL;
- DNSServiceRef op = NULL;
- DNSServiceFlags flags;
-
- err = _DotLocalSubtestCreate( &subtest );
- require_noerr( err, exit );
-
- if( inContext->state == kDotLocalTestState_GAIMDNSOnly )
- {
- ASPrintF( &subtest->queryName, "%s-2.local.", inContext->labelStr );
- require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-
- subtest->hasMDNSv4 = subtest->needMDNSv4 = true;
- subtest->hasMDNSv6 = subtest->needMDNSv6 = true;
-
- subtest->addrMDNSv4 = htonl( 0x00000201 ); // 0.0.2.1
- memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 ); // 2001:db8:2::2:1
- subtest->addrMDNSv6[ 13 ] = 2;
- subtest->addrMDNSv6[ 15 ] = 1;
-
- subtest->testDesc = kDotLocalTestSubtestDesc_GAIMDNSOnly;
- }
-
- else if( inContext->state == kDotLocalTestState_GAIDNSOnly )
- {
- ASPrintF( &subtest->queryName, "tag-dns-only.%s.local.", inContext->labelStr );
- require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-
- subtest->hasDNSv4 = subtest->needDNSv4 = true;
- subtest->hasDNSv6 = subtest->needDNSv6 = true;
-
- subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 ); // 203.0.113.1
- memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 ); // 2001:db8:1::1
- subtest->addrDNSv6[ 15 ] = 1;
-
- subtest->testDesc = kDotLocalTestSubtestDesc_GAIDNSOnly;
- }
-
- else if( inContext->state == kDotLocalTestState_GAIBoth )
- {
- ASPrintF( &subtest->queryName, "%s.local.", inContext->labelStr );
- require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-
- subtest->hasDNSv4 = subtest->needDNSv4 = true;
- subtest->hasDNSv6 = subtest->needDNSv6 = true;
- subtest->hasMDNSv4 = subtest->needMDNSv4 = true;
- subtest->hasMDNSv6 = subtest->needMDNSv6 = true;
-
- subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 ); // 203.0.113.1
- memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 ); // 2001:db8:1::1
- subtest->addrDNSv6[ 15 ] = 1;
-
- subtest->addrMDNSv4 = htonl( 0x00000101 ); // 0.0.1.1
- memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 ); // 2001:db8:2::1:1
- subtest->addrMDNSv6[ 13 ] = 1;
- subtest->addrMDNSv6[ 15 ] = 1;
-
- subtest->testDesc = kDotLocalTestSubtestDesc_GAIBoth;
- }
-
- else if( inContext->state == kDotLocalTestState_GAINeither )
- {
- ASPrintF( &subtest->queryName, "doesnotexit-%s.local.", inContext->labelStr );
- require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-
- subtest->testDesc = kDotLocalTestSubtestDesc_GAINeither;
- }
-
- else if( inContext->state == kDotLocalTestState_GAINoSuchRecord )
- {
- ASPrintF( &subtest->queryName, "doesnotexit-dns.%s.local.", inContext->labelStr );
- require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-
- subtest->hasDNSv4 = subtest->needDNSv4 = true;
- subtest->hasDNSv6 = subtest->needDNSv6 = true;
- subtest->testDesc = kDotLocalTestSubtestDesc_GAINoSuchRecord;
- }
-
- else if( inContext->state == kDotLocalTestState_QuerySRV )
- {
- ASPrintF( &subtest->queryName, "_http._tcp.srv-%u-%u-%u.%s%s.local.",
- kDotLocalTestSRV_Priority, kDotLocalTestSRV_Weight, kDotLocalTestSRV_Port, kDotLocalTestSRV_TargetStr,
- inContext->labelStr );
- require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-
- subtest->needSRV = true;
- subtest->testDesc = kDotLocalTestSubtestDesc_QuerySRV;
- }
-
- else
- {
- err = kStateErr;
- goto exit;
- }
-
- // Start new operation.
-
- flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
-#if( TARGET_OS_WATCH )
- flags |= kDNSServiceFlagsPathEvaluationDone;
-#endif
-
- subtest->startTime = NanoTimeGetCurrent();
- subtest->endTime = kNanoTime_Invalid;
-
- if( inContext->state == kDotLocalTestState_QuerySRV )
- {
- op = inContext->connection;
- err = DNSServiceQueryRecord( &op, flags, kDNSServiceInterfaceIndexAny, subtest->queryName,
- kDNSServiceType_SRV, kDNSServiceClass_IN, _DotLocalTestQueryRecordCallback, inContext );
- require_noerr( err, exit );
- }
- else
- {
- op = inContext->connection;
- err = DNSServiceGetAddrInfo( &op, flags, kDNSServiceInterfaceIndexAny,
- kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, subtest->queryName, _DotLocalTestGAICallback, inContext );
- require_noerr( err, exit );
- }
-
- // Start timer.
-
- check( !inContext->timer );
- err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestSubTestDurationSecs ),
- INT64_C_safe( kDotLocalTestSubTestDurationSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
- _DotLocalTestTimerHandler, inContext, &inContext->timer );
- require_noerr( err, exit );
- dispatch_resume( inContext->timer );
-
- check( !inContext->op );
- inContext->op = op;
- op = NULL;
-
- check( !inContext->subtest );
- inContext->subtest = subtest;
- subtest = NULL;
-
-exit:
- if( subtest ) _DotLocalSubtestFree( subtest );
- if( op ) DNSServiceRefDeallocate( op );
- return( err );
-}
-
-//===========================================================================================================================
-// _DotLocalTestFinalizeSubtest
-//===========================================================================================================================
-
-#define kDotLocalTestReportKey_StartTime CFSTR( "startTime" ) // String.
-#define kDotLocalTestReportKey_EndTime CFSTR( "endTime" ) // String.
-#define kDotLocalTestReportKey_Success CFSTR( "success" ) // Boolean.
-#define kDotLocalTestReportKey_MDNSReplierCmd CFSTR( "replierCmd" ) // String.
-#define kDotLocalTestReportKey_DNSServerCmd CFSTR( "serverCmd" ) // String.
-#define kDotLocalTestReportKey_GetAddrInfoTests CFSTR( "testsGAI" ) // Array of Dictionaries.
-#define kDotLocalTestReportKey_QuerySRVTests CFSTR( "testsQuerySRV" ) // Array of Dictionaries.
-#define kDotLocalTestReportKey_Description CFSTR( "description" ) // String.
-#define kDotLocalTestReportKey_QueryName CFSTR( "queryName" ) // String.
-#define kDotLocalTestReportKey_Error CFSTR( "error" ) // Integer.
-#define kDotLocalTestReportKey_Results CFSTR( "results" ) // Dictionary of Arrays.
-#define kDotLocalTestReportKey_CorrectResults CFSTR( "correct" ) // Array of Strings
-#define kDotLocalTestReportKey_DuplicateResults CFSTR( "duplicates" ) // Array of Strings.
-#define kDotLocalTestReportKey_UnexpectedResults CFSTR( "unexpected" ) // Array of Strings.
-#define kDotLocalTestReportKey_MissingResults CFSTR( "missing" ) // Array of Strings.
-
-static OSStatus _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext )
-{
- OSStatus err;
- DotLocalSubtest * subtest;
- CFMutableDictionaryRef reportDict;
- CFMutableDictionaryRef resultsDict;
- CFMutableArrayRef missingResults, reportArray;
- char startTimeStr[ 32 ];
- char endTimeStr[ 32 ];
-
- subtest = inContext->subtest;
- inContext->subtest = NULL;
-
- subtest->endTime = NanoTimeGetCurrent();
- _NanoTime64ToDateString( subtest->startTime, startTimeStr, sizeof( startTimeStr ) );
- _NanoTime64ToDateString( subtest->endTime, endTimeStr, sizeof( endTimeStr ) );
-
- reportDict = NULL;
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &reportDict,
- "{"
- "%kO=%s" // startTime
- "%kO=%s" // endTime
- "%kO=%s" // queryName
- "%kO=%s" // description
- "%kO={%@}" // results
- "}",
- kDotLocalTestReportKey_StartTime, startTimeStr,
- kDotLocalTestReportKey_EndTime, endTimeStr,
- kDotLocalTestReportKey_QueryName, subtest->queryName,
- kDotLocalTestReportKey_Description, subtest->testDesc,
- kDotLocalTestReportKey_Results, &resultsDict );
- require_noerr( err, exit );
-
- missingResults = NULL;
- switch( inContext->state )
- {
- case kDotLocalTestState_GAIMDNSOnly:
- case kDotLocalTestState_GAIDNSOnly:
- case kDotLocalTestState_GAIBoth:
- case kDotLocalTestState_GAINeither:
- if( subtest->needDNSv4 || subtest->needDNSv6 || subtest->needMDNSv4 || subtest->needMDNSv6 )
- {
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
- "["
- "%.4a" // Expected DNS IPv4 address
- "%.16a" // Expected DNS IPv6 address
- "%.4a" // Expected MDNS IPv4 address
- "%.16a" // Expected MDNS IPv6 address
- "]",
- subtest->needDNSv4 ? &subtest->addrDNSv4 : NULL,
- subtest->needDNSv6 ? subtest->addrDNSv6 : NULL,
- subtest->needMDNSv4 ? &subtest->addrMDNSv4 : NULL,
- subtest->needMDNSv6 ? subtest->addrMDNSv6 : NULL );
- require_noerr( err, exit );
- }
- break;
-
- case kDotLocalTestState_QuerySRV:
- if( subtest->needSRV )
- {
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
- "["
- "%s" // Expected SRV record data as a string.
- "]",
- kDotLocalTestSRV_ResultStr );
- require_noerr( err, exit );
- }
- break;
-
- case kDotLocalTestState_GAINoSuchRecord:
- if( subtest->needDNSv4 || subtest->needDNSv6 )
- {
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
- "["
- "%s" // No Such Record (A)
- "%s" // No Such Record (AAAA)
- "]",
- subtest->needDNSv4 ? kNoSuchRecordAStr : NULL,
- subtest->needDNSv6 ? kNoSuchRecordAAAAStr : NULL );
- require_noerr( err, exit );
- }
- break;
-
- default:
- err = kStateErr;
- goto exit;
- }
-
- CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_CorrectResults, subtest->correctResults );
-
- if( missingResults )
- {
- CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_MissingResults, missingResults );
- ForgetCF( &missingResults );
- if( !subtest->error ) subtest->error = kNotFoundErr;
- }
-
- if( CFArrayGetCount( subtest->unexpectedResults ) > 0 )
- {
- CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_UnexpectedResults, subtest->unexpectedResults );
- if( !subtest->error ) subtest->error = kUnexpectedErr;
- }
-
- if( CFArrayGetCount( subtest->duplicateResults ) > 0 )
- {
- CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_DuplicateResults, subtest->duplicateResults );
- if( !subtest->error ) subtest->error = kDuplicateErr;
- }
-
- if( subtest->error ) inContext->testFailed = true;
- err = CFDictionarySetInt64( reportDict, kDotLocalTestReportKey_Error, subtest->error );
- require_noerr( err, exit );
-
- reportArray = ( inContext->state == kDotLocalTestState_QuerySRV ) ? inContext->reportsQuerySRV : inContext->reportsGAI;
- CFArrayAppendValue( reportArray, reportDict );
-
-exit:
- _DotLocalSubtestFree( subtest );
- CFReleaseNullSafe( reportDict );
- return( err );
-}
-
-//===========================================================================================================================
-// _DotLocalTestFinalizeAndExit
-//===========================================================================================================================
-
-static void _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext )
-{
- OSStatus err;
- CFPropertyListRef plist;
- char startTimeStr[ 32 ];
- char endTimeStr[ 32 ];
-
- check( !inContext->subtest );
- inContext->endTime = NanoTimeGetCurrent();
-
- if( inContext->replierPID != -1 )
- {
- kill( inContext->replierPID, SIGTERM );
- inContext->replierPID = -1;
- }
- if( inContext->serverPID != -1 )
- {
- kill( inContext->serverPID, SIGTERM );
- inContext->serverPID = -1;
- }
- err = DNSServiceRemoveRecord( inContext->connection, inContext->localSOARef, 0 );
- require_noerr( err, exit );
-
- _NanoTime64ToDateString( inContext->startTime, startTimeStr, sizeof( startTimeStr ) );
- _NanoTime64ToDateString( inContext->endTime, endTimeStr, sizeof( endTimeStr ) );
-
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
- "{"
- "%kO=%s" // startTime
- "%kO=%s" // endTime
- "%kO=%O" // testsGAI
- "%kO=%O" // testsQuerySRV
- "%kO=%b" // success
- "%kO=%s" // replierCmd
- "%kO=%s" // serverCmd
- "}",
- kDotLocalTestReportKey_StartTime, startTimeStr,
- kDotLocalTestReportKey_EndTime, endTimeStr,
- kDotLocalTestReportKey_GetAddrInfoTests, inContext->reportsGAI,
- kDotLocalTestReportKey_QuerySRVTests, inContext->reportsQuerySRV,
- kDotLocalTestReportKey_Success, inContext->testFailed ? false : true,
- kDotLocalTestReportKey_MDNSReplierCmd, inContext->replierCmd,
- kDotLocalTestReportKey_DNSServerCmd, inContext->serverCmd );
- require_noerr( err, exit );
-
- ForgetCF( &inContext->reportsGAI );
- ForgetCF( &inContext->reportsQuerySRV );
-
- err = OutputPropertyList( plist, inContext->outputFormat, inContext->appendNewline, inContext->outputFilePath );
- CFRelease( plist );
- require_noerr( err, exit );
-
- exit( inContext->testFailed ? 2 : 0 );
-
-exit:
- ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-// _DotLocalTestProbeQueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _DotLocalTestProbeQueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
-
- Unused( inInterfaceIndex );
- Unused( inFullName );
- Unused( inType );
- Unused( inClass );
- Unused( inRDataLen );
- Unused( inRDataPtr );
- Unused( inTTL );
-
- check( context->state == kDotLocalTestState_Preparing );
-
- require_quiet( ( inFlags & kDNSServiceFlagsAdd ) && !inError, exit );
-
- if( inSDRef == context->op )
- {
- DNSServiceForget( &context->op );
- context->serverIsReady = true;
- }
- else if( inSDRef == context->op2 )
- {
- DNSServiceForget( &context->op2 );
- context->replierIsReady = true;
- }
-
- if( context->registeredSOA && context->serverIsReady && context->replierIsReady )
- {
- _DotLocalTestStateMachine( context );
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _DotLocalTestRegisterRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _DotLocalTestRegisterRecordCallback(
- DNSServiceRef inSDRef,
- DNSRecordRef inRecordRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- void * inContext )
-{
- DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
-
- Unused( inSDRef );
- Unused( inRecordRef );
- Unused( inFlags );
-
- if( inError ) ErrQuit( 1, "error: local. SOA record registration failed: %#m\n", inError );
-
- if( !context->registeredSOA )
- {
- context->registeredSOA = true;
- if( context->serverIsReady && context->replierIsReady ) _DotLocalTestStateMachine( context );
- }
-}
-
-//===========================================================================================================================
-// _DotLocalTestTimerHandler
-//===========================================================================================================================
-
-static void _DotLocalTestTimerHandler( void *inContext )
-{
- _DotLocalTestStateMachine( (DotLocalTestContext *) inContext );
-}
-
-//===========================================================================================================================
-// _DotLocalTestGAICallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _DotLocalTestGAICallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
- DotLocalSubtest * const subtest = context->subtest;
- const sockaddr_ip * const sip = (const sockaddr_ip *) inSockAddr;
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inHostname );
- Unused( inTTL );
-
- require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
- require_action_quiet( ( sip->sa.sa_family == AF_INET ) || ( sip->sa.sa_family == AF_INET6 ), exit, err = kTypeErr );
-
- if( context->state == kDotLocalTestState_GAINoSuchRecord )
- {
- if( inError == kDNSServiceErr_NoSuchRecord )
- {
- CFMutableArrayRef array = NULL;
- const char * noSuchRecordStr;
-
- if( sip->sa.sa_family == AF_INET )
- {
- array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
- subtest->needDNSv4 = false;
-
- noSuchRecordStr = kNoSuchRecordAStr;
- }
- else
- {
- array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
- subtest->needDNSv6 = false;
-
- noSuchRecordStr = kNoSuchRecordAAAAStr;
- }
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", noSuchRecordStr );
- require_noerr( err, fatal );
- }
- else if( !inError )
- {
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%##a", sip );
- require_noerr( err, fatal );
- }
- else
- {
- err = inError;
- goto exit;
- }
- }
- else
- {
- if( !inError )
- {
- CFMutableArrayRef array = NULL;
-
- if( sip->sa.sa_family == AF_INET )
- {
- const uint32_t addrV4 = sip->v4.sin_addr.s_addr;
-
- if( subtest->hasDNSv4 && ( addrV4 == subtest->addrDNSv4 ) )
- {
- array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
- subtest->needDNSv4 = false;
- }
- else if( subtest->hasMDNSv4 && ( addrV4 == subtest->addrMDNSv4 ) )
- {
- array = subtest->needMDNSv4 ? subtest->correctResults : subtest->duplicateResults;
- subtest->needMDNSv4 = false;
- }
- }
- else
- {
- const uint8_t * const addrV6 = sip->v6.sin6_addr.s6_addr;
-
- if( subtest->hasDNSv6 && ( memcmp( addrV6, subtest->addrDNSv6, 16 ) == 0 ) )
- {
- array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
- subtest->needDNSv6 = false;
- }
- else if( subtest->hasMDNSv6 && ( memcmp( addrV6, subtest->addrMDNSv6, 16 ) == 0 ) )
- {
- array = subtest->needMDNSv6 ? subtest->correctResults : subtest->duplicateResults;
- subtest->needMDNSv6 = false;
- }
- }
- if( !array ) array = subtest->unexpectedResults;
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%##a", sip );
- require_noerr( err, fatal );
- }
- else if( inError == kDNSServiceErr_NoSuchRecord )
- {
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%s",
- ( sip->sa.sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr );
- require_noerr( err, fatal );
- }
- else
- {
- err = inError;
- goto exit;
- }
- }
-
-exit:
- if( err )
- {
- subtest->error = err;
- _DotLocalTestStateMachine( context );
- }
- return;
-
-fatal:
- ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-// _DotLocalTestQueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _DotLocalTestQueryRecordCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
- DotLocalSubtest * const subtest = context->subtest;
- const SRVRecordDataFixedFields * fields;
- const uint8_t * target;
- const uint8_t * ptr;
- const uint8_t * end;
- char * rdataStr;
- unsigned int priority, weight, port;
- CFMutableArrayRef array;
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inFullName );
- Unused( inTTL );
-
- check( context->state == kDotLocalTestState_QuerySRV );
-
- err = inError;
- require_noerr_quiet( err, exit );
- require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
- require_action_quiet( ( inType == kDNSServiceType_SRV ) && ( inClass == kDNSServiceClass_IN ), exit, err = kTypeErr );
- require_action_quiet( inRDataLen > sizeof( SRVRecordDataFixedFields ), exit, err = kSizeErr );
-
- fields = (const SRVRecordDataFixedFields *) inRDataPtr;
- SRVRecordDataFixedFieldsGet( fields, &priority, &weight, &port );
- target = (const uint8_t *) &fields[ 1 ];
- end = ( (const uint8_t *) inRDataPtr ) + inRDataLen;
- for( ptr = target; ( ptr < end ) && ( *ptr != 0 ); ptr += ( 1 + *ptr ) ) {}
-
- if( ( priority == kDotLocalTestSRV_Priority ) &&
- ( weight == kDotLocalTestSRV_Weight ) &&
- ( port == kDotLocalTestSRV_Port ) &&
- ( ptr < end ) && DomainNameEqual( target, kDotLocalTestSRV_TargetName ) )
- {
- array = subtest->needSRV ? subtest->correctResults : subtest->duplicateResults;
- subtest->needSRV = false;
- }
- else
- {
- array = subtest->unexpectedResults;
- }
-
- rdataStr = NULL;
- DNSRecordDataToString( inRDataPtr, inRDataLen, kDNSServiceType_SRV, NULL, 0, &rdataStr );
- if( !rdataStr )
- {
- ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, inRDataLen );
- require_action( rdataStr, fatal, err = kNoMemoryErr );
- }
-
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", rdataStr );
- free( rdataStr );
- require_noerr( err, fatal );
-
-exit:
- if( err )
- {
- subtest->error = err;
- _DotLocalTestStateMachine( context );
- }
- return;
-
-fatal:
- ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-// ProbeConflictTestCmd
-//===========================================================================================================================
-
-#define kProbeConflictTestService_DefaultName "name"
-#define kProbeConflictTestService_Port 60000
-
-#define kProbeConflictTestTXTPtr "\x13" "PROBE-CONFLICT-TEST"
-#define kProbeConflictTestTXTLen sizeof_string( kProbeConflictTestTXTPtr )
-
-typedef struct
-{
- const char * description;
- const char * program;
- Boolean expectsRename;
-
-} ProbeConflictTestCase;
-
-#define kPCTProgPreWait "wait 1000;" // Wait 1 second before sending gratuitous response.
-#define kPCTProgPostWait "wait 8000;" // Wait 8 seconds after sending gratuitous response.
- // This allows ~2.75 seconds for probing and ~5 seconds for a rename.
-
-static const ProbeConflictTestCase kProbeConflictTestCases[] =
-{
- // No conflicts
-
- { "No probe conflicts.", kPCTProgPreWait "probes n-n-n;" "send;" kPCTProgPostWait, false },
-
- // One multicast probe conflict
-
- { "One multicast probe conflict (1).", kPCTProgPreWait "probes m;" "send;" kPCTProgPostWait, false },
- { "One multicast probe conflict (2).", kPCTProgPreWait "probes n-m;" "send;" kPCTProgPostWait, false },
- { "One multicast probe conflict (3).", kPCTProgPreWait "probes n-n-m;" "send;" kPCTProgPostWait, false },
-
- // One unicast probe conflict
-
- { "One unicast probe conflict (1).", kPCTProgPreWait "probes u;" "send;" kPCTProgPostWait, true },
- { "One unicast probe conflict (2).", kPCTProgPreWait "probes n-u;" "send;" kPCTProgPostWait, true },
- { "One unicast probe conflict (3).", kPCTProgPreWait "probes n-n-u;" "send;" kPCTProgPostWait, true },
-
- // One multicast and one unicast probe conflict
-
- { "Multicast and unicast probe conflict (1).", kPCTProgPreWait "probes m-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (2).", kPCTProgPreWait "probes m-n-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (3).", kPCTProgPreWait "probes m-n-n-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (4).", kPCTProgPreWait "probes n-m-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (5).", kPCTProgPreWait "probes n-m-n-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (6).", kPCTProgPreWait "probes n-m-n-n-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (7).", kPCTProgPreWait "probes n-n-m-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (8).", kPCTProgPreWait "probes n-n-m-n-u;" "send;" kPCTProgPostWait, true },
- { "Multicast and unicast probe conflict (9).", kPCTProgPreWait "probes n-n-m-n-n-u;" "send;" kPCTProgPostWait, true },
-
- // Two multicast probe conflicts
-
- { "Two multicast probe conflicts (1).", kPCTProgPreWait "probes m-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (2).", kPCTProgPreWait "probes m-n-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (3).", kPCTProgPreWait "probes m-n-n-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (4).", kPCTProgPreWait "probes n-m-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (5).", kPCTProgPreWait "probes n-m-n-m-n;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (6).", kPCTProgPreWait "probes n-m-n-n-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (7).", kPCTProgPreWait "probes n-n-m-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (8).", kPCTProgPreWait "probes n-n-m-n-m;" "send;" kPCTProgPostWait, true },
- { "Two multicast probe conflicts (9).", kPCTProgPreWait "probes n-n-m-n-n-m;" "send;" kPCTProgPostWait, true },
-};
-
-#define kProbeConflictTestCaseCount countof( kProbeConflictTestCases )
-
-typedef struct
-{
- DNSServiceRef registration; // Test service registration.
- NanoTime64 testStartTime; // Test's start time.
- NanoTime64 startTime; // Current test case's start time.
- MDNSColliderRef collider; // mDNS collider object.
- CFMutableArrayRef results; // Array of test case results.
- char * serviceName; // Test service's instance name as a string. (malloced)
- char * serviceType; // Test service's service type as a string. (malloced)
- uint8_t * recordName; // FQDN of collider's record (same as test service's SRV+TXT records). (malloced)
- unsigned int testCaseIndex; // Index of the current test case.
- uint32_t ifIndex; // Index of the interface that the collider is to operate on.
- char * outputFilePath; // File to write test results to. If NULL, then write to stdout. (malloced)
- OutputFormatType outputFormat; // Format of test report output.
- Boolean appendNewline; // True if a newline character should be appended to JSON output.
- Boolean registered; // True if the test service instance is currently registered.
- Boolean testFailed; // True if at least one test case failed.
-
-} ProbeConflictTestContext;
-
-static void DNSSD_API
- _ProbeConflictTestRegisterCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inType,
- const char * inDomain,
- void * inContext );
-static void _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError );
-static OSStatus _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext );
-static OSStatus _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed );
-static void _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext ) ATTRIBUTE_NORETURN;
-
-static void ProbeConflictTestCmd( void )
-{
- OSStatus err;
- ProbeConflictTestContext * context;
- const char * serviceName;
- char tag[ 6 + 1 ];
-
- context = (ProbeConflictTestContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- if( gProbeConflictTest_Interface )
- {
- err = InterfaceIndexFromArgString( gProbeConflictTest_Interface, &context->ifIndex );
- require_noerr_quiet( err, exit );
- }
- else
- {
- err = GetAnyMDNSInterface( NULL, &context->ifIndex );
- require_noerr_quiet( err, exit );
- }
-
- if( gProbeConflictTest_OutputFilePath )
- {
- context->outputFilePath = strdup( gProbeConflictTest_OutputFilePath );
- require_action( context->outputFilePath, exit, err = kNoMemoryErr );
- }
-
- context->appendNewline = gProbeConflictTest_OutputAppendNewline ? true : false;
- context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gProbeConflictTest_OutputFormat, &err,
- kOutputFormatStr_JSON, kOutputFormatType_JSON,
- kOutputFormatStr_XML, kOutputFormatType_XML,
- kOutputFormatStr_Binary, kOutputFormatType_Binary,
- NULL );
- require_noerr_quiet( err, exit );
-
- context->results = CFArrayCreateMutable( NULL, kProbeConflictTestCaseCount, &kCFTypeArrayCallBacks );
- require_action( context->results, exit, err = kNoMemoryErr );
-
- serviceName = gProbeConflictTest_UseComputerName ? NULL : kProbeConflictTestService_DefaultName;
-
- ASPrintF( &context->serviceType, "_pctest-%s._udp",
- _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
- require_action( context->serviceType, exit, err = kNoMemoryErr );
-
- context->testStartTime = NanoTimeGetCurrent();
- err = DNSServiceRegister( &context->registration, 0, context->ifIndex, serviceName, context->serviceType, "local.",
- NULL, htons( kProbeConflictTestService_Port ), 0, NULL, _ProbeConflictTestRegisterCallback, context );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( context->registration, dispatch_get_main_queue() );
- require_noerr( err, exit );
-
- dispatch_main();
-
-exit:
- exit( 1 );
-}
-
-//===========================================================================================================================
-// _ProbeConflictTestRegisterCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _ProbeConflictTestRegisterCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inType,
- const char * inDomain,
- void * inContext )
-{
- OSStatus err;
- ProbeConflictTestContext * const context = (ProbeConflictTestContext *) inContext;
-
- Unused( inSDRef );
- Unused( inType );
- Unused( inDomain );
-
- err = inError;
- require_noerr( err, exit );
-
- if( !context->registered )
- {
- if( inFlags & kDNSServiceFlagsAdd )
- {
- uint8_t * ptr;
- size_t recordNameLen;
- unsigned int len;
- uint8_t name[ kDomainNameLengthMax ];
-
- context->registered = true;
-
- FreeNullSafe( context->serviceName );
- context->serviceName = strdup( inName );
- require_action( context->serviceName, exit, err = kNoMemoryErr );
-
- err = DomainNameFromString( name, context->serviceName, NULL );
- require_noerr( err, exit );
-
- err = DomainNameAppendString( name, context->serviceType, NULL );
- require_noerr( err, exit );
-
- err = DomainNameAppendString( name, "local", NULL );
- require_noerr( err, exit );
-
- ForgetMem( &context->recordName );
- err = DomainNameDup( name, &context->recordName, &recordNameLen );
- require_noerr( err, exit );
- require_fatal( recordNameLen > 0, "Record name length is zero." ); // Prevents dubious static analyzer warning.
-
- // Make the first label all caps so that it's easier to spot in system logs.
-
- ptr = context->recordName;
- for( len = *ptr++; len > 0; --len, ++ptr ) *ptr = (uint8_t) toupper_safe( *ptr );
-
- err = _ProbeConflictTestStartNextTest( context );
- require_noerr( err, exit );
- }
- }
- else
- {
- if( !( inFlags & kDNSServiceFlagsAdd ) )
- {
- context->registered = false;
- err = _ProbeConflictTestStopCurrentTest( context, true );
- require_noerr( err, exit );
- }
- }
- err = kNoErr;
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// _ProbeConflictTestColliderStopHandler
-//===========================================================================================================================
-
-static void _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError )
-{
- OSStatus err;
- ProbeConflictTestContext * const context = (ProbeConflictTestContext *) inContext;
-
- err = inError;
- require_noerr_quiet( err, exit );
-
- ForgetCF( &context->collider );
-
- err = _ProbeConflictTestStopCurrentTest( context, false );
- require_noerr( err, exit );
-
- err = _ProbeConflictTestStartNextTest( context );
- require_noerr( err, exit );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// _ProbeConflictTestStartNextTest
-//===========================================================================================================================
-
-static OSStatus _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext )
-{
- OSStatus err;
- const ProbeConflictTestCase * testCase;
-
- check( !inContext->collider );
-
- if( inContext->testCaseIndex < kProbeConflictTestCaseCount )
- {
- testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
- }
- else
- {
- _ProbeConflictTestFinalizeAndExit( inContext );
- }
-
- err = MDNSColliderCreate( dispatch_get_main_queue(), &inContext->collider );
- require_noerr( err, exit );
-
- err = MDNSColliderSetProgram( inContext->collider, testCase->program );
- require_noerr( err, exit );
-
- err = MDNSColliderSetRecord( inContext->collider, inContext->recordName, kDNSServiceType_TXT,
- kProbeConflictTestTXTPtr, kProbeConflictTestTXTLen );
- require_noerr( err, exit );
-
- MDNSColliderSetProtocols( inContext->collider, kMDNSColliderProtocol_IPv4 );
- MDNSColliderSetInterfaceIndex( inContext->collider, inContext->ifIndex );
- MDNSColliderSetStopHandler( inContext->collider, _ProbeConflictTestColliderStopHandler, inContext );
-
- inContext->startTime = NanoTimeGetCurrent();
- err = MDNSColliderStart( inContext->collider );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _ProbeConflictTestStopCurrentTest
-//===========================================================================================================================
-
-#define kProbeConflictTestCaseResultKey_Description CFSTR( "description" )
-#define kProbeConflictTestCaseResultKey_StartTime CFSTR( "startTime" )
-#define kProbeConflictTestCaseResultKey_EndTime CFSTR( "endTime" )
-#define kProbeConflictTestCaseResultKey_ExpectedRename CFSTR( "expectedRename" )
-#define kProbeConflictTestCaseResultKey_ServiceName CFSTR( "serviceName" )
-#define kProbeConflictTestCaseResultKey_Passed CFSTR( "passed" )
-
-static OSStatus _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed )
-{
- OSStatus err;
- const ProbeConflictTestCase * testCase;
- NanoTime64 endTime;
- Boolean passed;
- char startTimeStr[ 32 ];
- char endTimeStr[ 32 ];
-
- endTime = NanoTimeGetCurrent();
-
- if( inContext->collider )
- {
- MDNSColliderSetStopHandler( inContext->collider, NULL, NULL );
- MDNSColliderStop( inContext->collider );
- CFRelease( inContext->collider );
- inContext->collider = NULL;
- }
-
- testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
- passed = ( ( testCase->expectsRename && inRenamed ) || ( !testCase->expectsRename && !inRenamed ) ) ? true : false;
- if( !passed ) inContext->testFailed = true;
-
- _NanoTime64ToDateString( inContext->startTime, startTimeStr, sizeof( startTimeStr ) );
- _NanoTime64ToDateString( endTime, endTimeStr, sizeof( endTimeStr ) );
-
- err = CFPropertyListAppendFormatted( kCFAllocatorDefault, inContext->results,
- "{"
- "%kO=%s" // description
- "%kO=%b" // expectedRename
- "%kO=%s" // startTime
- "%kO=%s" // endTime
- "%kO=%s" // serviceName
- "%kO=%b" // passed
- "}",
- kProbeConflictTestCaseResultKey_Description, testCase->description,
- kProbeConflictTestCaseResultKey_ExpectedRename, testCase->expectsRename,
- kProbeConflictTestCaseResultKey_StartTime, startTimeStr,
- kProbeConflictTestCaseResultKey_EndTime, endTimeStr,
- kProbeConflictTestCaseResultKey_ServiceName, inContext->serviceName,
- kProbeConflictTestCaseResultKey_Passed, passed );
- require_noerr( err, exit );
-
- ++inContext->testCaseIndex;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _ProbeConflictTestFinalizeAndExit
-//===========================================================================================================================
-
-#define kProbeConflictTestReportKey_StartTime CFSTR( "startTime" )
-#define kProbeConflictTestReportKey_EndTime CFSTR( "endTime" )
-#define kProbeConflictTestReportKey_ServiceType CFSTR( "serviceType" )
-#define kProbeConflictTestReportKey_Results CFSTR( "results" )
-#define kProbeConflictTestReportKey_Passed CFSTR( "passed" )
-
-static void _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext )
-{
- OSStatus err;
- CFPropertyListRef plist;
- NanoTime64 endTime;
- char startTimeStr[ 32 ];
- char endTimeStr[ 32 ];
-
- endTime = NanoTimeGetCurrent();
-
- check( !inContext->collider );
-
- _NanoTime64ToDateString( inContext->testStartTime, startTimeStr, sizeof( startTimeStr ) );
- _NanoTime64ToDateString( endTime, endTimeStr, sizeof( endTimeStr ) );
-
- err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
- "{"
- "%kO=%s" // startTime
- "%kO=%s" // endTime
- "%kO=%s" // serviceType
- "%kO=%O" // results
- "%kO=%b" // passed
- "}",
- kProbeConflictTestReportKey_StartTime, startTimeStr,
- kProbeConflictTestReportKey_EndTime, endTimeStr,
- kProbeConflictTestReportKey_ServiceType, inContext->serviceType,
- kProbeConflictTestReportKey_Results, inContext->results,
- kProbeConflictTestReportKey_Passed, inContext->testFailed ? false : true );
- require_noerr( err, exit );
- ForgetCF( &inContext->results );
-
- err = OutputPropertyList( plist, inContext->outputFormat, inContext->appendNewline, inContext->outputFilePath );
- CFRelease( plist );
- require_noerr( err, exit );
-
- exit( inContext->testFailed ? 2 : 0 );
-
-exit:
- ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-// SSDPDiscoverCmd
-//===========================================================================================================================
-
-#define kSSDPPort 1900
-
-typedef struct
-{
- HTTPHeader header; // HTTP header object for sending and receiving.
- dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
- dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
- int receiveSecs; // After send, the amount of time to spend receiving.
- uint32_t ifindex; // Index of the interface over which to send the query.
- Boolean useIPv4; // True if the query should be sent via IPv4 multicast.
- Boolean useIPv6; // True if the query should be sent via IPv6 multicast.
-
-} SSDPDiscoverContext;
-
-static void SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext );
-static void SSDPDiscoverReadHandler( void *inContext );
-static int SocketToPortNumber( SocketRef inSock );
-static OSStatus WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST );
-
-static void SSDPDiscoverCmd( void )
-{
- OSStatus err;
- struct timeval now;
- SSDPDiscoverContext * context;
- dispatch_source_t signalSource = NULL;
- SocketRef sockV4 = kInvalidSocketRef;
- SocketRef sockV6 = kInvalidSocketRef;
- ssize_t n;
- int sendCount;
-
- // Set up SIGINT handler.
-
- signal( SIGINT, SIG_IGN );
- err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
- require_noerr( err, exit );
- dispatch_resume( signalSource );
-
- // Check command parameters.
-
- if( gSSDPDiscover_ReceiveSecs < -1 )
- {
- FPrintF( stdout, "Invalid receive time: %d seconds.\n", gSSDPDiscover_ReceiveSecs );
- err = kParamErr;
- goto exit;
- }
-
- // Create context.
-
- context = (SSDPDiscoverContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->receiveSecs = gSSDPDiscover_ReceiveSecs;
- context->useIPv4 = ( gSSDPDiscover_UseIPv4 || !gSSDPDiscover_UseIPv6 ) ? true : false;
- context->useIPv6 = ( gSSDPDiscover_UseIPv6 || !gSSDPDiscover_UseIPv4 ) ? true : false;
-
- err = InterfaceIndexFromArgString( gInterface, &context->ifindex );
- require_noerr_quiet( err, exit );
-
- // Set up IPv4 socket.
-
- if( context->useIPv4 )
- {
- int port;
- err = UDPClientSocketOpen( AF_INET, NULL, 0, -1, &port, &sockV4 );
- require_noerr( err, exit );
-
- err = SocketSetMulticastInterface( sockV4, NULL, context->ifindex );
- require_noerr( err, exit );
-
- err = setsockopt( sockV4, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
- err = map_socket_noerr_errno( sockV4, err );
- require_noerr( err, exit );
- }
-
- // Set up IPv6 socket.
-
- if( context->useIPv6 )
- {
- err = UDPClientSocketOpen( AF_INET6, NULL, 0, -1, NULL, &sockV6 );
- require_noerr( err, exit );
-
- err = SocketSetMulticastInterface( sockV6, NULL, context->ifindex );
- require_noerr( err, exit );
-
- err = setsockopt( sockV6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
- err = map_socket_noerr_errno( sockV6, err );
- require_noerr( err, exit );
- }
-
- // Print prologue.
-
- SSDPDiscoverPrintPrologue( context );
-
- // Send mDNS query message.
-
- sendCount = 0;
- if( IsValidSocket( sockV4 ) )
- {
- struct sockaddr_in mcastAddr4;
-
- memset( &mcastAddr4, 0, sizeof( mcastAddr4 ) );
- SIN_LEN_SET( &mcastAddr4 );
- mcastAddr4.sin_family = AF_INET;
- mcastAddr4.sin_port = htons( kSSDPPort );
- mcastAddr4.sin_addr.s_addr = htonl( 0xEFFFFFFA ); // 239.255.255.250
-
- err = WriteSSDPSearchRequest( &context->header, &mcastAddr4, gSSDPDiscover_MX, gSSDPDiscover_ST );
- require_noerr( err, exit );
-
- n = sendto( sockV4, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr4,
- (socklen_t) sizeof( mcastAddr4 ) );
- err = map_socket_value_errno( sockV4, n == (ssize_t) context->header.len, n );
- if( err )
- {
- FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
- ForgetSocket( &sockV4 );
- }
- else
- {
- if( gSSDPDiscover_Verbose )
- {
- gettimeofday( &now, NULL );
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "Send time: %{du:time}\n", &now );
- FPrintF( stdout, "Source Port: %d\n", SocketToPortNumber( sockV4 ) );
- FPrintF( stdout, "Destination: %##a\n", &mcastAddr4 );
- FPrintF( stdout, "Message size: %zu\n", context->header.len );
- FPrintF( stdout, "HTTP header:\n%1{text}", context->header.buf, context->header.len );
- }
- ++sendCount;
- }
- }
-
- if( IsValidSocket( sockV6 ) )
- {
- struct sockaddr_in6 mcastAddr6;
-
- memset( &mcastAddr6, 0, sizeof( mcastAddr6 ) );
- SIN6_LEN_SET( &mcastAddr6 );
- mcastAddr6.sin6_family = AF_INET6;
- mcastAddr6.sin6_port = htons( kSSDPPort );
- mcastAddr6.sin6_addr.s6_addr[ 0 ] = 0xFF; // SSDP IPv6 link-local multicast address FF02::C
- mcastAddr6.sin6_addr.s6_addr[ 1 ] = 0x02;
- mcastAddr6.sin6_addr.s6_addr[ 15 ] = 0x0C;
-
- err = WriteSSDPSearchRequest( &context->header, &mcastAddr6, gSSDPDiscover_MX, gSSDPDiscover_ST );
- require_noerr( err, exit );
-
- n = sendto( sockV6, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr6,
- (socklen_t) sizeof( mcastAddr6 ) );
- err = map_socket_value_errno( sockV6, n == (ssize_t) context->header.len, n );
- if( err )
- {
- FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
- ForgetSocket( &sockV6 );
- }
- else
- {
- if( gSSDPDiscover_Verbose )
- {
- gettimeofday( &now, NULL );
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "Send time: %{du:time}\n", &now );
- FPrintF( stdout, "Source Port: %d\n", SocketToPortNumber( sockV6 ) );
- FPrintF( stdout, "Destination: %##a\n", &mcastAddr6 );
- FPrintF( stdout, "Message size: %zu\n", context->header.len );
- FPrintF( stdout, "HTTP header:\n%1{text}", context->header.buf, context->header.len );
- }
- ++sendCount;
- }
- }
- require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
-
- // If there's no wait period after the send, then exit.
-
- if( context->receiveSecs == 0 ) goto exit;
-
- // Create dispatch read sources for socket(s).
-
- if( IsValidSocket( sockV4 ) )
- {
- SocketContext * sockCtx;
-
- err = SocketContextCreate( sockV4, context, &sockCtx );
- require_noerr( err, exit );
- sockV4 = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
- &context->readSourceV4 );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSourceV4 );
- }
-
- if( IsValidSocket( sockV6 ) )
- {
- SocketContext * sockCtx;
-
- err = SocketContextCreate( sockV6, context, &sockCtx );
- require_noerr( err, exit );
- sockV6 = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
- &context->readSourceV6 );
- if( err ) ForgetSocketContext( &sockCtx );
- require_noerr( err, exit );
-
- dispatch_resume( context->readSourceV6 );
- }
-
- if( context->receiveSecs > 0 )
- {
- dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
- Exit );
- }
- dispatch_main();
-
-exit:
- ForgetSocket( &sockV4 );
- ForgetSocket( &sockV6 );
- dispatch_source_forget( &signalSource );
- if( err ) exit( 1 );
-}
-
-static int SocketToPortNumber( SocketRef inSock )
-{
- OSStatus err;
- sockaddr_ip sip;
- socklen_t len;
-
- len = (socklen_t) sizeof( sip );
- err = getsockname( inSock, &sip.sa, &len );
- err = map_socket_noerr_errno( inSock, err );
- check_noerr( err );
- return( err ? -1 : SockAddrGetPort( &sip ) );
-}
-
-static OSStatus WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST )
-{
- OSStatus err;
-
- err = HTTPHeader_InitRequest( inHeader, "M-SEARCH", "*", "HTTP/1.1" );
- require_noerr( err, exit );
-
- err = HTTPHeader_SetField( inHeader, "Host", "%##a", inHostSA );
- require_noerr( err, exit );
-
- err = HTTPHeader_SetField( inHeader, "ST", "%s", inST ? inST : "ssdp:all" );
- require_noerr( err, exit );
-
- err = HTTPHeader_SetField( inHeader, "Man", "\"ssdp:discover\"" );
- require_noerr( err, exit );
-
- err = HTTPHeader_SetField( inHeader, "MX", "%d", inMX );
- require_noerr( err, exit );
-
- err = HTTPHeader_Commit( inHeader );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// SSDPDiscoverPrintPrologue
-//===========================================================================================================================
-
-static void SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext )
-{
- const int receiveSecs = inContext->receiveSecs;
- const char * ifName;
- char ifNameBuf[ IF_NAMESIZE + 1 ];
- NetTransportType ifType;
-
- ifName = if_indextoname( inContext->ifindex, ifNameBuf );
-
- ifType = kNetTransportType_Undefined;
- if( ifName ) SocketGetInterfaceInfo( kInvalidSocketRef, ifName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ifType );
-
- FPrintF( stdout, "Interface: %s/%d/%s\n",
- ifName ? ifName : "?", inContext->ifindex, NetTransportTypeToString( ifType ) );
- FPrintF( stdout, "IP protocols: %?s%?s%?s\n",
- inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
- FPrintF( stdout, "Receive duration: " );
- if( receiveSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
- else FPrintF( stdout, "∞\n" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
-}
-
-//===========================================================================================================================
-// SSDPDiscoverReadHandler
-//===========================================================================================================================
-
-static void SSDPDiscoverReadHandler( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- SSDPDiscoverContext * const context = (SSDPDiscoverContext *) sockCtx->userContext;
- HTTPHeader * const header = &context->header;
- sockaddr_ip fromAddr;
- size_t msgLen;
-
- gettimeofday( &now, NULL );
-
- err = SocketRecvFrom( sockCtx->sock, header->buf, sizeof( header->buf ), &msgLen, &fromAddr, sizeof( fromAddr ),
- NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "Receive time: %{du:time}\n", &now );
- FPrintF( stdout, "Source: %##a\n", &fromAddr );
- FPrintF( stdout, "Message size: %zu\n", msgLen );
- header->len = msgLen;
- if( HTTPHeader_Validate( header ) )
- {
- FPrintF( stdout, "HTTP header:\n%1{text}", header->buf, header->len );
- if( header->extraDataLen > 0 )
- {
- FPrintF( stdout, "HTTP body: %1.1H", header->extraDataPtr, (int) header->extraDataLen, INT_MAX );
- }
- }
- else
- {
- FPrintF( stdout, "Invalid HTTP message:\n%1.1H", header->buf, (int) msgLen, INT_MAX );
- goto exit;
- }
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// HTTPHeader_Validate
-//
-// Parses for the end of an HTTP header and updates the HTTPHeader structure so it's ready to parse. Returns true if valid.
-// This assumes the "buf" and "len" fields are set. The other fields are set by this function.
-//
-// Note: This was copied from CoreUtils because the HTTPHeader_Validate function is currently not exported in the framework.
-//===========================================================================================================================
-
-Boolean HTTPHeader_Validate( HTTPHeader *inHeader )
-{
- const char * src;
- const char * end;
-
- // Check for interleaved binary data (4 byte header that begins with $). See RFC 2326 section 10.12.
-
- require( inHeader->len < sizeof( inHeader->buf ), exit );
- src = inHeader->buf;
- end = src + inHeader->len;
- if( ( ( end - src ) >= 4 ) && ( src[ 0 ] == '$' ) )
- {
- src += 4;
- }
- else
- {
- // Search for an empty line (HTTP-style header/body separator). CRLFCRLF, LFCRLF, or LFLF accepted.
- // $$$ TO DO: Start from the last search location to avoid re-searching the same data over and over.
-
- for( ;; )
- {
- while( ( src < end ) && ( src[ 0 ] != '\n' ) ) ++src;
- if( src >= end ) goto exit;
- ++src;
- if( ( ( end - src ) >= 2 ) && ( src[ 0 ] == '\r' ) && ( src[ 1 ] == '\n' ) ) // CFLFCRLF or LFCRLF
- {
- src += 2;
- break;
- }
- else if( ( ( end - src ) >= 1 ) && ( src[ 0 ] == '\n' ) ) // LFLF
- {
- src += 1;
- break;
- }
- }
- }
- inHeader->extraDataPtr = src;
- inHeader->extraDataLen = (size_t)( end - src );
- inHeader->len = (size_t)( src - inHeader->buf );
- return( true );
-
-exit:
- return( false );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// ResQueryCmd
-//===========================================================================================================================
-
-// res_query() from libresolv is actually called res_9_query (see /usr/include/resolv.h).
-
-SOFT_LINK_LIBRARY_EX( "/usr/lib", resolv );
-SOFT_LINK_FUNCTION_EX( resolv, res_9_query,
- int,
- ( const char *dname, int class, int type, u_char *answer, int anslen ),
- ( dname, class, type, answer, anslen ) );
-
-// res_query() from libinfo
-
-SOFT_LINK_LIBRARY_EX( "/usr/lib", info );
-SOFT_LINK_FUNCTION_EX( info, res_query,
- int,
- ( const char *dname, int class, int type, u_char *answer, int anslen ),
- ( dname, class, type, answer, anslen ) );
-
-typedef int ( *res_query_f )( const char *dname, int class, int type, u_char *answer, int anslen );
-
-static void ResQueryCmd( void )
-{
- OSStatus err;
- res_query_f res_query_ptr;
- int n;
- uint16_t type, class;
- uint8_t answer[ 1024 ];
-
- // Get pointer to one of the res_query() functions.
-
- if( gResQuery_UseLibInfo )
- {
- if( !SOFT_LINK_HAS_FUNCTION( info, res_query ) )
- {
- FPrintF( stderr, "Failed to soft link res_query from libinfo.\n" );
- err = kNotFoundErr;
- goto exit;
- }
- res_query_ptr = soft_res_query;
- }
- else
- {
- if( !SOFT_LINK_HAS_FUNCTION( resolv, res_9_query ) )
- {
- FPrintF( stderr, "Failed to soft link res_query from libresolv.\n" );
- err = kNotFoundErr;
- goto exit;
- }
- res_query_ptr = soft_res_9_query;
- }
-
- // Get record type.
-
- err = RecordTypeFromArgString( gResQuery_Type, &type );
- require_noerr( err, exit );
-
- // Get record class.
-
- if( gResQuery_Class )
- {
- err = RecordClassFromArgString( gResQuery_Class, &class );
- require_noerr( err, exit );
- }
- else
- {
- class = kDNSServiceClass_IN;
- }
-
- // Print prologue.
-
- FPrintF( stdout, "Name: %s\n", gResQuery_Name );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
- FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
- // Call res_query().
-
- n = res_query_ptr( gResQuery_Name, class, type, (u_char *) answer, (int) sizeof( answer ) );
- if( n < 0 )
- {
- FPrintF( stderr, "res_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
- err = kUnknownErr;
- goto exit;
- }
-
- // Print result.
-
- FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// ResolvDNSQueryCmd
-//===========================================================================================================================
-
-// dns_handle_t is defined as a pointer to a privately-defined struct in /usr/include/dns.h. It's defined as a void * here to
-// avoid including the header file.
-
-typedef void * dns_handle_t;
-
-SOFT_LINK_FUNCTION_EX( resolv, dns_open, dns_handle_t, ( const char *path ), ( path ) );
-SOFT_LINK_FUNCTION_VOID_RETURN_EX( resolv, dns_free, ( dns_handle_t *dns ), ( dns ) );
-SOFT_LINK_FUNCTION_EX( resolv, dns_query,
- int32_t, (
- dns_handle_t dns,
- const char * name,
- uint32_t dnsclass,
- uint32_t dnstype,
- char * buf,
- uint32_t len,
- struct sockaddr * from,
- uint32_t * fromlen ),
- ( dns, name, dnsclass, dnstype, buf, len, from, fromlen ) );
-
-static void ResolvDNSQueryCmd( void )
-{
- OSStatus err;
- int n;
- dns_handle_t dns = NULL;
- uint16_t type, class;
- sockaddr_ip from;
- uint32_t fromLen;
- uint8_t answer[ 1024 ];
-
- // Make sure that the required symbols are available.
-
- if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_open ) )
- {
- FPrintF( stderr, "Failed to soft link dns_open from libresolv.\n" );
- err = kNotFoundErr;
- goto exit;
- }
-
- if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_free ) )
- {
- FPrintF( stderr, "Failed to soft link dns_free from libresolv.\n" );
- err = kNotFoundErr;
- goto exit;
- }
-
- if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_query ) )
- {
- FPrintF( stderr, "Failed to soft link dns_query from libresolv.\n" );
- err = kNotFoundErr;
- goto exit;
- }
-
- // Get record type.
-
- err = RecordTypeFromArgString( gResolvDNSQuery_Type, &type );
- require_noerr( err, exit );
-
- // Get record class.
-
- if( gResolvDNSQuery_Class )
- {
- err = RecordClassFromArgString( gResolvDNSQuery_Class, &class );
- require_noerr( err, exit );
- }
- else
- {
- class = kDNSServiceClass_IN;
- }
-
- // Get dns handle.
-
- dns = soft_dns_open( gResolvDNSQuery_Path );
- if( !dns )
- {
- FPrintF( stderr, "dns_open( %s ) failed.\n", gResolvDNSQuery_Path );
- err = kUnknownErr;
- goto exit;
- }
-
- // Print prologue.
-
- FPrintF( stdout, "Name: %s\n", gResolvDNSQuery_Name );
- FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
- FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
- FPrintF( stdout, "Path: %s\n", gResolvDNSQuery_Path ? gResolvDNSQuery_Name : "<NULL>" );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
- // Call dns_query().
-
- memset( &from, 0, sizeof( from ) );
- fromLen = (uint32_t) sizeof( from );
- n = soft_dns_query( dns, gResolvDNSQuery_Name, class, type, (char *) answer, (uint32_t) sizeof( answer ), &from.sa,
- &fromLen );
- if( n < 0 )
- {
- FPrintF( stderr, "dns_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
- err = kUnknownErr;
- goto exit;
- }
-
- // Print result.
-
- FPrintF( stdout, "From: %##a\n", &from );
- FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
-
-exit:
- if( dns ) soft_dns_free( dns );
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// CFHostCmd
-//===========================================================================================================================
-
-static void
- _CFHostResolveCallback(
- CFHostRef inHost,
- CFHostInfoType inInfoType,
- const CFStreamError * inError,
- void * inInfo );
-
-static void CFHostCmd( void )
-{
- OSStatus err;
- CFStringRef name;
- Boolean success;
- CFHostRef host = NULL;
- CFHostClientContext context;
- CFStreamError streamErr;
-
- name = CFStringCreateWithCString( kCFAllocatorDefault, gCFHost_Name, kCFStringEncodingUTF8 );
- require_action( name, exit, err = kUnknownErr );
-
- host = CFHostCreateWithName( kCFAllocatorDefault, name );
- ForgetCF( &name );
- require_action( host, exit, err = kUnknownErr );
-
- memset( &context, 0, sizeof( context ) );
- success = CFHostSetClient( host, _CFHostResolveCallback, &context );
- require_action( success, exit, err = kUnknownErr );
-
- CFHostScheduleWithRunLoop( host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
-
- // Print prologue.
-
- FPrintF( stdout, "Hostname: %s\n", gCFHost_Name );
- FPrintF( stdout, "Start time: %{du:time}\n", NULL );
- FPrintF( stdout, "---\n" );
-
- success = CFHostStartInfoResolution( host, kCFHostAddresses, &streamErr );
- require_action( success, exit, err = kUnknownErr );
- err = kNoErr;
-
- CFRunLoopRun();
-
-exit:
- CFReleaseNullSafe( host );
- if( err ) exit( 1 );
-}
-
-static void _CFHostResolveCallback( CFHostRef inHost, CFHostInfoType inInfoType, const CFStreamError *inError, void *inInfo )
-{
- OSStatus err;
- struct timeval now;
-
- gettimeofday( &now, NULL );
-
- Unused( inInfoType );
- Unused( inInfo );
-
- if( inError && ( inError->domain != 0 ) && ( inError->error ) )
- {
- err = inError->error;
- if( inError->domain == kCFStreamErrorDomainNetDB )
- {
- FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
- }
- else
- {
- FPrintF( stderr, "Error %#m\n", err );
- }
- }
- else
- {
- CFArrayRef addresses;
- CFIndex count, i;
- CFDataRef addrData;
- const struct sockaddr * sockAddr;
- Boolean wasResolved = false;
-
- addresses = CFHostGetAddressing( inHost, &wasResolved );
- check( wasResolved );
-
- if( addresses )
- {
- count = CFArrayGetCount( addresses );
- for( i = 0; i < count; ++i )
- {
- addrData = CFArrayGetCFDataAtIndex( addresses, i, &err );
- require_noerr( err, exit );
-
- sockAddr = (const struct sockaddr *) CFDataGetBytePtr( addrData );
- FPrintF( stdout, "%##a\n", sockAddr );
- }
- }
- err = kNoErr;
- }
-
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "End time: %{du:time}\n", &now );
-
- if( gCFHost_WaitSecs > 0 ) sleep( (unsigned int) gCFHost_WaitSecs );
-
-exit:
- exit( err ? 1 : 0 );
-}
-
-//===========================================================================================================================
-// DNSConfigAddCmd
-//
-// Note: Based on ajn's supplemental test tool.
-//===========================================================================================================================
-
-static void DNSConfigAddCmd( void )
-{
- OSStatus err;
- CFMutableDictionaryRef dict = NULL;
- CFMutableArrayRef array = NULL;
- size_t i;
- SCDynamicStoreRef store = NULL;
- CFStringRef key = NULL;
- Boolean success;
-
- // Create dictionary.
-
- dict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
- require_action( dict, exit, err = kNoMemoryErr );
-
- // Add DNS server IP addresses.
-
- array = CFArrayCreateMutable( NULL, (CFIndex) gDNSConfigAdd_IPAddrCount, &kCFTypeArrayCallBacks );
- require_action( array, exit, err = kNoMemoryErr );
-
- for( i = 0; i < gDNSConfigAdd_IPAddrCount; ++i )
- {
- CFStringRef addrStr;
-
- addrStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_IPAddrArray[ i ], kCFStringEncodingUTF8 );
- require_action( addrStr, exit, err = kUnknownErr );
-
- CFArrayAppendValue( array, addrStr );
- CFRelease( addrStr );
- }
-
- CFDictionarySetValue( dict, kSCPropNetDNSServerAddresses, array );
- ForgetCF( &array );
-
- // Add domains, if any.
-
- array = CFArrayCreateMutable( NULL, (CFIndex) Min( gDNSConfigAdd_DomainCount, 1 ), &kCFTypeArrayCallBacks );
- require_action( array, exit, err = kNoMemoryErr );
-
- if( gDNSConfigAdd_DomainCount > 0 )
- {
- for( i = 0; i < gDNSConfigAdd_DomainCount; ++i )
- {
- CFStringRef domainStr;
-
- domainStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_DomainArray[ i ], kCFStringEncodingUTF8 );
- require_action( domainStr, exit, err = kUnknownErr );
-
- CFArrayAppendValue( array, domainStr );
- CFRelease( domainStr );
- }
- }
- else
- {
- // There are no domains, but the domain array needs to be non-empty, so add a zero-length string to the array.
-
- CFArrayAppendValue( array, CFSTR( "" ) );
- }
-
- CFDictionarySetValue( dict, kSCPropNetDNSSupplementalMatchDomains, array );
- ForgetCF( &array );
-
- // Add interface, if any.
-
- if( gDNSConfigAdd_Interface )
- {
- err = CFDictionarySetCString( dict, kSCPropInterfaceName, gDNSConfigAdd_Interface, kSizeCString );
- require_noerr( err, exit );
-
- CFDictionarySetValue( dict, kSCPropNetDNSConfirmedServiceID, gDNSConfigAdd_ID );
- }
-
- // Set dictionary in dynamic store.
-
- store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
- err = map_scerror( store );
- require_noerr( err, exit );
-
- key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigAdd_ID, kSCEntNetDNS );
- require_action( key, exit, err = kUnknownErr );
-
- success = SCDynamicStoreSetValue( store, key, dict );
- require_action( success, exit, err = kUnknownErr );
-
-exit:
- CFReleaseNullSafe( dict );
- CFReleaseNullSafe( array );
- CFReleaseNullSafe( store );
- CFReleaseNullSafe( key );
- gExitCode = err ? 1 : 0;
-}
-
-//===========================================================================================================================
-// DNSConfigRemoveCmd
-//===========================================================================================================================
-
-static void DNSConfigRemoveCmd( void )
-{
- OSStatus err;
- SCDynamicStoreRef store = NULL;
- CFStringRef key = NULL;
- Boolean success;
-
- store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
- err = map_scerror( store );
- require_noerr( err, exit );
-
- key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigRemove_ID, kSCEntNetDNS );
- require_action( key, exit, err = kUnknownErr );
-
- success = SCDynamicStoreRemoveValue( store, key );
- require_action( success, exit, err = kUnknownErr );
-
-exit:
- CFReleaseNullSafe( store );
- CFReleaseNullSafe( key );
- gExitCode = err ? 1 : 0;
-}
-#endif // TARGET_OS_DARWIN
-
-//===========================================================================================================================
-// DaemonVersionCmd
-//===========================================================================================================================
-
-static void DaemonVersionCmd( void )
-{
- OSStatus err;
- uint32_t size, version;
- char strBuf[ 16 ];
-
- size = (uint32_t) sizeof( version );
- err = DNSServiceGetProperty( kDNSServiceProperty_DaemonVersion, &version, &size );
- require_noerr( err, exit );
-
- FPrintF( stdout, "Daemon version: %s\n", SourceVersionToCString( version, strBuf ) );
-
-exit:
- if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-// Exit
-//===========================================================================================================================
-
-static void Exit( void *inContext )
-{
- const char * const reason = (const char *) inContext;
-
- FPrintF( stdout, "---\n" );
- FPrintF( stdout, "End time: %{du:time}\n", NULL );
- if( reason ) FPrintF( stdout, "End reason: %s\n", reason );
- exit( gExitCode );
-}
-
-//===========================================================================================================================
-// PrintFTimestampHandler
-//===========================================================================================================================
-
-static int
- PrintFTimestampHandler(
- PrintFContext * inContext,
- PrintFFormat * inFormat,
- PrintFVAList * inArgs,
- void * inUserContext )
-{
- struct timeval now;
- const struct timeval * tv;
- struct tm * localTime;
- size_t len;
- int n;
- char dateTimeStr[ 32 ];
-
- Unused( inUserContext );
-
- tv = va_arg( inArgs->args, const struct timeval * );
- require_action_quiet( !inFormat->suppress, exit, n = 0 );
-
- if( !tv )
- {
- gettimeofday( &now, NULL );
- tv = &now;
- }
- localTime = localtime( &tv->tv_sec );
- len = strftime( dateTimeStr, sizeof( dateTimeStr ), "%Y-%m-%d %H:%M:%S", localTime );
- if( len == 0 ) dateTimeStr[ 0 ] = '\0';
-
- n = PrintFCore( inContext, "%s.%06u", dateTimeStr, (unsigned int) tv->tv_usec );
-
-exit:
- return( n );
-}
-
-//===========================================================================================================================
-// PrintFDNSMessageHandler
-//===========================================================================================================================
-
-static int
- PrintFDNSMessageHandler(
- PrintFContext * inContext,
- PrintFFormat * inFormat,
- PrintFVAList * inArgs,
- void * inUserContext )
-{
- OSStatus err;
- const void * msgPtr;
- size_t msgLen;
- char * text;
- int n;
- Boolean isMDNS;
- Boolean printRawRData;
-
- Unused( inUserContext );
-
- msgPtr = va_arg( inArgs->args, const void * );
- msgLen = va_arg( inArgs->args, size_t );
- require_action_quiet( !inFormat->suppress, exit, n = 0 );
-
- isMDNS = ( inFormat->altForm > 0 ) ? true : false;
- if( inFormat->precision == 0 ) printRawRData = false;
- else if( inFormat->precision == 1 ) printRawRData = true;
- else
- {
- n = PrintFCore( inContext, "<< BAD %%{du:dnsmsg} PRECISION >>" );
- goto exit;
- }
-
- err = DNSMessageToText( msgPtr, msgLen, isMDNS, printRawRData, &text );
- if( !err )
- {
- n = PrintFCore( inContext, "%*{text}", inFormat->fieldWidth, text, kSizeCString );
- free( text );
- }
- else
- {
- n = PrintFCore( inContext, "%*.1H", inFormat->fieldWidth, msgPtr, (int) msgLen, (int) msgLen );
- }
-
-exit:
- return( n );
-}
-
-//===========================================================================================================================
-// PrintFAddRmvFlagsHandler
-//===========================================================================================================================
-
-static int
- PrintFAddRmvFlagsHandler(
- PrintFContext * inContext,
- PrintFFormat * inFormat,
- PrintFVAList * inArgs,
- void * inUserContext )
-{
- DNSServiceFlags flags;
- int n;
-
- Unused( inUserContext );
-
- flags = va_arg( inArgs->args, DNSServiceFlags );
- require_action_quiet( !inFormat->suppress, exit, n = 0 );
-
- n = PrintFCore( inContext, "%08X %s%c%c", flags,
- ( flags & kDNSServiceFlagsAdd ) ? "Add" : "Rmv",
- ( flags & kDNSServiceFlagsMoreComing ) ? '+' : ' ',
- ( flags & kDNSServiceFlagsExpiredAnswer ) ? '!' : ' ' );
-
-exit:
- return( n );
-}
-
-//===========================================================================================================================
-// GetDNSSDFlagsFromOpts
-//===========================================================================================================================
-
-static DNSServiceFlags GetDNSSDFlagsFromOpts( void )
-{
- DNSServiceFlags flags;
-
- flags = (DNSServiceFlags) gDNSSDFlags;
- if( flags & kDNSServiceFlagsShareConnection )
- {
- FPrintF( stderr, "*** Warning: kDNSServiceFlagsShareConnection (0x%X) is explicitly set in flag parameters.\n",
- kDNSServiceFlagsShareConnection );
- }
-
- if( gDNSSDFlag_AllowExpiredAnswers ) flags |= kDNSServiceFlagsAllowExpiredAnswers;
- if( gDNSSDFlag_BrowseDomains ) flags |= kDNSServiceFlagsBrowseDomains;
- if( gDNSSDFlag_DenyCellular ) flags |= kDNSServiceFlagsDenyCellular;
- if( gDNSSDFlag_DenyExpensive ) flags |= kDNSServiceFlagsDenyExpensive;
- if( gDNSSDFlag_ForceMulticast ) flags |= kDNSServiceFlagsForceMulticast;
- if( gDNSSDFlag_IncludeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
- if( gDNSSDFlag_NoAutoRename ) flags |= kDNSServiceFlagsNoAutoRename;
- if( gDNSSDFlag_PathEvaluationDone ) flags |= kDNSServiceFlagsPathEvaluationDone;
- if( gDNSSDFlag_RegistrationDomains ) flags |= kDNSServiceFlagsRegistrationDomains;
- if( gDNSSDFlag_ReturnIntermediates ) flags |= kDNSServiceFlagsReturnIntermediates;
- if( gDNSSDFlag_Shared ) flags |= kDNSServiceFlagsShared;
- if( gDNSSDFlag_SuppressUnusable ) flags |= kDNSServiceFlagsSuppressUnusable;
- if( gDNSSDFlag_Timeout ) flags |= kDNSServiceFlagsTimeout;
- if( gDNSSDFlag_UnicastResponse ) flags |= kDNSServiceFlagsUnicastResponse;
- if( gDNSSDFlag_Unique ) flags |= kDNSServiceFlagsUnique;
- if( gDNSSDFlag_WakeOnResolve ) flags |= kDNSServiceFlagsWakeOnResolve;
-
- return( flags );
-}
-
-//===========================================================================================================================
-// CreateConnectionFromArgString
-//===========================================================================================================================
-
-static OSStatus
- CreateConnectionFromArgString(
- const char * inString,
- dispatch_queue_t inQueue,
- DNSServiceRef * outSDRef,
- ConnectionDesc * outDesc )
-{
- OSStatus err;
- DNSServiceRef sdRef = NULL;
- ConnectionType type;
- int32_t pid = -1; // Initializing because the analyzer claims pid may be used uninitialized.
- uint8_t uuid[ 16 ];
-
- if( strcasecmp( inString, kConnectionArg_Normal ) == 0 )
- {
- err = DNSServiceCreateConnection( &sdRef );
- require_noerr( err, exit );
- type = kConnectionType_Normal;
- }
- else if( stricmp_prefix( inString, kConnectionArgPrefix_PID ) == 0 )
- {
- const char * const pidStr = inString + sizeof_string( kConnectionArgPrefix_PID );
-
- err = StringToInt32( pidStr, &pid );
- if( err )
- {
- FPrintF( stderr, "Invalid delegate connection PID value: %s\n", pidStr );
- err = kParamErr;
- goto exit;
- }
-
- memset( uuid, 0, sizeof( uuid ) );
- err = DNSServiceCreateDelegateConnection( &sdRef, pid, uuid );
- if( err )
- {
- FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for PID %d\n", err, pid );
- goto exit;
- }
- type = kConnectionType_DelegatePID;
- }
- else if( stricmp_prefix( inString, kConnectionArgPrefix_UUID ) == 0 )
- {
- const char * const uuidStr = inString + sizeof_string( kConnectionArgPrefix_UUID );
-
- check_compile_time_code( sizeof( uuid ) == sizeof( uuid_t ) );
-
- err = StringToUUID( uuidStr, kSizeCString, false, uuid );
- if( err )
- {
- FPrintF( stderr, "Invalid delegate connection UUID value: %s\n", uuidStr );
- err = kParamErr;
- goto exit;
- }
-
- err = DNSServiceCreateDelegateConnection( &sdRef, 0, uuid );
- if( err )
- {
- FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for UUID %#U\n", err, uuid );
- goto exit;
- }
- type = kConnectionType_DelegateUUID;
- }
- else
- {
- FPrintF( stderr, "Unrecognized connection string \"%s\".\n", inString );
- err = kParamErr;
- goto exit;
- }
-
- err = DNSServiceSetDispatchQueue( sdRef, inQueue );
- require_noerr( err, exit );
-
- *outSDRef = sdRef;
- if( outDesc )
- {
- outDesc->type = type;
- if( type == kConnectionType_DelegatePID ) outDesc->delegate.pid = pid;
- else if( type == kConnectionType_DelegateUUID ) memcpy( outDesc->delegate.uuid, uuid, 16 );
- }
- sdRef = NULL;
-
-exit:
- if( sdRef ) DNSServiceRefDeallocate( sdRef );
- return( err );
-}
-
-//===========================================================================================================================
-// InterfaceIndexFromArgString
-//===========================================================================================================================
-
-static OSStatus InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex )
-{
- OSStatus err;
- uint32_t ifIndex;
-
- if( inString )
- {
- ifIndex = if_nametoindex( inString );
- if( ifIndex == 0 )
- {
- err = StringToUInt32( inString, &ifIndex );
- if( err )
- {
- FPrintF( stderr, "error: Invalid interface value: %s\n", inString );
- err = kParamErr;
- goto exit;
- }
- }
- }
- else
- {
- ifIndex = 0;
- }
-
- *outIndex = ifIndex;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// RecordDataFromArgString
-//===========================================================================================================================
-
-static OSStatus RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen )
-{
- OSStatus err;
- uint8_t * dataPtr = NULL;
- size_t dataLen;
-
- if( 0 ) {}
-
- // Domain name
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_Domain ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_Domain );
-
- err = StringToDomainName( str, &dataPtr, &dataLen );
- require_noerr_quiet( err, exit );
- }
-
- // File path
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_File ) == 0 )
- {
- const char * const path = inString + sizeof_string( kRDataArgPrefix_File );
-
- err = CopyFileDataByPath( path, (char **) &dataPtr, &dataLen );
- require_noerr( err, exit );
- require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
- }
-
- // Hexadecimal string
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_HexString ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_HexString );
-
- err = HexToDataCopy( str, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
- require_noerr( err, exit );
- require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
- }
-
- // IPv4 address string
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_IPv4 ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_IPv4 );
-
- err = StringToARecordData( str, &dataPtr, &dataLen );
- require_noerr_quiet( err, exit );
- }
-
- // IPv6 address string
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_IPv6 ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_IPv6 );
-
- err = StringToAAAARecordData( str, &dataPtr, &dataLen );
- require_noerr_quiet( err, exit );
- }
-
- // SRV record
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_SRV ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_SRV );
-
- err = CreateSRVRecordDataFromString( str, &dataPtr, &dataLen );
- require_noerr( err, exit );
- }
-
- // String with escaped hex and octal bytes
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_String ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_String );
- const char * const end = str + strlen( str );
- size_t copiedLen;
- size_t totalLen;
- Boolean success;
-
- if( str < end )
- {
- success = ParseQuotedEscapedString( str, end, "", NULL, 0, NULL, &totalLen, NULL );
- require_action( success, exit, err = kParamErr );
- require_action( totalLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
-
- dataLen = totalLen;
- dataPtr = (uint8_t *) malloc( dataLen );
- require_action( dataPtr, exit, err = kNoMemoryErr );
-
- success = ParseQuotedEscapedString( str, end, "", (char *) dataPtr, dataLen, &copiedLen, NULL, NULL );
- require_action( success, exit, err = kParamErr );
- check( copiedLen == dataLen );
- }
- else
- {
- dataPtr = NULL;
- dataLen = 0;
- }
- }
-
- // TXT record
-
- else if( stricmp_prefix( inString, kRDataArgPrefix_TXT ) == 0 )
- {
- const char * const str = inString + sizeof_string( kRDataArgPrefix_TXT );
-
- err = CreateTXTRecordDataFromString( str, ',', &dataPtr, &dataLen );
- require_noerr( err, exit );
- }
-
- // Unrecognized format
-
- else
- {
- FPrintF( stderr, "Unrecognized record data string \"%s\".\n", inString );
- err = kParamErr;
- goto exit;
- }
-
- err = kNoErr;
- *outDataLen = dataLen;
- *outDataPtr = dataPtr;
- dataPtr = NULL;
-
-exit:
- FreeNullSafe( dataPtr );
- return( err );
-}
-
-//===========================================================================================================================
-// RecordTypeFromArgString
-//===========================================================================================================================
-
-typedef struct
-{
- uint16_t value; // Record type's numeric value.
- const char * name; // Record type's name as a string (e.g., "A", "PTR", "SRV").
-
-} RecordType;
-
-static const RecordType kRecordTypes[] =
-{
- // Common types.
-
- { kDNSServiceType_A, "A" },
- { kDNSServiceType_AAAA, "AAAA" },
- { kDNSServiceType_PTR, "PTR" },
- { kDNSServiceType_SRV, "SRV" },
- { kDNSServiceType_TXT, "TXT" },
- { kDNSServiceType_CNAME, "CNAME" },
- { kDNSServiceType_SOA, "SOA" },
- { kDNSServiceType_NSEC, "NSEC" },
- { kDNSServiceType_NS, "NS" },
- { kDNSServiceType_MX, "MX" },
- { kDNSServiceType_ANY, "ANY" },
- { kDNSServiceType_OPT, "OPT" },
-
- // Less common types.
-
- { kDNSServiceType_MD, "MD" },
- { kDNSServiceType_NS, "NS" },
- { kDNSServiceType_MD, "MD" },
- { kDNSServiceType_MF, "MF" },
- { kDNSServiceType_MB, "MB" },
- { kDNSServiceType_MG, "MG" },
- { kDNSServiceType_MR, "MR" },
- { kDNSServiceType_NULL, "NULL" },
- { kDNSServiceType_WKS, "WKS" },
- { kDNSServiceType_HINFO, "HINFO" },
- { kDNSServiceType_MINFO, "MINFO" },
- { kDNSServiceType_RP, "RP" },
- { kDNSServiceType_AFSDB, "AFSDB" },
- { kDNSServiceType_X25, "X25" },
- { kDNSServiceType_ISDN, "ISDN" },
- { kDNSServiceType_RT, "RT" },
- { kDNSServiceType_NSAP, "NSAP" },
- { kDNSServiceType_NSAP_PTR, "NSAP_PTR" },
- { kDNSServiceType_SIG, "SIG" },
- { kDNSServiceType_KEY, "KEY" },
- { kDNSServiceType_PX, "PX" },
- { kDNSServiceType_GPOS, "GPOS" },
- { kDNSServiceType_LOC, "LOC" },
- { kDNSServiceType_NXT, "NXT" },
- { kDNSServiceType_EID, "EID" },
- { kDNSServiceType_NIMLOC, "NIMLOC" },
- { kDNSServiceType_ATMA, "ATMA" },
- { kDNSServiceType_NAPTR, "NAPTR" },
- { kDNSServiceType_KX, "KX" },
- { kDNSServiceType_CERT, "CERT" },
- { kDNSServiceType_A6, "A6" },
- { kDNSServiceType_DNAME, "DNAME" },
- { kDNSServiceType_SINK, "SINK" },
- { kDNSServiceType_APL, "APL" },
- { kDNSServiceType_DS, "DS" },
- { kDNSServiceType_SSHFP, "SSHFP" },
- { kDNSServiceType_IPSECKEY, "IPSECKEY" },
- { kDNSServiceType_RRSIG, "RRSIG" },
- { kDNSServiceType_DNSKEY, "DNSKEY" },
- { kDNSServiceType_DHCID, "DHCID" },
- { kDNSServiceType_NSEC3, "NSEC3" },
- { kDNSServiceType_NSEC3PARAM, "NSEC3PARAM" },
- { kDNSServiceType_HIP, "HIP" },
- { kDNSServiceType_SPF, "SPF" },
- { kDNSServiceType_UINFO, "UINFO" },
- { kDNSServiceType_UID, "UID" },
- { kDNSServiceType_GID, "GID" },
- { kDNSServiceType_UNSPEC, "UNSPEC" },
- { kDNSServiceType_TKEY, "TKEY" },
- { kDNSServiceType_TSIG, "TSIG" },
- { kDNSServiceType_IXFR, "IXFR" },
- { kDNSServiceType_AXFR, "AXFR" },
- { kDNSServiceType_MAILB, "MAILB" },
- { kDNSServiceType_MAILA, "MAILA" }
-};
-
-static OSStatus RecordTypeFromArgString( const char *inString, uint16_t *outValue )
-{
- OSStatus err;
- int32_t i32;
- const RecordType * type;
- const RecordType * const end = kRecordTypes + countof( kRecordTypes );
-
- for( type = kRecordTypes; type < end; ++type )
- {
- if( strcasecmp( type->name, inString ) == 0 )
- {
- *outValue = type->value;
- return( kNoErr );
- }
- }
-
- err = StringToInt32( inString, &i32 );
- require_noerr_quiet( err, exit );
- require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
-
- *outValue = (uint16_t) i32;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// RecordClassFromArgString
-//===========================================================================================================================
-
-static OSStatus RecordClassFromArgString( const char *inString, uint16_t *outValue )
-{
- OSStatus err;
- int32_t i32;
-
- if( strcasecmp( inString, "IN" ) == 0 )
- {
- *outValue = kDNSServiceClass_IN;
- err = kNoErr;
- goto exit;
- }
-
- err = StringToInt32( inString, &i32 );
- require_noerr_quiet( err, exit );
- require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
-
- *outValue = (uint16_t) i32;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// InterfaceIndexToName
-//===========================================================================================================================
-
-static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] )
-{
- switch( inIfIndex )
- {
- case kDNSServiceInterfaceIndexAny:
- strlcpy( inNameBuf, "Any", kInterfaceNameBufLen );
- break;
-
- case kDNSServiceInterfaceIndexLocalOnly:
- strlcpy( inNameBuf, "LocalOnly", kInterfaceNameBufLen );
- break;
-
- case kDNSServiceInterfaceIndexUnicast:
- strlcpy( inNameBuf, "Unicast", kInterfaceNameBufLen );
- break;
-
- case kDNSServiceInterfaceIndexP2P:
- strlcpy( inNameBuf, "P2P", kInterfaceNameBufLen );
- break;
-
- #if( defined( kDNSServiceInterfaceIndexBLE ) )
- case kDNSServiceInterfaceIndexBLE:
- strlcpy( inNameBuf, "BLE", kInterfaceNameBufLen );
- break;
- #endif
-
- default:
- {
- const char * name;
-
- name = if_indextoname( inIfIndex, inNameBuf );
- if( !name ) strlcpy( inNameBuf, "NO NAME", kInterfaceNameBufLen );
- break;
- }
- }
-
- return( inNameBuf );
-}
-
-//===========================================================================================================================
-// RecordTypeToString
-//===========================================================================================================================
-
-static const char * RecordTypeToString( unsigned int inValue )
-{
- const RecordType * type;
- const RecordType * const end = kRecordTypes + countof( kRecordTypes );
-
- for( type = kRecordTypes; type < end; ++type )
- {
- if( type->value == inValue ) return( type->name );
- }
- return( "???" );
-}
-
-//===========================================================================================================================
-// DNSMessageExtractDomainName
-//===========================================================================================================================
-
-static OSStatus
- DNSMessageExtractDomainName(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const uint8_t * inNamePtr,
- uint8_t inBuf[ kDomainNameLengthMax ],
- const uint8_t ** outNextPtr )
-{
- OSStatus err;
- const uint8_t * label;
- uint8_t labelLen;
- const uint8_t * nextLabel;
- const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
- uint8_t * dst = inBuf;
- const uint8_t * const dstLim = inBuf ? ( inBuf + kDomainNameLengthMax ) : NULL;
- const uint8_t * nameEnd = NULL;
-
- require_action( ( inNamePtr >= inMsgPtr ) && ( inNamePtr < msgEnd ), exit, err = kRangeErr );
-
- for( label = inNamePtr; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
- {
- if( labelLen <= kDomainLabelLengthMax )
- {
- nextLabel = label + 1 + labelLen;
- require_action( nextLabel < msgEnd, exit, err = kUnderrunErr );
- if( dst )
- {
- require_action( ( dstLim - dst ) > ( 1 + labelLen ), exit, err = kOverrunErr );
- memcpy( dst, label, 1 + labelLen );
- dst += ( 1 + labelLen );
- }
- }
- else if( IsCompressionByte( labelLen ) )
- {
- uint16_t offset;
-
- require_action( ( msgEnd - label ) >= 2, exit, err = kUnderrunErr );
- if( !nameEnd )
- {
- nameEnd = label + 2;
- if( !dst ) break;
- }
- offset = (uint16_t)( ( ( label[ 0 ] & 0x3F ) << 8 ) | label[ 1 ] );
- nextLabel = inMsgPtr + offset;
- require_action( nextLabel < msgEnd, exit, err = kUnderrunErr );
- require_action( !IsCompressionByte( nextLabel[ 0 ] ), exit, err = kMalformedErr );
- }
- else
- {
- dlogassert( "Unhandled label length 0x%02X\n", labelLen );
- err = kMalformedErr;
- goto exit;
- }
- }
-
- if( dst ) *dst = 0;
- if( !nameEnd ) nameEnd = label + 1;
-
- if( outNextPtr ) *outNextPtr = nameEnd;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSMessageExtractDomainNameString
-//===========================================================================================================================
-
-static OSStatus
- DNSMessageExtractDomainNameString(
- const void * inMsgPtr,
- size_t inMsgLen,
- const void * inNamePtr,
- char inBuf[ kDNSServiceMaxDomainName ],
- const uint8_t ** outNextPtr )
-{
- OSStatus err;
- const uint8_t * nextPtr;
- uint8_t domainName[ kDomainNameLengthMax ];
-
- err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inNamePtr, domainName, &nextPtr );
- require_noerr( err, exit );
-
- err = DomainNameToString( domainName, NULL, inBuf, NULL );
- require_noerr( err, exit );
-
- if( outNextPtr ) *outNextPtr = nextPtr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSMessageExtractQuestion
-//===========================================================================================================================
-
-static OSStatus
- DNSMessageExtractQuestion(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const uint8_t * inPtr,
- uint8_t inNameBuf[ kDomainNameLengthMax ],
- uint16_t * outType,
- uint16_t * outClass,
- const uint8_t ** outPtr )
-{
- OSStatus err;
- const uint8_t * const msgEnd = &inMsgPtr[ inMsgLen ];
- const uint8_t * ptr;
- const DNSQuestionFixedFields * fields;
-
- err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, inNameBuf, &ptr );
- require_noerr_quiet( err, exit );
- require_action_quiet( (size_t)( msgEnd - ptr ) >= sizeof( DNSQuestionFixedFields ), exit, err = kUnderrunErr );
-
- fields = (const DNSQuestionFixedFields *) ptr;
- if( outType ) *outType = DNSQuestionFixedFieldsGetType( fields );
- if( outClass ) *outClass = DNSQuestionFixedFieldsGetClass( fields );
- if( outPtr ) *outPtr = (const uint8_t *) &fields[ 1 ];
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSMessageExtractRecord
-//===========================================================================================================================
-
-typedef struct
-{
- uint8_t type[ 2 ];
- uint8_t class[ 2 ];
- uint8_t ttl[ 4 ];
- uint8_t rdLength[ 2 ];
- uint8_t rdata[ 1 ];
-
-} DNSRecordFields;
-
-check_compile_time( offsetof( DNSRecordFields, rdata ) == 10 );
-
-static OSStatus
- DNSMessageExtractRecord(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const uint8_t * inPtr,
- uint8_t inNameBuf[ kDomainNameLengthMax ],
- uint16_t * outType,
- uint16_t * outClass,
- uint32_t * outTTL,
- const uint8_t ** outRDataPtr,
- size_t * outRDataLen,
- const uint8_t ** outPtr )
-{
- OSStatus err;
- const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
- const uint8_t * ptr;
- const DNSRecordFields * record;
- size_t rdLength;
-
- err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, inNameBuf, &ptr );
- require_noerr_quiet( err, exit );
- require_action_quiet( (size_t)( msgEnd - ptr ) >= offsetof( DNSRecordFields, rdata ), exit, err = kUnderrunErr );
-
- record = (DNSRecordFields *) ptr;
- rdLength = ReadBig16( record->rdLength );
- require_action_quiet( (size_t)( msgEnd - record->rdata ) >= rdLength , exit, err = kUnderrunErr );
-
- if( outType ) *outType = ReadBig16( record->type );
- if( outClass ) *outClass = ReadBig16( record->class );
- if( outTTL ) *outTTL = ReadBig32( record->ttl );
- if( outRDataPtr ) *outRDataPtr = record->rdata;
- if( outRDataLen ) *outRDataLen = rdLength;
- if( outPtr ) *outPtr = record->rdata + rdLength;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSMessageGetAnswerSection
-//===========================================================================================================================
-
-static OSStatus DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr )
-{
- OSStatus err;
- unsigned int questionCount, i;
- const DNSHeader * hdr;
- const uint8_t * ptr;
-
- require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
-
- hdr = (DNSHeader *) inMsgPtr;
- questionCount = DNSHeaderGetQuestionCount( hdr );
-
- ptr = (const uint8_t *) &hdr[ 1 ];
- for( i = 0; i < questionCount; ++i )
- {
- err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, NULL, NULL, NULL, &ptr );
- require_noerr( err, exit );
- }
-
- if( outPtr ) *outPtr = ptr;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSRecordDataToString
-//===========================================================================================================================
-
-static OSStatus
- DNSRecordDataToString(
- const void * inRDataPtr,
- size_t inRDataLen,
- unsigned int inRDataType,
- const void * inMsgPtr,
- size_t inMsgLen,
- char ** outString )
-{
- OSStatus err;
- const uint8_t * const rdataPtr = (uint8_t *) inRDataPtr;
- const uint8_t * const rdataEnd = rdataPtr + inRDataLen;
- char * rdataStr;
- const uint8_t * ptr;
- int n;
- char domainNameStr[ kDNSServiceMaxDomainName ];
-
- rdataStr = NULL;
- if( inRDataType == kDNSServiceType_A )
- {
- require_action_quiet( inRDataLen == 4, exit, err = kMalformedErr );
-
- ASPrintF( &rdataStr, "%.4a", rdataPtr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- else if( inRDataType == kDNSServiceType_AAAA )
- {
- require_action_quiet( inRDataLen == 16, exit, err = kMalformedErr );
-
- ASPrintF( &rdataStr, "%.16a", rdataPtr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- else if( ( inRDataType == kDNSServiceType_PTR ) || ( inRDataType == kDNSServiceType_CNAME ) ||
- ( inRDataType == kDNSServiceType_NS ) )
- {
- if( inMsgPtr )
- {
- err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, NULL );
- require_noerr( err, exit );
- }
- else
- {
- err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, NULL );
- require_noerr( err, exit );
- }
-
- rdataStr = strdup( domainNameStr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- else if( inRDataType == kDNSServiceType_SRV )
- {
- const SRVRecordDataFixedFields * fields;
- const uint8_t * target;
- unsigned int priority, weight, port;
-
- require_action_quiet( inRDataLen > sizeof( SRVRecordDataFixedFields ), exit, err = kMalformedErr );
-
- fields = (const SRVRecordDataFixedFields *) rdataPtr;
- SRVRecordDataFixedFieldsGet( fields, &priority, &weight, &port );
- target = (const uint8_t *) &fields[ 1 ];
-
- if( inMsgPtr )
- {
- err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, target, domainNameStr, NULL );
- require_noerr( err, exit );
- }
- else
- {
- err = DomainNameToString( target, rdataEnd, domainNameStr, NULL );
- require_noerr( err, exit );
- }
-
- ASPrintF( &rdataStr, "%u %u %u %s", priority, weight, port, domainNameStr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- else if( inRDataType == kDNSServiceType_TXT )
- {
- require_action_quiet( inRDataLen > 0, exit, err = kMalformedErr );
-
- if( inRDataLen == 1 )
- {
- ASPrintF( &rdataStr, "%#H", rdataPtr, (int) inRDataLen, INT_MAX );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- else
- {
- ASPrintF( &rdataStr, "%#{txt}", rdataPtr, inRDataLen );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
- }
- else if( inRDataType == kDNSServiceType_SOA )
- {
- uint32_t serial, refresh, retry, expire, minimum;
-
- if( inMsgPtr )
- {
- err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
- require_noerr( err, exit );
-
- require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
-
- rdataStr = strdup( domainNameStr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
-
- err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, ptr, domainNameStr, &ptr );
- require_noerr( err, exit );
- }
- else
- {
- err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
- require_noerr( err, exit );
-
- rdataStr = strdup( domainNameStr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
-
- err = DomainNameToString( ptr, rdataEnd, domainNameStr, &ptr );
- require_noerr( err, exit );
- }
-
- require_action_quiet( ( rdataEnd - ptr ) == sizeof( SOARecordDataFixedFields ), exit, err = kMalformedErr );
-
- SOARecordDataFixedFieldsGet( (const SOARecordDataFixedFields *) ptr, &serial, &refresh, &retry, &expire, &minimum );
-
- n = AppendPrintF( &rdataStr, " %s %u %u %u %u %u\n", domainNameStr, serial, refresh, retry, expire, minimum );
- require_action( n > 0, exit, err = kUnknownErr );
- }
- else if( inRDataType == kDNSServiceType_NSEC )
- {
- unsigned int windowBlock, bitmapLen, i, recordType;
- const uint8_t * bitmapPtr;
-
- if( inMsgPtr )
- {
- err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
- require_noerr( err, exit );
- }
- else
- {
- err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
- require_noerr( err, exit );
- }
-
- require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
-
- rdataStr = strdup( domainNameStr );
- require_action( rdataStr, exit, err = kNoMemoryErr );
-
- for( ; ptr < rdataEnd; ptr += ( 2 + bitmapLen ) )
- {
- require_action_quiet( ( ptr + 2 ) < rdataEnd, exit, err = kMalformedErr );
-
- windowBlock = ptr[ 0 ];
- bitmapLen = ptr[ 1 ];
- bitmapPtr = &ptr[ 2 ];
-
- require_action_quiet( ( bitmapLen >= 1 ) && ( bitmapLen <= 32 ) , exit, err = kMalformedErr );
- require_action_quiet( ( bitmapPtr + bitmapLen ) <= rdataEnd, exit, err = kMalformedErr );
-
- for( i = 0; i < BitArray_MaxBits( bitmapLen ); ++i )
- {
- if( BitArray_GetBit( bitmapPtr, bitmapLen, i ) )
- {
- recordType = ( windowBlock * 256 ) + i;
- n = AppendPrintF( &rdataStr, " %s", RecordTypeToString( recordType ) );
- require_action( n > 0, exit, err = kUnknownErr );
- }
- }
- }
- }
- else if( inRDataType == kDNSServiceType_MX )
- {
- uint16_t preference;
- const uint8_t * exchange;
-
- require_action_quiet( ( rdataPtr + 2 ) < rdataEnd, exit, err = kMalformedErr );
-
- preference = ReadBig16( rdataPtr );
- exchange = &rdataPtr[ 2 ];
-
- if( inMsgPtr )
- {
- err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, exchange, domainNameStr, NULL );
- require_noerr( err, exit );
- }
- else
- {
- err = DomainNameToString( exchange, rdataEnd, domainNameStr, NULL );
- require_noerr( err, exit );
- }
-
- n = ASPrintF( &rdataStr, "%u %s", preference, domainNameStr );
- require_action( n > 0, exit, err = kUnknownErr );
- }
- else
- {
- err = kNotHandledErr;
- goto exit;
- }
-
- check( rdataStr );
- *outString = rdataStr;
- rdataStr = NULL;
- err = kNoErr;
-
-exit:
- FreeNullSafe( rdataStr );
- return( err );
-}
-
-//===========================================================================================================================
-// DomainNameAppendString
-//===========================================================================================================================
-
-static OSStatus
- DomainNameAppendString(
- uint8_t inDomainName[ kDomainNameLengthMax ],
- const char * inString,
- uint8_t ** outEndPtr )
-{
- OSStatus err;
- const char * src;
- uint8_t * root;
- const uint8_t * const nameLim = inDomainName + kDomainNameLengthMax;
-
- for( root = inDomainName; ( root < nameLim ) && *root; root += ( 1 + *root ) ) {}
- require_action_quiet( root < nameLim, exit, err = kMalformedErr );
-
- // If the string is a single dot, denoting the root domain, then there are no non-empty labels.
-
- src = inString;
- if( ( src[ 0 ] == '.' ) && ( src[ 1 ] == '\0' ) ) ++src;
- while( *src )
- {
- uint8_t * const label = root;
- const uint8_t * const labelLim = Min( &label[ 1 + kDomainLabelLengthMax ], nameLim - 1 );
- uint8_t * dst;
- int c;
- size_t labelLen;
-
- dst = &label[ 1 ];
- while( *src && ( ( c = *src++ ) != '.' ) )
- {
- if( c == '\\' )
- {
- require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
- c = *src++;
- if( isdigit_safe( c ) && isdigit_safe( src[ 0 ] ) && isdigit_safe( src[ 1 ] ) )
- {
- const int decimal = ( ( c - '0' ) * 100 ) + ( ( src[ 0 ] - '0' ) * 10 ) + ( src[ 1 ] - '0' );
-
- if( decimal <= 255 )
- {
- c = decimal;
- src += 2;
- }
- }
- }
- require_action_quiet( dst < labelLim, exit, err = kOverrunErr );
- *dst++ = (uint8_t) c;
- }
-
- labelLen = (size_t)( dst - &label[ 1 ] );
- require_action_quiet( labelLen > 0, exit, err = kMalformedErr );
-
- label[ 0 ] = (uint8_t) labelLen;
- root = dst;
- *root = 0;
- }
-
- if( outEndPtr ) *outEndPtr = root + 1;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DomainNameEqual
-//===========================================================================================================================
-
-static Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 )
-{
- const uint8_t * p1 = inName1;
- const uint8_t * p2 = inName2;
- unsigned int len;
-
- for( ;; )
- {
- if( ( len = *p1++ ) != *p2++ ) return( false );
- if( len == 0 ) break;
- for( ; len > 0; ++p1, ++p2, --len )
- {
- if( tolower_safe( *p1 ) != tolower_safe( *p2 ) ) return( false );
- }
- }
- return( true );
-}
-
-//===========================================================================================================================
-// DomainNameLength
-//===========================================================================================================================
-
-static size_t DomainNameLength( const uint8_t * const inName )
-{
- const uint8_t * ptr;
-
- for( ptr = inName; *ptr != 0; ptr += ( 1 + *ptr ) ) {}
- return( (size_t)( ptr - inName ) + 1 );
-}
-
-//===========================================================================================================================
-// DomainNameDupEx
-//===========================================================================================================================
-
-static OSStatus DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen )
-{
- OSStatus err;
- uint8_t * namePtr;
- const size_t nameLen = DomainNameLength( inName );
-
- if( inLower )
- {
- const uint8_t * src;
- uint8_t * dst;
- unsigned int len;
-
- namePtr = (uint8_t *) malloc( nameLen );
- require_action( namePtr, exit, err = kNoMemoryErr );
-
- src = inName;
- dst = namePtr;
- while( ( len = *src ) != 0 )
- {
- *dst++ = *src++;
- while( len-- )
- {
- *dst++ = (uint8_t) tolower_safe( *src );
- ++src;
- }
- }
- *dst = 0;
- }
- else
- {
- namePtr = (uint8_t *) memdup( inName, nameLen );
- require_action( namePtr, exit, err = kNoMemoryErr );
- }
-
- *outNamePtr = namePtr;
- if( outNameLen ) *outNameLen = nameLen;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DomainNameFromString
-//===========================================================================================================================
-
-static OSStatus
- DomainNameFromString(
- uint8_t inDomainName[ kDomainNameLengthMax ],
- const char * inString,
- uint8_t ** outEndPtr )
-{
- inDomainName[ 0 ] = 0;
- return( DomainNameAppendString( inDomainName, inString, outEndPtr ) );
-}
-
-//===========================================================================================================================
-// DomainNameToString
-//===========================================================================================================================
-
-static OSStatus
- DomainNameToString(
- const uint8_t * inDomainName,
- const uint8_t * inEnd,
- char inBuf[ kDNSServiceMaxDomainName ],
- const uint8_t ** outNextPtr )
-{
- OSStatus err;
- const uint8_t * label;
- uint8_t labelLen;
- const uint8_t * nextLabel;
- char * dst;
- const uint8_t * src;
-
- require_action( !inEnd || ( inDomainName < inEnd ), exit, err = kUnderrunErr );
-
- // Convert each label up until the root label, i.e., the zero-length label.
-
- dst = inBuf;
- for( label = inDomainName; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
- {
- require_action( labelLen <= kDomainLabelLengthMax, exit, err = kMalformedErr );
-
- nextLabel = &label[ 1 ] + labelLen;
- require_action( ( nextLabel - inDomainName ) < kDomainNameLengthMax, exit, err = kMalformedErr );
- require_action( !inEnd || ( nextLabel < inEnd ), exit, err = kUnderrunErr );
-
- for( src = &label[ 1 ]; src < nextLabel; ++src )
- {
- if( isprint_safe( *src ) )
- {
- if( ( *src == '.' ) || ( *src == '\\' ) || ( *src == ' ' ) ) *dst++ = '\\';
- *dst++ = (char) *src;
- }
- else
- {
- *dst++ = '\\';
- *dst++ = '0' + ( *src / 100 );
- *dst++ = '0' + ( ( *src / 10 ) % 10 );
- *dst++ = '0' + ( *src % 10 );
- }
- }
- *dst++ = '.';
- }
-
- // At this point, label points to the root label.
- // If the root label was the only label, then write a dot for it.
-
- if( label == inDomainName ) *dst++ = '.';
- *dst = '\0';
- if( outNextPtr ) *outNextPtr = label + 1;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DNSMessageToText
-//===========================================================================================================================
-
-#define DNSFlagsOpCodeToString( X ) ( \
- ( (X) == kDNSOpCode_Query ) ? "Query" : \
- ( (X) == kDNSOpCode_InverseQuery ) ? "IQuery" : \
- ( (X) == kDNSOpCode_Status ) ? "Status" : \
- ( (X) == kDNSOpCode_Notify ) ? "Notify" : \
- ( (X) == kDNSOpCode_Update ) ? "Update" : \
- "Unassigned" )
-
-#define DNSFlagsRCodeToString( X ) ( \
- ( (X) == kDNSRCode_NoError ) ? "NoError" : \
- ( (X) == kDNSRCode_FormatError ) ? "FormErr" : \
- ( (X) == kDNSRCode_ServerFailure ) ? "ServFail" : \
- ( (X) == kDNSRCode_NXDomain ) ? "NXDomain" : \
- ( (X) == kDNSRCode_NotImplemented ) ? "NotImp" : \
- ( (X) == kDNSRCode_Refused ) ? "Refused" : \
- "???" )
-
-static OSStatus
- DNSMessageToText(
- const uint8_t * inMsgPtr,
- size_t inMsgLen,
- const Boolean inMDNS,
- const Boolean inPrintRaw,
- char ** outText )
-{
- OSStatus err;
- DataBuffer dataBuf;
- size_t len;
- const DNSHeader * hdr;
- const uint8_t * ptr;
- unsigned int id, flags, opcode, rcode;
- unsigned int questionCount, answerCount, authorityCount, additionalCount, i, totalRRCount;
- uint8_t name[ kDomainNameLengthMax ];
- char nameStr[ kDNSServiceMaxDomainName ];
-
- DataBuffer_Init( &dataBuf, NULL, 0, SIZE_MAX );
- #define _Append( ... ) do { err = DataBuffer_AppendF( &dataBuf, __VA_ARGS__ ); require_noerr( err, exit ); } while( 0 )
-
- require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
-
- hdr = (DNSHeader *) inMsgPtr;
- id = DNSHeaderGetID( hdr );
- flags = DNSHeaderGetFlags( hdr );
- questionCount = DNSHeaderGetQuestionCount( hdr );
- answerCount = DNSHeaderGetAnswerCount( hdr );
- authorityCount = DNSHeaderGetAuthorityCount( hdr );
- additionalCount = DNSHeaderGetAdditionalCount( hdr );
- opcode = DNSFlagsGetOpCode( flags );
- rcode = DNSFlagsGetRCode( flags );
-
- _Append( "ID: 0x%04X (%u)\n", id, id );
- _Append( "Flags: 0x%04X %c/%s %cAA%cTC%cRD%cRA%?s%?s %s\n",
- flags,
- ( flags & kDNSHeaderFlag_Response ) ? 'R' : 'Q', DNSFlagsOpCodeToString( opcode ),
- ( flags & kDNSHeaderFlag_AuthAnswer ) ? ' ' : '!',
- ( flags & kDNSHeaderFlag_Truncation ) ? ' ' : '!',
- ( flags & kDNSHeaderFlag_RecursionDesired ) ? ' ' : '!',
- ( flags & kDNSHeaderFlag_RecursionAvailable ) ? ' ' : '!',
- !inMDNS, ( flags & kDNSHeaderFlag_AuthenticData ) ? " AD" : "!AD",
- !inMDNS, ( flags & kDNSHeaderFlag_CheckingDisabled ) ? " CD" : "!CD",
- DNSFlagsRCodeToString( rcode ) );
- _Append( "Question count: %u\n", questionCount );
- _Append( "Answer count: %u\n", answerCount );
- _Append( "Authority count: %u\n", authorityCount );
- _Append( "Additional count: %u\n", additionalCount );
-
- ptr = (const uint8_t *) &hdr[ 1 ];
- for( i = 0; i < questionCount; ++i )
- {
- uint16_t qtype, qclass;
- Boolean isQU;
-
- err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, name, &qtype, &qclass, &ptr );
- require_noerr( err, exit );
-
- err = DomainNameToString( name, NULL, nameStr, NULL );
- require_noerr( err, exit );
-
- isQU = ( inMDNS && ( qclass & kQClassUnicastResponseBit ) ) ? true : false;
- if( inMDNS ) qclass &= ~kQClassUnicastResponseBit;
-
- if( i == 0 ) _Append( "\nQUESTION SECTION\n" );
-
- _Append( "%-30s %2s %?2s%?2u %-5s\n",
- nameStr, inMDNS ? ( isQU ? "QU" : "QM" ) : "",
- ( qclass == kDNSServiceClass_IN ), "IN", ( qclass != kDNSServiceClass_IN ), qclass, RecordTypeToString( qtype ) );
- }
-
- totalRRCount = answerCount + authorityCount + additionalCount;
- for( i = 0; i < totalRRCount; ++i )
- {
- uint16_t type;
- uint16_t class;
- uint32_t ttl;
- const uint8_t * rdataPtr;
- size_t rdataLen;
- char * rdataStr;
- Boolean cacheFlush;
-
- err = DNSMessageExtractRecord( inMsgPtr, inMsgLen, ptr, name, &type, &class, &ttl, &rdataPtr, &rdataLen, &ptr );
- require_noerr( err, exit );
-
- err = DomainNameToString( name, NULL, nameStr, NULL );
- require_noerr( err, exit );
-
- cacheFlush = ( inMDNS && ( class & kRRClassCacheFlushBit ) ) ? true : false;
- if( inMDNS ) class &= ~kRRClassCacheFlushBit;
-
- rdataStr = NULL;
- if( !inPrintRaw ) DNSRecordDataToString( rdataPtr, rdataLen, type, inMsgPtr, inMsgLen, &rdataStr );
- if( !rdataStr )
- {
- ASPrintF( &rdataStr, "%#H", rdataPtr, (int) rdataLen, INT_MAX );
- require_action( rdataStr, exit, err = kNoMemoryErr );
- }
-
- if( answerCount && ( i == 0 ) ) _Append( "\nANSWER SECTION\n" );
- else if( authorityCount && ( i == answerCount ) ) _Append( "\nAUTHORITY SECTION\n" );
- else if( additionalCount && ( i == ( answerCount + authorityCount ) ) ) _Append( "\nADDITIONAL SECTION\n" );
-
- _Append( "%-42s %6u %2s %?2s%?2u %-5s %s\n",
- nameStr, ttl, cacheFlush ? "CF" : "",
- ( class == kDNSServiceClass_IN ), "IN", ( class != kDNSServiceClass_IN ), class,
- RecordTypeToString( type ), rdataStr );
- free( rdataStr );
- }
- _Append( "\n" );
-
- err = DataBuffer_Append( &dataBuf, "", 1 );
- require_noerr( err, exit );
-
- err = DataBuffer_Detach( &dataBuf, (uint8_t **) outText, &len );
- require_noerr( err, exit );
-
-exit:
- DataBuffer_Free( &dataBuf );
- return( err );
-}
-
-//===========================================================================================================================
-// WriteDNSQueryMessage
-//===========================================================================================================================
-
-static OSStatus
- WriteDNSQueryMessage(
- uint8_t inMsg[ kDNSQueryMessageMaxLen ],
- uint16_t inMsgID,
- uint16_t inFlags,
- const char * inQName,
- uint16_t inQType,
- uint16_t inQClass,
- size_t * outMsgLen )
-{
- OSStatus err;
- DNSHeader * const hdr = (DNSHeader *) inMsg;
- uint8_t * ptr;
- size_t msgLen;
-
- memset( hdr, 0, sizeof( *hdr ) );
- DNSHeaderSetID( hdr, inMsgID );
- DNSHeaderSetFlags( hdr, inFlags );
- DNSHeaderSetQuestionCount( hdr, 1 );
-
- ptr = (uint8_t *)( hdr + 1 );
- err = DomainNameFromString( ptr, inQName, &ptr );
- require_noerr_quiet( err, exit );
-
- DNSQuestionFixedFieldsInit( (DNSQuestionFixedFields *) ptr, inQType, inQClass );
- ptr += 4;
-
- msgLen = (size_t)( ptr - inMsg );
- check( msgLen <= kDNSQueryMessageMaxLen );
-
- if( outMsgLen ) *outMsgLen = msgLen;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DispatchSignalSourceCreate
-//===========================================================================================================================
-
-static OSStatus
- DispatchSignalSourceCreate(
- int inSignal,
- DispatchHandler inEventHandler,
- void * inContext,
- dispatch_source_t * outSource )
-{
- OSStatus err;
- dispatch_source_t source;
-
- source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, dispatch_get_main_queue() );
- require_action( source, exit, err = kUnknownErr );
-
- dispatch_set_context( source, inContext );
- dispatch_source_set_event_handler_f( source, inEventHandler );
-
- *outSource = source;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DispatchSocketSourceCreate
-//===========================================================================================================================
-
-static OSStatus
- DispatchSocketSourceCreate(
- SocketRef inSock,
- dispatch_source_type_t inType,
- dispatch_queue_t inQueue,
- DispatchHandler inEventHandler,
- DispatchHandler inCancelHandler,
- void * inContext,
- dispatch_source_t * outSource )
-{
- OSStatus err;
- dispatch_source_t source;
-
- source = dispatch_source_create( inType, (uintptr_t) inSock, 0, inQueue ? inQueue : dispatch_get_main_queue() );
- require_action( source, exit, err = kUnknownErr );
-
- dispatch_set_context( source, inContext );
- dispatch_source_set_event_handler_f( source, inEventHandler );
- dispatch_source_set_cancel_handler_f( source, inCancelHandler );
-
- *outSource = source;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DispatchTimerCreate
-//===========================================================================================================================
-
-static OSStatus
- DispatchTimerCreate(
- dispatch_time_t inStart,
- uint64_t inIntervalNs,
- uint64_t inLeewayNs,
- dispatch_queue_t inQueue,
- DispatchHandler inEventHandler,
- DispatchHandler inCancelHandler,
- void * inContext,
- dispatch_source_t * outTimer )
-{
- OSStatus err;
- dispatch_source_t timer;
-
- timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, inQueue ? inQueue : dispatch_get_main_queue() );
- require_action( timer, exit, err = kUnknownErr );
-
- dispatch_source_set_timer( timer, inStart, inIntervalNs, inLeewayNs );
- dispatch_set_context( timer, inContext );
- dispatch_source_set_event_handler_f( timer, inEventHandler );
- dispatch_source_set_cancel_handler_f( timer, inCancelHandler );
-
- *outTimer = timer;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// DispatchProcessMonitorCreate
-//===========================================================================================================================
-
-static OSStatus
- DispatchProcessMonitorCreate(
- pid_t inPID,
- unsigned long inFlags,
- dispatch_queue_t inQueue,
- DispatchHandler inEventHandler,
- DispatchHandler inCancelHandler,
- void * inContext,
- dispatch_source_t * outMonitor )
-{
- OSStatus err;
- dispatch_source_t monitor;
-
- monitor = dispatch_source_create( DISPATCH_SOURCE_TYPE_PROC, (uintptr_t) inPID, inFlags,
- inQueue ? inQueue : dispatch_get_main_queue() );
- require_action( monitor, exit, err = kUnknownErr );
-
- dispatch_set_context( monitor, inContext );
- dispatch_source_set_event_handler_f( monitor, inEventHandler );
- dispatch_source_set_cancel_handler_f( monitor, inCancelHandler );
-
- *outMonitor = monitor;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ServiceTypeDescription
-//===========================================================================================================================
-
-typedef struct
-{
- const char * name; // Name of the service type in two-label "_service._proto" format.
- const char * description; // Description of the service type.
-
-} ServiceType;
-
-// A Non-comprehensive table of DNS-SD service types
-
-static const ServiceType kServiceTypes[] =
-{
- { "_acp-sync._tcp", "AirPort Base Station Sync" },
- { "_adisk._tcp", "Automatic Disk Discovery" },
- { "_afpovertcp._tcp", "Apple File Sharing" },
- { "_airdrop._tcp", "AirDrop" },
- { "_airplay._tcp", "AirPlay" },
- { "_airport._tcp", "AirPort Base Station" },
- { "_daap._tcp", "Digital Audio Access Protocol (iTunes)" },
- { "_eppc._tcp", "Remote AppleEvents" },
- { "_ftp._tcp", "File Transfer Protocol" },
- { "_home-sharing._tcp", "Home Sharing" },
- { "_homekit._tcp", "HomeKit" },
- { "_http._tcp", "World Wide Web HTML-over-HTTP" },
- { "_https._tcp", "HTTP over SSL/TLS" },
- { "_ipp._tcp", "Internet Printing Protocol" },
- { "_ldap._tcp", "Lightweight Directory Access Protocol" },
- { "_mediaremotetv._tcp", "Media Remote" },
- { "_net-assistant._tcp", "Apple Remote Desktop" },
- { "_od-master._tcp", "OpenDirectory Master" },
- { "_nfs._tcp", "Network File System" },
- { "_presence._tcp", "Peer-to-peer messaging / Link-Local Messaging" },
- { "_pdl-datastream._tcp", "Printer Page Description Language Data Stream" },
- { "_raop._tcp", "Remote Audio Output Protocol" },
- { "_rfb._tcp", "Remote Frame Buffer" },
- { "_scanner._tcp", "Bonjour Scanning" },
- { "_smb._tcp", "Server Message Block over TCP/IP" },
- { "_sftp-ssh._tcp", "Secure File Transfer Protocol over SSH" },
- { "_sleep-proxy._udp", "Sleep Proxy Server" },
- { "_ssh._tcp", "SSH Remote Login Protocol" },
- { "_teleport._tcp", "teleport" },
- { "_tftp._tcp", "Trivial File Transfer Protocol" },
- { "_workstation._tcp", "Workgroup Manager" },
- { "_webdav._tcp", "World Wide Web Distributed Authoring and Versioning (WebDAV)" },
- { "_webdavs._tcp", "WebDAV over SSL/TLS" }
-};
-
-static const char * ServiceTypeDescription( const char *inName )
-{
- const ServiceType * serviceType;
- const ServiceType * const end = kServiceTypes + countof( kServiceTypes );
-
- for( serviceType = kServiceTypes; serviceType < end; ++serviceType )
- {
- if( ( stricmp_prefix( inName, serviceType->name ) == 0 ) )
- {
- const size_t len = strlen( serviceType->name );
-
- if( ( inName[ len ] == '\0' ) || ( strcmp( &inName[ len ], "." ) == 0 ) )
- {
- return( serviceType->description );
- }
- }
- }
- return( NULL );
-}
-
-//===========================================================================================================================
-// SocketContextCreate
-//===========================================================================================================================
-
-static OSStatus SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext )
-{
- OSStatus err;
- SocketContext * context;
-
- context = (SocketContext *) calloc( 1, sizeof( *context ) );
- require_action( context, exit, err = kNoMemoryErr );
-
- context->refCount = 1;
- context->sock = inSock;
- context->userContext = inUserContext;
-
- *outContext = context;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// SocketContextRetain
-//===========================================================================================================================
-
-static SocketContext * SocketContextRetain( SocketContext *inContext )
-{
- ++inContext->refCount;
- return( inContext );
-}
-
-//===========================================================================================================================
-// SocketContextRelease
-//===========================================================================================================================
-
-static void SocketContextRelease( SocketContext *inContext )
-{
- if( --inContext->refCount == 0 )
- {
- ForgetSocket( &inContext->sock );
- free( inContext );
- }
-}
-
-//===========================================================================================================================
-// SocketContextCancelHandler
-//===========================================================================================================================
-
-static void SocketContextCancelHandler( void *inContext )
-{
- SocketContextRelease( (SocketContext *) inContext );
-}
-
-//===========================================================================================================================
-// StringToInt32
-//===========================================================================================================================
-
-static OSStatus StringToInt32( const char *inString, int32_t *outValue )
-{
- OSStatus err;
- long value;
- char * endPtr;
-
- value = strtol( inString, &endPtr, 0 );
- require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
- require_action_quiet( ( value >= INT32_MIN ) && ( value <= INT32_MAX ), exit, err = kRangeErr );
-
- *outValue = (int32_t) value;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// StringToUInt32
-//===========================================================================================================================
-
-static OSStatus StringToUInt32( const char *inString, uint32_t *outValue )
-{
- OSStatus err;
- uint32_t value;
- char * endPtr;
-
- value = (uint32_t) strtol( inString, &endPtr, 0 );
- require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
-
- *outValue = value;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// StringToPID
-//===========================================================================================================================
-
-static OSStatus StringToPID( const char *inString, pid_t *outPID )
-{
- OSStatus err;
- long long value;
- char * endPtr;
-
- set_errno_compat( 0 );
- value = strtoll( inString, &endPtr, 0 );
- err = errno_compat();
- require_noerr_quiet( err, exit );
- require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kMalformedErr );
- require_action_quiet( value == (pid_t) value, exit, err = kRangeErr );
-
- *outPID = (pid_t) value;
- err = kNoErr;
-
-exit:
- return( err );
-}
-#endif
-
-//===========================================================================================================================
-// StringToARecordData
-//===========================================================================================================================
-
-static OSStatus StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
- OSStatus err;
- uint32_t * addrPtr;
- const size_t addrLen = sizeof( *addrPtr );
- const char * end;
-
- addrPtr = (uint32_t *) malloc( addrLen );
- require_action( addrPtr, exit, err = kNoMemoryErr );
-
- err = StringToIPv4Address( inString, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix, addrPtr,
- NULL, NULL, NULL, &end );
- if( !err && ( *end != '\0' ) ) err = kMalformedErr;
- require_noerr_quiet( err, exit );
-
- *addrPtr = HostToBig32( *addrPtr );
-
- *outPtr = (uint8_t *) addrPtr;
- addrPtr = NULL;
- *outLen = addrLen;
-
-exit:
- FreeNullSafe( addrPtr );
- return( err );
-}
-
-//===========================================================================================================================
-// StringToAAAARecordData
-//===========================================================================================================================
-
-static OSStatus StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
- OSStatus err;
- uint8_t * addrPtr;
- const size_t addrLen = 16;
- const char * end;
-
- addrPtr = (uint8_t *) malloc( addrLen );
- require_action( addrPtr, exit, err = kNoMemoryErr );
-
- err = StringToIPv6Address( inString,
- kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
- addrPtr, NULL, NULL, NULL, &end );
- if( !err && ( *end != '\0' ) ) err = kMalformedErr;
- require_noerr_quiet( err, exit );
-
- *outPtr = addrPtr;
- addrPtr = NULL;
- *outLen = addrLen;
-
-exit:
- FreeNullSafe( addrPtr );
- return( err );
-}
-
-//===========================================================================================================================
-// StringToDomainName
-//===========================================================================================================================
-
-static OSStatus StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
- OSStatus err;
- uint8_t * namePtr;
- size_t nameLen;
- uint8_t * end;
- uint8_t nameBuf[ kDomainNameLengthMax ];
-
- err = DomainNameFromString( nameBuf, inString, &end );
- require_noerr_quiet( err, exit );
-
- nameLen = (size_t)( end - nameBuf );
- namePtr = memdup( nameBuf, nameLen );
- require_action( namePtr, exit, err = kNoMemoryErr );
-
- *outPtr = namePtr;
- namePtr = NULL;
- if( outLen ) *outLen = nameLen;
-
-exit:
- return( err );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-// GetDefaultDNSServer
-//===========================================================================================================================
-
-static OSStatus GetDefaultDNSServer( sockaddr_ip *outAddr )
-{
- OSStatus err;
- dns_config_t * config;
- struct sockaddr * addr;
- int32_t i;
-
- config = dns_configuration_copy();
- require_action( config, exit, err = kUnknownErr );
-
- addr = NULL;
- for( i = 0; i < config->n_resolver; ++i )
- {
- const dns_resolver_t * const resolver = config->resolver[ i ];
-
- if( !resolver->domain && ( resolver->n_nameserver > 0 ) )
- {
- addr = resolver->nameserver[ 0 ];
- break;
- }
- }
- require_action_quiet( addr, exit, err = kNotFoundErr );
-
- SockAddrCopy( addr, outAddr );
- err = kNoErr;
-
-exit:
- if( config ) dns_configuration_free( config );
- return( err );
-}
-#endif
-
-//===========================================================================================================================
-// GetMDNSMulticastAddrV4
-//===========================================================================================================================
-
-static void _MDNSMulticastAddrV4Init( void *inContext );
-
-static const struct sockaddr * GetMDNSMulticastAddrV4( void )
-{
- static struct sockaddr_in sMDNSMulticastAddrV4;
- static dispatch_once_t sMDNSMulticastAddrV4InitOnce = 0;
-
- dispatch_once_f( &sMDNSMulticastAddrV4InitOnce, &sMDNSMulticastAddrV4, _MDNSMulticastAddrV4Init);
- return( (const struct sockaddr *) &sMDNSMulticastAddrV4 );
-}
-
-static void _MDNSMulticastAddrV4Init( void *inContext )
-{
- struct sockaddr_in * const addr = (struct sockaddr_in *) inContext;
-
- memset( addr, 0, sizeof( *addr ) );
- SIN_LEN_SET( addr );
- addr->sin_family = AF_INET;
- addr->sin_port = htons( kMDNSPort );
- addr->sin_addr.s_addr = htonl( 0xE00000FB ); // The mDNS IPv4 multicast address is 224.0.0.251
-}
-
-//===========================================================================================================================
-// GetMDNSMulticastAddrV6
-//===========================================================================================================================
-
-static void _MDNSMulticastAddrV6Init( void *inContext );
-
-static const struct sockaddr * GetMDNSMulticastAddrV6( void )
-{
- static struct sockaddr_in6 sMDNSMulticastAddrV6;
- static dispatch_once_t sMDNSMulticastAddrV6InitOnce = 0;
-
- dispatch_once_f( &sMDNSMulticastAddrV6InitOnce, &sMDNSMulticastAddrV6, _MDNSMulticastAddrV6Init);
- return( (const struct sockaddr *) &sMDNSMulticastAddrV6 );
-}
-
-static void _MDNSMulticastAddrV6Init( void *inContext )
-{
- struct sockaddr_in6 * const addr = (struct sockaddr_in6 *) inContext;
-
- memset( addr, 0, sizeof( *addr ) );
- SIN6_LEN_SET( addr );
- addr->sin6_family = AF_INET6;
- addr->sin6_port = htons( kMDNSPort );
- addr->sin6_addr.s6_addr[ 0 ] = 0xFF; // The mDNS IPv6 multicast address is FF02::FB.
- addr->sin6_addr.s6_addr[ 1 ] = 0x02;
- addr->sin6_addr.s6_addr[ 15 ] = 0xFB;
-}
-
-//===========================================================================================================================
-// GetAnyMDNSInterface
-//===========================================================================================================================
-
-static OSStatus GetAnyMDNSInterface( char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex )
-{
- OSStatus err;
- struct ifaddrs * ifaList;
- const struct ifaddrs * ifa;
- const struct ifaddrs * ifa2;
- const char * ifname = NULL;
- const unsigned int checkFlags = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTOPOINT;
- const unsigned int wantFlags = IFF_UP | IFF_MULTICAST;
- int wantFamily;
- NetTransportType type;
-
- ifaList = NULL;
- err = getifaddrs( &ifaList );
- err = map_global_noerr_errno( err );
- require_noerr( err, exit );
-
- for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
- {
- if( ( ifa->ifa_flags & checkFlags ) != wantFlags ) continue;
- if( !ifa->ifa_addr || !ifa->ifa_name ) continue;
- if( ( ifa->ifa_addr->sa_family != AF_INET ) &&
- ( ifa->ifa_addr->sa_family != AF_INET6 ) ) continue;
-
- err = SocketGetInterfaceInfo( kInvalidSocketRef, ifa->ifa_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &type );
- check_noerr( err );
- if( err || ( type == kNetTransportType_AWDL ) ) continue;
-
- if( !ifname ) ifname = ifa->ifa_name;
- wantFamily = ( ifa->ifa_addr->sa_family == AF_INET ) ? AF_INET6 : AF_INET;
-
- for( ifa2 = ifa->ifa_next; ifa2; ifa2 = ifa2->ifa_next )
- {
- if( ( ifa2->ifa_flags & checkFlags ) != wantFlags ) continue;
- if( !ifa2->ifa_addr || !ifa2->ifa_name ) continue;
- if( ifa2->ifa_addr->sa_family != wantFamily ) continue;
- if( strcmp( ifa2->ifa_name, ifa->ifa_name ) == 0 ) break;
- }
- if( ifa2 )
- {
- ifname = ifa->ifa_name;
- break;
- }
- }
- require_action_quiet( ifname, exit, err = kNotFoundErr );
-
- if( inNameBuf ) strlcpy( inNameBuf, ifname, IF_NAMESIZE + 1 );
- if( outIndex ) *outIndex = if_nametoindex( ifname );
-
-exit:
- if( ifaList ) freeifaddrs( ifaList );
- return( err );
-}
-
-//===========================================================================================================================
-// CreateMulticastSocket
-//===========================================================================================================================
-
-static OSStatus
- CreateMulticastSocket(
- const struct sockaddr * inAddr,
- int inPort,
- const char * inIfName,
- uint32_t inIfIndex,
- Boolean inJoin,
- int * outPort,
- SocketRef * outSock )
-{
- OSStatus err;
- SocketRef sock = kInvalidSocketRef;
- const int family = inAddr->sa_family;
- int port;
-
- require_action_quiet( ( family == AF_INET ) ||( family == AF_INET6 ), exit, err = kUnsupportedErr );
-
- err = ServerSocketOpen( family, SOCK_DGRAM, IPPROTO_UDP, inPort, &port, kSocketBufferSize_DontSet, &sock );
- require_noerr_quiet( err, exit );
-
- err = SocketSetMulticastInterface( sock, inIfName, inIfIndex );
- require_noerr_quiet( err, exit );
-
- if( family == AF_INET )
- {
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
- err = map_socket_noerr_errno( sock, err );
- require_noerr_quiet( err, exit );
- }
- else
- {
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
- err = map_socket_noerr_errno( sock, err );
- require_noerr_quiet( err, exit );
- }
-
- if( inJoin )
- {
- err = SocketJoinMulticast( sock, inAddr, inIfName, inIfIndex );
- require_noerr_quiet( err, exit );
- }
-
- if( outPort ) *outPort = port;
- *outSock = sock;
- sock = kInvalidSocketRef;
-
-exit:
- ForgetSocket( &sock );
- return( err );
-}
-
-//===========================================================================================================================
-// DecimalTextToUInt32
-//===========================================================================================================================
-
-static OSStatus DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr )
-{
- OSStatus err;
- uint64_t value;
- const char * ptr = inSrc;
-
- require_action_quiet( ( ptr < inEnd ) && isdigit_safe( *ptr ), exit, err = kMalformedErr );
-
- value = (uint64_t)( *ptr++ - '0' );
- if( value == 0 )
- {
- if( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
- {
- err = kMalformedErr;
- goto exit;
- }
- }
- else
- {
- while( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
- {
- value = ( value * 10 ) + (uint64_t)( *ptr++ - '0' );
- require_action_quiet( value <= UINT32_MAX, exit, err = kRangeErr );
- }
- }
-
- *outValue = (uint32_t) value;
- if( outPtr ) *outPtr = ptr;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// CheckIntegerArgument
-//===========================================================================================================================
-
-static OSStatus CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax )
-{
- if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
-
- FPrintF( stderr, "error: Invalid %s: %d. Valid range is [%d, %d].\n", inArgName, inArgValue, inMin, inMax );
- return( kRangeErr );
-}
-
-//===========================================================================================================================
-// CheckDoubleArgument
-//===========================================================================================================================
-
-static OSStatus CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax )
-{
- if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
-
- FPrintF( stderr, "error: Invalid %s: %.1f. Valid range is [%.1f, %.1f].\n", inArgName, inArgValue, inMin, inMax );
- return( kRangeErr );
-}
-
-//===========================================================================================================================
-// CheckRootUser
-//===========================================================================================================================
-
-static OSStatus CheckRootUser( void )
-{
- if( geteuid() == 0 ) return( kNoErr );
-
- FPrintF( stderr, "error: This command must to be run as root.\n" );
- return( kPermissionErr );
-}
-
-//===========================================================================================================================
-// SpawnCommand
-//
-// Note: Based on systemf() from CoreUtils framework.
-//===========================================================================================================================
-
-extern char ** environ;
-
-static OSStatus SpawnCommand( pid_t *outPID, const char *inFormat, ... )
-{
- OSStatus err;
- va_list args;
- char * command;
- char * argv[ 4 ];
- pid_t pid;
-
- command = NULL;
- va_start( args, inFormat );
- VASPrintF( &command, inFormat, args );
- va_end( args );
- require_action( command, exit, err = kUnknownErr );
-
- argv[ 0 ] = "/bin/sh";
- argv[ 1 ] = "-c";
- argv[ 2 ] = command;
- argv[ 3 ] = NULL;
- err = posix_spawn( &pid, argv[ 0 ], NULL, NULL, argv, environ );
- free( command );
- require_noerr_quiet( err, exit );
-
- if( outPID ) *outPID = pid;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// OutputPropertyList
-//===========================================================================================================================
-
-static OSStatus
- OutputPropertyList(
- CFPropertyListRef inPList,
- OutputFormatType inType,
- Boolean inAppendNewline,
- const char * inOutputFilePath )
-{
- OSStatus err;
- CFDataRef results = NULL;
- FILE * file = NULL;
-
- // Convert plist to a specific format.
-
- switch( inType )
- {
- case kOutputFormatType_JSON:
- results = CFCreateJSONData( inPList, kJSONFlags_None, NULL );
- require_action( results, exit, err = kUnknownErr );
- break;
-
- case kOutputFormatType_XML:
- results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListXMLFormat_v1_0, 0, NULL );
- require_action( results, exit, err = kUnknownErr );
- break;
-
- case kOutputFormatType_Binary:
- results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListBinaryFormat_v1_0, 0, NULL );
- require_action( results, exit, err = kUnknownErr );
- break;
-
- default:
- err = kTypeErr;
- goto exit;
- }
-
- // Write formatted results to file or stdout.
-
- if( inOutputFilePath )
- {
- file = fopen( inOutputFilePath, "wb" );
- err = map_global_value_errno( file, file );
- require_noerr( err, exit );
- }
- else
- {
- file = stdout;
- }
-
- err = WriteANSIFile( file, CFDataGetBytePtr( results ), (size_t) CFDataGetLength( results ) );
- require_noerr_quiet( err, exit );
-
- // Write a trailing newline for JSON-formatted results if requested.
-
- if( ( inType == kOutputFormatType_JSON ) && inAppendNewline )
- {
- err = WriteANSIFile( file, "\n", 1 );
- require_noerr_quiet( err, exit );
- }
-
-exit:
- if( file && ( file != stdout ) ) fclose( file );
- CFReleaseNullSafe( results );
- return( err );
-}
-
-//===========================================================================================================================
-// DNSRecordFixedFieldsSet
-//===========================================================================================================================
-
-static void
- DNSRecordFixedFieldsSet(
- DNSRecordFixedFields * inFields,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- uint16_t inRDLength )
-{
- WriteBig16( inFields->type, inType );
- WriteBig16( inFields->class, inClass );
- WriteBig32( inFields->ttl, inTTL );
- WriteBig16( inFields->rdlength, inRDLength );
-}
-
-//===========================================================================================================================
-// SRVRecordDataFixedFieldsGet
-//===========================================================================================================================
-
-static void
- SRVRecordDataFixedFieldsGet(
- const SRVRecordDataFixedFields * inFields,
- unsigned int * outPriority,
- unsigned int * outWeight,
- unsigned int * outPort )
-{
- if( outPriority ) *outPriority = ReadBig16( inFields->priority );
- if( outWeight ) *outWeight = ReadBig16( inFields->weight );
- if( outPort ) *outPort = ReadBig16( inFields->port );
-}
-
-//===========================================================================================================================
-// SRVRecordDataFixedFieldsSet
-//===========================================================================================================================
-
-static void
- SRVRecordDataFixedFieldsSet(
- SRVRecordDataFixedFields * inFields,
- uint16_t inPriority,
- uint16_t inWeight,
- uint16_t inPort )
-{
- WriteBig16( inFields->priority, inPriority );
- WriteBig16( inFields->weight, inWeight );
- WriteBig16( inFields->port, inPort );
-}
-
-//===========================================================================================================================
-// SOARecordDataFixedFieldsGet
-//===========================================================================================================================
-
-static void
- SOARecordDataFixedFieldsGet(
- const SOARecordDataFixedFields * inFields,
- uint32_t * outSerial,
- uint32_t * outRefresh,
- uint32_t * outRetry,
- uint32_t * outExpire,
- uint32_t * outMinimum )
-{
- if( outSerial ) *outSerial = ReadBig32( inFields->serial );
- if( outRefresh ) *outRefresh = ReadBig32( inFields->refresh );
- if( outRetry ) *outRetry = ReadBig32( inFields->retry );
- if( outExpire ) *outExpire = ReadBig32( inFields->expire );
- if( outMinimum ) *outMinimum = ReadBig32( inFields->minimum );
-}
-
-//===========================================================================================================================
-// SOARecordDataFixedFieldsSet
-//===========================================================================================================================
-
-static void
- SOARecordDataFixedFieldsSet(
- SOARecordDataFixedFields * inFields,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimum )
-{
- WriteBig32( inFields->serial, inSerial );
- WriteBig32( inFields->refresh, inRefresh );
- WriteBig32( inFields->retry, inRetry );
- WriteBig32( inFields->expire, inExpire );
- WriteBig32( inFields->minimum, inMinimum );
-}
-
-//===========================================================================================================================
-// CreateSRVRecordDataFromString
-//===========================================================================================================================
-
-static OSStatus CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
- OSStatus err;
- DataBuffer dataBuf;
- const char * ptr;
- int i;
- uint8_t * end;
- uint8_t target[ kDomainNameLengthMax ];
-
- DataBuffer_Init( &dataBuf, NULL, 0, ( 3 * 2 ) + kDomainNameLengthMax );
-
- // Parse and set the priority, weight, and port values (all three are unsigned 16-bit values).
-
- ptr = inString;
- for( i = 0; i < 3; ++i )
- {
- char * next;
- long value;
- uint8_t buf[ 2 ];
-
- value = strtol( ptr, &next, 0 );
- require_action_quiet( ( next != ptr ) && ( *next == ',' ), exit, err = kMalformedErr );
- require_action_quiet( ( value >= 0 ) && ( value <= UINT16_MAX ), exit, err = kRangeErr );
- ptr = next + 1;
-
- WriteBig16( buf, value );
-
- err = DataBuffer_Append( &dataBuf, buf, sizeof( buf ) );
- require_noerr( err, exit );
- }
-
- // Set the target domain name.
-
- err = DomainNameFromString( target, ptr, &end );
- require_noerr_quiet( err, exit );
-
- err = DataBuffer_Append( &dataBuf, target, (size_t)( end - target ) );
- require_noerr( err, exit );
-
- err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
- require_noerr( err, exit );
-
-exit:
- DataBuffer_Free( &dataBuf );
- return( err );
-}
-
-//===========================================================================================================================
-// CreateTXTRecordDataFromString
-//===========================================================================================================================
-
-static OSStatus CreateTXTRecordDataFromString(const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen )
-{
- OSStatus err;
- DataBuffer dataBuf;
- const char * src;
- uint8_t txtStr[ 256 ]; // Buffer for single TXT string: 1 length byte + up to 255 bytes of data.
-
- DataBuffer_Init( &dataBuf, NULL, 0, kDNSRecordDataLengthMax );
-
- src = inString;
- for( ;; )
- {
- uint8_t * dst = &txtStr[ 1 ];
- const uint8_t * const lim = &txtStr[ 256 ];
- int c;
-
- while( *src && ( *src != inDelimiter ) )
- {
- if( ( c = *src++ ) == '\\' )
- {
- require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
- c = *src++;
- }
- require_action_quiet( dst < lim, exit, err = kOverrunErr );
- *dst++ = (uint8_t) c;
- }
- txtStr[ 0 ] = (uint8_t)( dst - &txtStr[ 1 ] );
- err = DataBuffer_Append( &dataBuf, txtStr, 1 + txtStr[ 0 ] );
- require_noerr( err, exit );
-
- if( *src == '\0' ) break;
- ++src;
- }
-
- err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
- require_noerr( err, exit );
-
-exit:
- DataBuffer_Free( &dataBuf );
- return( err );
-}
-
-//===========================================================================================================================
-// CreateNSECRecordData
-//===========================================================================================================================
-
-DECLARE_QSORT_NUMERIC_COMPARATOR( _QSortCmpUnsigned );
-DEFINE_QSORT_NUMERIC_COMPARATOR( unsigned int, _QSortCmpUnsigned )
-
-#define kNSECBitmapMaxLength 32 // 32 bytes (256 bits). See <https://tools.ietf.org/html/rfc4034#section-4.1.2>.
-
-static OSStatus
- CreateNSECRecordData(
- const uint8_t * inNextDomainName,
- uint8_t ** outPtr,
- size_t * outLen,
- unsigned int inTypeCount,
- ... )
-{
- OSStatus err;
- va_list args;
- DataBuffer rdataDB;
- unsigned int * array = NULL;
- unsigned int i, type, maxBit, currBlock, bitmapLen;
- uint8_t fields[ 2 + kNSECBitmapMaxLength ];
- uint8_t * const bitmap = &fields[ 2 ];
-
- va_start( args, inTypeCount );
- DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
-
- // Append Next Domain Name.
-
- err = DataBuffer_Append( &rdataDB, inNextDomainName, DomainNameLength( inNextDomainName ) );
- require_noerr( err, exit );
-
- // Append Type Bit Maps.
-
- maxBit = 0;
- memset( bitmap, 0, kNSECBitmapMaxLength );
- if( inTypeCount > 0 )
- {
- array = (unsigned int *) malloc( inTypeCount * sizeof_element( array ) );
- require_action( array, exit, err = kNoMemoryErr );
-
- for( i = 0; i < inTypeCount; ++i )
- {
- type = va_arg( args, unsigned int );
- require_action_quiet( type <= UINT16_MAX, exit, err = kRangeErr );
- array[ i ] = type;
- }
- qsort( array, inTypeCount, sizeof_element( array ), _QSortCmpUnsigned );
-
- currBlock = array[ 0 ] / 256;
- for( i = 0; i < inTypeCount; ++i )
- {
- const unsigned int block = array[ i ] / 256;
- const unsigned int bit = array[ i ] % 256;
-
- if( block != currBlock )
- {
- bitmapLen = BitArray_MaxBytes( maxBit + 1 );
- fields[ 0 ] = (uint8_t) currBlock;
- fields[ 1 ] = (uint8_t) bitmapLen;
-
- err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
- require_noerr( err, exit );
-
- maxBit = 0;
- currBlock = block;
- memset( bitmap, 0, bitmapLen );
- }
- BitArray_SetBit( bitmap, bit );
- if( bit > maxBit ) maxBit = bit;
- }
- }
- else
- {
- currBlock = 0;
- }
-
- bitmapLen = BitArray_MaxBytes( maxBit + 1 );
- fields[ 0 ] = (uint8_t) currBlock;
- fields[ 1 ] = (uint8_t) bitmapLen;
-
- err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
- require_noerr( err, exit );
-
- err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
- require_noerr( err, exit );
-
-exit:
- va_end( args );
- DataBuffer_Free( &rdataDB );
- FreeNullSafe( array );
- return( err );
-}
-
-//===========================================================================================================================
-// AppendSOARecord
-//===========================================================================================================================
-
-static OSStatus
- _AppendSOARecordData(
- DataBuffer * inDB,
- const uint8_t * inMName,
- const uint8_t * inRName,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimumTTL,
- size_t * outLen );
-
-static OSStatus
- AppendSOARecord(
- DataBuffer * inDB,
- const uint8_t * inNamePtr,
- size_t inNameLen,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- const uint8_t * inMName,
- const uint8_t * inRName,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimumTTL,
- size_t * outLen )
-{
- OSStatus err;
- size_t rdataLen;
- size_t rdlengthOffset = 0;
- uint8_t * rdlengthPtr;
-
- if( inDB )
- {
- err = _DataBuffer_AppendDNSRecord( inDB, inNamePtr, inNameLen, inType, inClass, inTTL, NULL, 0 );
- require_noerr( err, exit );
-
- rdlengthOffset = DataBuffer_GetLen( inDB ) - 2;
- }
-
- err = _AppendSOARecordData( inDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, &rdataLen );
- require_noerr( err, exit );
-
- if( inDB )
- {
- rdlengthPtr = DataBuffer_GetPtr( inDB ) + rdlengthOffset;
- WriteBig16( rdlengthPtr, rdataLen );
- }
-
- if( outLen ) *outLen = inNameLen + sizeof( DNSRecordFixedFields ) + rdataLen;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-static OSStatus
- _AppendSOARecordData(
- DataBuffer * inDB,
- const uint8_t * inMName,
- const uint8_t * inRName,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimumTTL,
- size_t * outLen )
-{
- OSStatus err;
- SOARecordDataFixedFields fields;
- const size_t mnameLen = DomainNameLength( inMName );
- const size_t rnameLen = DomainNameLength( inRName );
-
- if( inDB )
- {
- err = DataBuffer_Append( inDB, inMName, mnameLen );
- require_noerr( err, exit );
-
- err = DataBuffer_Append( inDB, inRName, rnameLen );
- require_noerr( err, exit );
-
- SOARecordDataFixedFieldsSet( &fields, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL );
- err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
- }
- if( outLen ) *outLen = mnameLen + rnameLen + sizeof( fields );
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// CreateSOARecordData
-//===========================================================================================================================
-
-static OSStatus
- CreateSOARecordData(
- const uint8_t * inMName,
- const uint8_t * inRName,
- uint32_t inSerial,
- uint32_t inRefresh,
- uint32_t inRetry,
- uint32_t inExpire,
- uint32_t inMinimumTTL,
- uint8_t ** outPtr,
- size_t * outLen )
-{
- OSStatus err;
- DataBuffer rdataDB;
-
- DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
-
- err = _AppendSOARecordData( &rdataDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, NULL );
- require_noerr( err, exit );
-
- err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
- require_noerr( err, exit );
-
-exit:
- DataBuffer_Free( &rdataDB );
- return( err );
-}
-
-//===========================================================================================================================
-// _DataBuffer_AppendDNSQuestion
-//===========================================================================================================================
-
-static OSStatus
- _DataBuffer_AppendDNSQuestion(
- DataBuffer * inDB,
- const uint8_t * inNamePtr,
- size_t inNameLen,
- uint16_t inType,
- uint16_t inClass )
-{
- OSStatus err;
- DNSQuestionFixedFields fields;
-
- err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
- require_noerr( err, exit );
-
- DNSQuestionFixedFieldsInit( &fields, inType, inClass );
- err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _DataBuffer_AppendDNSRecord
-//===========================================================================================================================
-
-static OSStatus
- _DataBuffer_AppendDNSRecord(
- DataBuffer * inDB,
- const uint8_t * inNamePtr,
- size_t inNameLen,
- uint16_t inType,
- uint16_t inClass,
- uint32_t inTTL,
- const uint8_t * inRDataPtr,
- size_t inRDataLen )
-{
- OSStatus err;
- DNSRecordFixedFields fields;
-
- require_action_quiet( inRDataLen < kDNSRecordDataLengthMax, exit, err = kSizeErr );
-
- err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
- require_noerr( err, exit );
-
- DNSRecordFixedFieldsSet( &fields, inType, inClass, inTTL, (uint16_t) inRDataLen );
- err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
- require_noerr( err, exit );
-
- if( inRDataPtr )
- {
- err = DataBuffer_Append( inDB, inRDataPtr, inRDataLen );
- require_noerr( err, exit );
- }
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _NanoTime64ToDateString
-//===========================================================================================================================
-
-static char * _NanoTime64ToDateString( NanoTime64 inTime, char *inBuf, size_t inMaxLen )
-{
- struct timeval tv;
-
- NanoTimeToTimeVal( inTime, &tv );
- return( MakeFractionalDateString( &tv, inBuf, inMaxLen ) );
-}
-
-//===========================================================================================================================
-// MDNSColliderCreate
-//===========================================================================================================================
-
-typedef enum
-{
- kMDNSColliderOpCode_Invalid = 0,
- kMDNSColliderOpCode_Send = 1,
- kMDNSColliderOpCode_Wait = 2,
- kMDNSColliderOpCode_SetProbeActions = 3,
- kMDNSColliderOpCode_LoopPush = 4,
- kMDNSColliderOpCode_LoopPop = 5,
- kMDNSColliderOpCode_Exit = 6
-
-} MDNSColliderOpCode;
-
-typedef struct
-{
- MDNSColliderOpCode opcode;
- uint32_t operand;
-
-} MDNSCInstruction;
-
-#define kMaxLoopDepth 16
-
-struct MDNSColliderPrivate
-{
- CFRuntimeBase base; // CF object base.
- dispatch_queue_t queue; // Queue for collider's events.
- dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
- dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
- SocketRef sockV4; // IPv4 UDP socket for mDNS.
- SocketRef sockV6; // IPv6 UDP socket for mDNS.
- uint8_t * target; // Record name being targeted. (malloced)
- uint8_t * responsePtr; // Response message pointer. (malloced)
- size_t responseLen; // Response message length.
- uint8_t * probePtr; // Probe query message pointer. (malloced)
- size_t probeLen; // Probe query message length.
- unsigned int probeCount; // Count of probe queries received for collider's record.
- uint32_t probeActionMap; // Bitmap of actions to take for
- MDNSCInstruction * program; // Program to execute.
- uint32_t pc; // Program's program counter.
- uint32_t loopCounts[ kMaxLoopDepth ]; // Stack of loop counters.
- uint32_t loopDepth; // Current loop depth.
- dispatch_source_t waitTimer; // Timer for program's wait commands.
- uint32_t interfaceIndex; // Interface over which to send and receive mDNS msgs.
- MDNSColliderStopHandler_f stopHandler; // User's stop handler.
- void * stopContext; // User's stop handler context.
- MDNSColliderProtocols protocols; // Protocols to use, i.e., IPv4, IPv6.
- Boolean stopped; // True if the collider has been stopped.
- uint8_t msgBuf[ kMDNSMessageSizeMax ]; // mDNS message buffer.
-};
-
-static void _MDNSColliderStop( MDNSColliderRef inCollider, OSStatus inError );
-static void _MDNSColliderReadHandler( void *inContext );
-static void _MDNSColliderExecuteProgram( void *inContext );
-static OSStatus _MDNSColliderSendResponse( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
-static OSStatus _MDNSColliderSendProbe( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
-
-CF_CLASS_DEFINE( MDNSCollider );
-
-ulog_define_ex( "com.apple.dnssdutil", MDNSCollider, kLogLevelInfo, kLogFlags_None, "MDNSCollider", NULL );
-#define mc_ulog( LEVEL, ... ) ulog( &log_category_from_name( MDNSCollider ), (LEVEL), __VA_ARGS__ )
-
-static OSStatus MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider )
-{
- OSStatus err;
- MDNSColliderRef obj = NULL;
-
- CF_OBJECT_CREATE( MDNSCollider, obj, err, exit );
-
- ReplaceDispatchQueue( &obj->queue, inQueue );
- obj->sockV4 = kInvalidSocketRef;
- obj->sockV6 = kInvalidSocketRef;
-
- *outCollider = obj;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSColliderFinalize
-//===========================================================================================================================
-
-static void _MDNSColliderFinalize( CFTypeRef inObj )
-{
- MDNSColliderRef const me = (MDNSColliderRef) inObj;
-
- check( !me->waitTimer );
- check( !me->readSourceV4 );
- check( !me->readSourceV6 );
- check( !IsValidSocket( me->sockV4 ) );
- check( !IsValidSocket( me->sockV6 ) );
- ForgetMem( &me->target );
- ForgetMem( &me->responsePtr );
- ForgetMem( &me->probePtr );
- ForgetMem( &me->program );
- dispatch_forget( &me->queue );
-}
-
-//===========================================================================================================================
-// MDNSColliderStart
-//===========================================================================================================================
-
-static void _MDNSColliderStart( void *inContext );
-
-static OSStatus MDNSColliderStart( MDNSColliderRef me )
-{
- OSStatus err;
-
- require_action_quiet( me->target, exit, err = kNotPreparedErr );
- require_action_quiet( me->responsePtr, exit, err = kNotPreparedErr );
- require_action_quiet( me->probePtr, exit, err = kNotPreparedErr );
- require_action_quiet( me->program, exit, err = kNotPreparedErr );
- require_action_quiet( me->interfaceIndex, exit, err = kNotPreparedErr );
- require_action_quiet( me->protocols, exit, err = kNotPreparedErr );
-
- CFRetain( me );
- dispatch_async_f( me->queue, me, _MDNSColliderStart );
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-static void _MDNSColliderStart( void *inContext )
-{
- OSStatus err;
- MDNSColliderRef const me = (MDNSColliderRef) inContext;
- SocketRef sock = kInvalidSocketRef;
- SocketContext * sockCtx = NULL;
-
- if( me->protocols & kMDNSColliderProtocol_IPv4 )
- {
- err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
- require_noerr( err, exit );
-
- err = SocketContextCreate( sock, me, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
- sockCtx, &me->readSourceV4 );
- require_noerr( err, exit );
- me->sockV4 = sockCtx->sock;
- sockCtx = NULL;
-
- dispatch_resume( me->readSourceV4 );
- }
-
- if( me->protocols & kMDNSColliderProtocol_IPv6 )
- {
- err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
- require_noerr( err, exit );
-
- err = SocketContextCreate( sock, me, &sockCtx );
- require_noerr( err, exit );
- sock = kInvalidSocketRef;
-
- err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
- sockCtx, &me->readSourceV6 );
- require_noerr( err, exit );
- me->sockV6 = sockCtx->sock;
- sockCtx = NULL;
-
- dispatch_resume( me->readSourceV6 );
- }
-
- _MDNSColliderExecuteProgram( me );
- err = kNoErr;
-
-exit:
- ForgetSocket( &sock );
- ForgetSocketContext( &sockCtx );
- if( err ) _MDNSColliderStop( me, err );
-}
-
-//===========================================================================================================================
-// MDNSColliderStop
-//===========================================================================================================================
-
-static void _MDNSColliderUserStop( void *inContext );
-
-static void MDNSColliderStop( MDNSColliderRef me )
-{
- CFRetain( me );
- dispatch_async_f( me->queue, me, _MDNSColliderUserStop );
-}
-
-static void _MDNSColliderUserStop( void *inContext )
-{
- MDNSColliderRef const me = (MDNSColliderRef) inContext;
-
- _MDNSColliderStop( me, kCanceledErr );
- CFRelease( me );
-}
-
-//===========================================================================================================================
-// MDNSColliderSetProtocols
-//===========================================================================================================================
-
-static void MDNSColliderSetProtocols( MDNSColliderRef me, MDNSColliderProtocols inProtocols )
-{
- me->protocols = inProtocols;
-}
-
-//===========================================================================================================================
-// MDNSColliderSetInterfaceIndex
-//===========================================================================================================================
-
-static void MDNSColliderSetInterfaceIndex( MDNSColliderRef me, uint32_t inInterfaceIndex )
-{
- me->interfaceIndex = inInterfaceIndex;
-}
-
-//===========================================================================================================================
-// MDNSColliderSetProgram
-//===========================================================================================================================
-
-#define kMDNSColliderProgCmd_Done "done"
-#define kMDNSColliderProgCmd_Loop "loop"
-#define kMDNSColliderProgCmd_Send "send"
-#define kMDNSColliderProgCmd_Probes "probes"
-#define kMDNSColliderProgCmd_Wait "wait"
-
-typedef uint32_t MDNSColliderProbeAction;
-
-#define kMDNSColliderProbeAction_None 0
-#define kMDNSColliderProbeAction_Respond 1
-#define kMDNSColliderProbeAction_RespondUnicast 2
-#define kMDNSColliderProbeAction_RespondMulticast 3
-#define kMDNSColliderProbeAction_Probe 4
-#define kMDNSColliderProbeAction_MaxValue kMDNSColliderProbeAction_Probe
-
-#define kMDNSColliderProbeActionBits_Count 3
-#define kMDNSColliderProbeActionBits_Mask ( ( 1U << kMDNSColliderProbeActionBits_Count ) - 1 )
-#define kMDNSColliderProbeActionMaxProbeCount ( 32 / kMDNSColliderProbeActionBits_Count )
-
-check_compile_time( kMDNSColliderProbeAction_MaxValue <= kMDNSColliderProbeActionBits_Mask );
-
-static OSStatus _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap );
-
-static OSStatus MDNSColliderSetProgram( MDNSColliderRef me, const char *inProgramStr )
-{
- OSStatus err;
- uint32_t insCount;
- unsigned int loopDepth;
- const char * cmd;
- const char * end;
- const char * next;
- MDNSCInstruction * program = NULL;
- uint32_t loopStart[ kMaxLoopDepth ];
-
- insCount = 0;
- for( cmd = inProgramStr; *cmd; cmd = next )
- {
- for( end = cmd; *end && ( *end != ';' ); ++end ) {}
- require_action_quiet( end != cmd, exit, err = kMalformedErr );
- next = ( *end == ';' ) ? ( end + 1 ) : end;
- ++insCount;
- }
-
- program = (MDNSCInstruction *) calloc( insCount + 1, sizeof( *program ) );
- require_action( program, exit, err = kNoMemoryErr );
-
- insCount = 0;
- loopDepth = 0;
- for( cmd = inProgramStr; *cmd; cmd = next )
- {
- size_t cmdLen;
- const char * ptr;
- const char * arg;
- size_t argLen;
- uint32_t value;
- MDNSCInstruction * const ins = &program[ insCount ];
-
- while( isspace_safe( *cmd ) ) ++cmd;
- for( end = cmd; *end && ( *end != ';' ); ++end ) {}
- next = ( *end == ';' ) ? ( end + 1 ) : end;
-
- for( ptr = cmd; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
- cmdLen = (size_t)( ptr - cmd );
-
- // Done statement
-
- if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Done ) == 0 )
- {
- while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
- require_action_quiet( ptr == end, exit, err = kMalformedErr );
-
- require_action_quiet( loopDepth > 0, exit, err = kMalformedErr );
-
- ins->opcode = kMDNSColliderOpCode_LoopPop;
- ins->operand = loopStart[ --loopDepth ];
- }
-
- // Loop command
-
- else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Loop ) == 0 )
- {
- for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
- err = DecimalTextToUInt32( arg, end, &value, &ptr );
- require_noerr_quiet( err, exit );
- require_action_quiet( value > 0, exit, err = kValueErr );
-
- while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
- require_action_quiet( ptr == end, exit, err = kMalformedErr );
-
- ins->opcode = kMDNSColliderOpCode_LoopPush;
- ins->operand = value;
-
- require_action_quiet( loopDepth < kMaxLoopDepth, exit, err = kNoSpaceErr );
- loopStart[ loopDepth++ ] = insCount + 1;
- }
-
- // Probes command
-
- else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Probes ) == 0 )
- {
- for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
- for( ptr = arg; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
- argLen = (size_t)( ptr - arg );
- if( argLen > 0 )
- {
- err = _MDNSColliderParseProbeActionString( arg, argLen, &value );
- require_noerr_quiet( err, exit );
- }
- else
- {
- value = 0;
- }
-
- while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
- require_action_quiet( ptr == end, exit, err = kMalformedErr );
-
- ins->opcode = kMDNSColliderOpCode_SetProbeActions;
- ins->operand = value;
- }
-
- // Send command
-
- else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Send ) == 0 )
- {
- while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
- require_action_quiet( ptr == end, exit, err = kMalformedErr );
-
- ins->opcode = kMDNSColliderOpCode_Send;
- }
-
- // Wait command
-
- else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Wait ) == 0 )
- {
- for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
- err = DecimalTextToUInt32( arg, end, &value, &ptr );
- require_noerr_quiet( err, exit );
-
- while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
- require_action_quiet( ptr == end, exit, err = kMalformedErr );
-
- ins->opcode = kMDNSColliderOpCode_Wait;
- ins->operand = value;
- }
-
- // Unrecognized command
-
- else
- {
- err = kCommandErr;
- goto exit;
- }
- ++insCount;
- }
- require_action_quiet( loopDepth == 0, exit, err = kMalformedErr );
-
- program[ insCount ].opcode = kMDNSColliderOpCode_Exit;
-
- FreeNullSafe( me->program );
- me->program = program;
- program = NULL;
- err = kNoErr;
-
-exit:
- FreeNullSafe( program );
- return( err );
-}
-
-static OSStatus _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap )
-{
- OSStatus err;
- const char * ptr;
- const char * const end = &inString[ inLen ];
- uint32_t bitmap;
- int index;
-
- bitmap = 0;
- index = 0;
- ptr = inString;
- while( ptr < end )
- {
- int c, count;
- MDNSColliderProbeAction action;
-
- c = *ptr++;
- if( isdigit_safe( c ) )
- {
- count = 0;
- do
- {
- count = ( count * 10 ) + ( c - '0' );
- require_action_quiet( count <= ( kMDNSColliderProbeActionMaxProbeCount - index ), exit, err = kCountErr );
- require_action_quiet( ptr < end, exit, err = kUnderrunErr );
- c = *ptr++;
-
- } while( isdigit_safe( c ) );
- require_action_quiet( count > 0, exit, err = kCountErr );
- }
- else
- {
- require_action_quiet( index < kMDNSColliderProbeActionMaxProbeCount, exit, err = kMalformedErr );
- count = 1;
- }
-
- switch( c )
- {
- case 'n': action = kMDNSColliderProbeAction_None; break;
- case 'r': action = kMDNSColliderProbeAction_Respond; break;
- case 'u': action = kMDNSColliderProbeAction_RespondUnicast; break;
- case 'm': action = kMDNSColliderProbeAction_RespondMulticast; break;
- case 'p': action = kMDNSColliderProbeAction_Probe; break;
- default: err = kMalformedErr; goto exit;
- }
- if( ptr < end )
- {
- c = *ptr++;
- require_action_quiet( ( c == '-' ) && ( ptr < end ), exit, err = kMalformedErr );
- }
- while( count-- > 0 )
- {
- bitmap |= ( action << ( index * kMDNSColliderProbeActionBits_Count ) );
- ++index;
- }
- }
-
- *outBitmap = bitmap;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// MDNSColliderSetStopHandler
-//===========================================================================================================================
-
-static void MDNSColliderSetStopHandler( MDNSColliderRef me, MDNSColliderStopHandler_f inStopHandler, void *inStopContext )
-{
- me->stopHandler = inStopHandler;
- me->stopContext = inStopContext;
-}
-
-//===========================================================================================================================
-// MDNSColliderSetRecord
-//===========================================================================================================================
-
-#define kMDNSColliderDummyStr "\x16" "mdnscollider-sent-this" kLocalStr
-#define kMDNSColliderDummyName ( (const uint8_t *) kMDNSColliderDummyStr )
-#define kMDNSColliderDummyNameLen sizeof( kMDNSColliderDummyStr )
-
-static OSStatus
- MDNSColliderSetRecord(
- MDNSColliderRef me,
- const uint8_t * inName,
- uint16_t inType,
- const void * inRDataPtr,
- size_t inRDataLen )
-{
- OSStatus err;
- DataBuffer msgDB;
- DNSHeader header;
- uint8_t * targetPtr = NULL;
- size_t targetLen;
- uint8_t * responsePtr = NULL;
- size_t responseLen;
- uint8_t * probePtr = NULL;
- size_t probeLen;
-
- DataBuffer_Init( &msgDB, NULL, 0, kMDNSMessageSizeMax );
-
- err = DomainNameDup( inName, &targetPtr, &targetLen );
- require_noerr_quiet( err, exit );
-
- // Create response message.
-
- memset( &header, 0, sizeof( header ) );
- DNSHeaderSetFlags( &header, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
- DNSHeaderSetAnswerCount( &header, 1 );
-
- err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
- require_noerr( err, exit );
-
- err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN | kRRClassCacheFlushBit,
- 1976, inRDataPtr, inRDataLen );
- require_noerr( err, exit );
-
- err = DataBuffer_Detach( &msgDB, &responsePtr, &responseLen );
- require_noerr( err, exit );
-
- // Create probe message.
-
- memset( &header, 0, sizeof( header ) );
- DNSHeaderSetQuestionCount( &header, 2 );
- DNSHeaderSetAuthorityCount( &header, 1 );
-
- err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
- require_noerr( err, exit );
-
- err = _DataBuffer_AppendDNSQuestion( &msgDB, targetPtr, targetLen, kDNSServiceType_ANY, kDNSServiceClass_IN );
- require_noerr( err, exit );
-
- err = _DataBuffer_AppendDNSQuestion( &msgDB, kMDNSColliderDummyName, kMDNSColliderDummyNameLen,
- kDNSServiceType_NULL, kDNSServiceClass_IN );
- require_noerr( err, exit );
-
- err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN,
- 1976, inRDataPtr, inRDataLen );
- require_noerr( err, exit );
-
- err = DataBuffer_Detach( &msgDB, &probePtr, &probeLen );
- require_noerr( err, exit );
-
- FreeNullSafe( me->target );
- me->target = targetPtr;
- targetPtr = NULL;
-
- FreeNullSafe( me->responsePtr );
- me->responsePtr = responsePtr;
- me->responseLen = responseLen;
- responsePtr = NULL;
-
- FreeNullSafe( me->probePtr );
- me->probePtr = probePtr;
- me->probeLen = probeLen;
- probePtr = NULL;
-
-exit:
- DataBuffer_Free( &msgDB );
- FreeNullSafe( targetPtr );
- FreeNullSafe( responsePtr );
- FreeNullSafe( probePtr );
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSColliderStop
-//===========================================================================================================================
-
-static void _MDNSColliderStop( MDNSColliderRef me, OSStatus inError )
-{
- dispatch_source_forget( &me->waitTimer );
- dispatch_source_forget( &me->readSourceV4 );
- dispatch_source_forget( &me->readSourceV6 );
- me->sockV4 = kInvalidSocketRef;
- me->sockV6 = kInvalidSocketRef;
-
- if( !me->stopped )
- {
- me->stopped = true;
- if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
- CFRelease( me );
- }
-}
-
-//===========================================================================================================================
-// _MDNSColliderReadHandler
-//===========================================================================================================================
-
-static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber );
-static const char * _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction );
-
-static void _MDNSColliderReadHandler( void *inContext )
-{
- OSStatus err;
- struct timeval now;
- SocketContext * const sockCtx = (SocketContext *) inContext;
- MDNSColliderRef const me = (MDNSColliderRef) sockCtx->userContext;
- size_t msgLen;
- sockaddr_ip sender;
- const DNSHeader * hdr;
- const uint8_t * ptr;
- const struct sockaddr * dest;
- int probeFound, probeIsQU;
- unsigned int qCount, i;
- MDNSColliderProbeAction action;
-
- gettimeofday( &now, NULL );
-
- err = SocketRecvFrom( sockCtx->sock, me->msgBuf, sizeof( me->msgBuf ), &msgLen, &sender, sizeof( sender ),
- NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- require_quiet( msgLen >= kDNSHeaderLength, exit );
- hdr = (const DNSHeader *) me->msgBuf;
-
- probeFound = false;
- probeIsQU = false;
- qCount = DNSHeaderGetQuestionCount( hdr );
- ptr = (const uint8_t *) &hdr[ 1 ];
- for( i = 0; i < qCount; ++i )
- {
- uint16_t qtype, qclass;
- uint8_t qname[ kDomainNameLengthMax ];
-
- err = DNSMessageExtractQuestion( me->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
- require_noerr_quiet( err, exit );
-
- if( ( qtype == kDNSServiceType_NULL ) && ( qclass == kDNSServiceClass_IN ) &&
- DomainNameEqual( qname, kMDNSColliderDummyName ) )
- {
- probeFound = false;
- break;
- }
-
- if( qtype != kDNSServiceType_ANY ) continue;
- if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
- if( !DomainNameEqual( qname, me->target ) ) continue;
-
- if( !probeFound )
- {
- probeFound = true;
- probeIsQU = ( qclass & kQClassUnicastResponseBit ) ? true : false;
- }
- }
- require_quiet( probeFound, exit );
-
- ++me->probeCount;
- action = _MDNSColliderGetProbeAction( me->probeActionMap, me->probeCount );
-
- mc_ulog( kLogLevelInfo, "Received probe from %##a at %{du:time} (action: %s):\n\n%#1{du:dnsmsg}",
- &sender, &now, _MDNSColliderProbeActionToString( action ), me->msgBuf, msgLen );
-
- if( ( action == kMDNSColliderProbeAction_Respond ) ||
- ( action == kMDNSColliderProbeAction_RespondUnicast ) ||
- ( action == kMDNSColliderProbeAction_RespondMulticast ) )
- {
- if( ( ( action == kMDNSColliderProbeAction_Respond ) && probeIsQU ) ||
- ( action == kMDNSColliderProbeAction_RespondUnicast ) )
- {
- dest = &sender.sa;
- }
- else if( ( ( action == kMDNSColliderProbeAction_Respond ) && !probeIsQU ) ||
- ( action == kMDNSColliderProbeAction_RespondMulticast ) )
- {
- dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
- }
-
- err = _MDNSColliderSendResponse( me, sockCtx->sock, dest );
- require_noerr( err, exit );
- }
- else if( action == kMDNSColliderProbeAction_Probe )
- {
- dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
-
- err = _MDNSColliderSendProbe( me, sockCtx->sock, dest );
- require_noerr( err, exit );
- }
-
-exit:
- return;
-}
-
-static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber )
-{
- MDNSColliderProbeAction action;
-
- if( ( inProbeNumber >= 1 ) && ( inProbeNumber <= kMDNSColliderProbeActionMaxProbeCount ) )
- {
- action = ( inBitmap >> ( ( inProbeNumber - 1 ) * kMDNSColliderProbeActionBits_Count ) ) &
- kMDNSColliderProbeActionBits_Mask;
- }
- else
- {
- action = kMDNSColliderProbeAction_None;
- }
- return( action );
-}
-
-static const char * _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction )
-{
- switch( inAction )
- {
- case kMDNSColliderProbeAction_None: return( "None" );
- case kMDNSColliderProbeAction_Respond: return( "Respond" );
- case kMDNSColliderProbeAction_RespondUnicast: return( "Respond (unicast)" );
- case kMDNSColliderProbeAction_RespondMulticast: return( "Respond (multicast)" );
- case kMDNSColliderProbeAction_Probe: return( "Probe" );
- default: return( "???" );
- }
-}
-
-//===========================================================================================================================
-// _MDNSColliderExecuteProgram
-//===========================================================================================================================
-
-static void _MDNSColliderExecuteProgram( void *inContext )
-{
- OSStatus err;
- MDNSColliderRef const me = (MDNSColliderRef) inContext;
- int stop;
-
- dispatch_forget( &me->waitTimer );
-
- stop = false;
- for( ;; )
- {
- const MDNSCInstruction * const ins = &me->program[ me->pc++ ];
- uint32_t waitMs;
-
- switch( ins->opcode )
- {
- case kMDNSColliderOpCode_Send:
- if( IsValidSocket( me->sockV4 ) )
- {
- err = _MDNSColliderSendResponse( me, me->sockV4, GetMDNSMulticastAddrV4() );
- require_noerr( err, exit );
- }
- if( IsValidSocket( me->sockV6 ) )
- {
- err = _MDNSColliderSendResponse( me, me->sockV6, GetMDNSMulticastAddrV6() );
- require_noerr( err, exit );
- }
- break;
-
- case kMDNSColliderOpCode_Wait:
- waitMs = ins->operand;
- if( waitMs > 0 )
- {
- err = DispatchTimerOneShotCreate( dispatch_time_milliseconds( waitMs ), 1, me->queue,
- _MDNSColliderExecuteProgram, me, &me->waitTimer );
- require_noerr( err, exit );
- dispatch_resume( me->waitTimer );
- goto exit;
- }
- break;
-
- case kMDNSColliderOpCode_SetProbeActions:
- me->probeCount = 0;
- me->probeActionMap = ins->operand;
- break;
-
- case kMDNSColliderOpCode_LoopPush:
- check( me->loopDepth < kMaxLoopDepth );
- me->loopCounts[ me->loopDepth++ ] = ins->operand;
- break;
-
- case kMDNSColliderOpCode_LoopPop:
- check( me->loopDepth > 0 );
- if( --me->loopCounts[ me->loopDepth - 1 ] > 0 )
- {
- me->pc = ins->operand;
- }
- else
- {
- --me->loopDepth;
- }
- break;
-
- case kMDNSColliderOpCode_Exit:
- stop = true;
- err = kNoErr;
- goto exit;
-
- default:
- dlogassert( "Unhandled opcode %u\n", ins->opcode );
- err = kCommandErr;
- goto exit;
- }
- }
-
-exit:
- if( err || stop ) _MDNSColliderStop( me, err );
-}
-
-//===========================================================================================================================
-// _MDNSColliderSendResponse
-//===========================================================================================================================
-
-static OSStatus _MDNSColliderSendResponse( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
-{
- OSStatus err;
- ssize_t n;
-
- n = sendto( inSock, (char *) me->responsePtr, me->responseLen, 0, inDest, SockAddrGetSize( inDest ) );
- err = map_socket_value_errno( inSock, n == (ssize_t) me->responseLen, n );
- return( err );
-}
-
-//===========================================================================================================================
-// _MDNSColliderSendProbe
-//===========================================================================================================================
-
-static OSStatus _MDNSColliderSendProbe( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
-{
- OSStatus err;
- ssize_t n;
-
- n = sendto( inSock, (char *) me->probePtr, me->probeLen, 0, inDest, SockAddrGetSize( inDest ) );
- err = map_socket_value_errno( inSock, n == (ssize_t) me->probeLen, n );
- return( err );
-}
-
-//===========================================================================================================================
-// ServiceBrowserCreate
-//===========================================================================================================================
-
-typedef struct SBDomain SBDomain;
-typedef struct SBServiceType SBServiceType;
-typedef struct SBServiceBrowse SBServiceBrowse;
-typedef struct SBServiceInstance SBServiceInstance;
-typedef struct SBIPAddress SBIPAddress;
-
-struct ServiceBrowserPrivate
-{
- CFRuntimeBase base; // CF object base.
- dispatch_queue_t queue; // Queue for service browser's events.
- DNSServiceRef connection; // Shared connection for DNS-SD ops.
- DNSServiceRef domainsQuery; // Query for recommended browsing domains.
- char * domain; // If non-null, then browsing is limited to this domain.
- StringListItem * serviceTypeList; // If non-null, then browsing is limited to these service types.
- ServiceBrowserCallback_f userCallback; // User's callback. Called when browsing stops.
- void * userContext; // User's callback context.
- SBDomain * domainList; // List of domains and their browse results.
- dispatch_source_t stopTimer; // Timer to stop browsing after browseTimeSecs.
- uint32_t ifIndex; // If non-zero, then browsing is limited to this interface.
- unsigned int browseTimeSecs; // Amount of time to spend browsing in seconds.
- Boolean includeAWDL; // True if the IncludeAWDL flag should be used for DNS-SD ops that
- // use the "any" interface.
-};
-
-struct SBDomain
-{
- SBDomain * next; // Next domain object in list.
- ServiceBrowserRef browser; // Pointer to parent service browser.
- char * name; // Name of the domain.
- DNSServiceRef servicesQuery; // Query for services (_services._dns-sd._udp.<domain> PTR record) in domain.
- SBServiceType * typeList; // List of service types to browse for in this domain.
-};
-
-struct SBServiceType
-{
- SBServiceType * next; // Next service type object in list.
- char * name; // Name of the service type.
- SBServiceBrowse * browseList; // List of browses for this service type.
-};
-
-struct SBServiceBrowse
-{
- SBServiceBrowse * next; // Next browse object in list.
- ServiceBrowserRef browser; // Pointer to parent service browser.
- DNSServiceRef browse; // Reference to DNSServiceBrowse op.
- SBServiceInstance * instanceList; // List of service instances that were discovered by this browse.
- uint64_t startTicks; // Value of UpTicks() when the browse op began.
- uint32_t ifIndex; // If non-zero, then the browse is limited to this interface.
-};
-
-struct SBServiceInstance
-{
- SBServiceInstance * next; // Next service instance object in list.
- ServiceBrowserRef browser; // Pointer to parent service browser.
- char * name; // Name of the service instance.
- uint32_t ifIndex; // Index of interface over which this service instance was discovered.
- uint64_t discoverTimeUs; // Time it took to discover this service instance in microseconds.
- DNSServiceRef resolve; // Reference to DNSServiceResolve op for this service instance.
- uint64_t resolveStartTicks; // Value of UpTicks() when the DNSServiceResolve op began.
- uint64_t resolveTimeUs; // Time it took to resolve this service instance.
- char * hostname; // Service instance's hostname. Result of DNSServiceResolve.
- uint16_t port; // Service instance's port number. Result of DNSServiceResolve.
- uint8_t * txtPtr; // Service instance's TXT record data. Result of DNSServiceResolve.
- size_t txtLen; // Length of service instance's TXT record data.
- DNSServiceRef getAddrInfo; // Reference to DNSServiceGetAddrInfo op for service instance's hostname.
- uint64_t gaiStartTicks; // Value of UpTicks() when the DNSServiceGetAddrInfo op began.
- SBIPAddress * ipaddrList; // List of IP addresses that the hostname resolved to.
-};
-
-struct SBIPAddress
-{
- SBIPAddress * next; // Next IP address object in list.
- sockaddr_ip sip; // IPv4 or IPv6 address.
- uint64_t resolveTimeUs; // Time it took to resolve this IP address in microseconds.
-};
-
-typedef struct
-{
- SBRDomain * domainList; // List of domains in which services were found.
- int32_t refCount; // This object's reference count.
-
-} ServiceBrowserResultsPrivate;
-
-static void _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError );
-static OSStatus _ServiceBrowserAddDomain( ServiceBrowserRef inBrowser, const char *inDomain );
-static OSStatus _ServiceBrowserRemoveDomain( ServiceBrowserRef inBrowser, const char *inName );
-static void _ServiceBrowserTimerHandler( void *inContext );
-static void DNSSD_API
- _ServiceBrowserDomainsQueryCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-static void DNSSD_API
- _ServiceBrowserServicesQueryCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext );
-static void DNSSD_API
- _ServiceBrowserBrowseCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inRegType,
- const char * inDomain,
- void * inContext );
-static void DNSSD_API
- _ServiceBrowserResolveCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- const char * inHostname,
- uint16_t inPort,
- uint16_t inTXTLen,
- const unsigned char * inTXTPtr,
- void * inContext );
-static void DNSSD_API
- _ServiceBrowserGAICallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext );
-static OSStatus
- _ServiceBrowserAddServiceType(
- ServiceBrowserRef inBrowser,
- SBDomain * inDomain,
- const char * inName,
- uint32_t inIfIndex );
-static OSStatus
- _ServiceBrowserRemoveServiceType(
- ServiceBrowserRef inBrowser,
- SBDomain * inDomain,
- const char * inName,
- uint32_t inIfIndex );
-static OSStatus
- _ServiceBrowserAddServiceInstance(
- ServiceBrowserRef inBrowser,
- SBServiceBrowse * inBrowse,
- uint32_t inIfIndex,
- const char * inName,
- const char * inRegType,
- const char * inDomain,
- uint64_t inDiscoverTimeUs );
-static OSStatus
- _ServiceBrowserRemoveServiceInstance(
- ServiceBrowserRef inBrowser,
- SBServiceBrowse * inBrowse,
- const char * inName,
- uint32_t inIfIndex );
-static OSStatus
- _ServiceBrowserAddIPAddress(
- ServiceBrowserRef inBrowser,
- SBServiceInstance * inInstance,
- const struct sockaddr * inSockAddr,
- uint64_t inResolveTimeUs );
-static OSStatus
- _ServiceBrowserRemoveIPAddress(
- ServiceBrowserRef inBrowser,
- SBServiceInstance * inInstance,
- const struct sockaddr * inSockAddr );
-static OSStatus _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults );
-static OSStatus _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain );
-static void _SBDomainFree( SBDomain *inDomain );
-static OSStatus _SBServiceTypeCreate( const char *inName, SBServiceType **outType );
-static void _SBServiceTypeFree( SBServiceType *inType );
-static OSStatus _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse );
-static void _SBServiceBrowseFree( SBServiceBrowse *inBrowse );
-static OSStatus
- _SBServiceInstanceCreate(
- const char * inName,
- uint32_t inIfIndex,
- uint64_t inDiscoverTimeUs,
- ServiceBrowserRef inBrowser,
- SBServiceInstance ** outInstance );
-static void _SBServiceInstanceFree( SBServiceInstance *inInstance );
-static OSStatus
- _SBIPAddressCreate(
- const struct sockaddr * inSockAddr,
- uint64_t inResolveTimeUs,
- SBIPAddress ** outIPAddress );
-static void _SBIPAddressFree( SBIPAddress *inIPAddress );
-static void _SBIPAddressFreeList( SBIPAddress *inList );
-static OSStatus _SBRDomainCreate( const char *inName, SBRDomain **outDomain );
-static void _SBRDomainFree( SBRDomain *inDomain );
-static OSStatus _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType );
-static void _SBRServiceTypeFree( SBRServiceType *inType );
-static OSStatus
- _SBRServiceInstanceCreate(
- const char * inName,
- uint32_t inInterfaceIndex,
- const char * inHostname,
- uint16_t inPort,
- const uint8_t * inTXTPtr,
- size_t inTXTLen,
- uint64_t inDiscoverTimeUs,
- uint64_t inResolveTimeUs,
- SBRServiceInstance ** outInstance );
-static void _SBRServiceInstanceFree( SBRServiceInstance *inInstance );
-static OSStatus
- _SBRIPAddressCreate(
- const struct sockaddr * inSockAddr,
- uint64_t inResolveTimeUs,
- SBRIPAddress ** outIPAddress );
-static void _SBRIPAddressFree( SBRIPAddress *inIPAddress );
-
-#define ForgetSBIPAddressList( X ) ForgetCustom( X, _SBIPAddressFreeList )
-
-CF_CLASS_DEFINE( ServiceBrowser );
-
-static OSStatus
- ServiceBrowserCreate(
- dispatch_queue_t inQueue,
- uint32_t inInterfaceIndex,
- const char * inDomain,
- unsigned int inBrowseTimeSecs,
- Boolean inIncludeAWDL,
- ServiceBrowserRef * outBrowser )
-{
- OSStatus err;
- ServiceBrowserRef obj;
-
- CF_OBJECT_CREATE( ServiceBrowser, obj, err, exit );
-
- ReplaceDispatchQueue( &obj->queue, inQueue );
- obj->ifIndex = inInterfaceIndex;
- if( inDomain )
- {
- obj->domain = strdup( inDomain );
- require_action( obj->domain, exit, err = kNoMemoryErr );
- }
- obj->browseTimeSecs = inBrowseTimeSecs;
- obj->includeAWDL = inIncludeAWDL;
-
- *outBrowser = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- CFReleaseNullSafe( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserFinalize
-//===========================================================================================================================
-
-static void _ServiceBrowserFinalize( CFTypeRef inObj )
-{
- ServiceBrowserRef const me = (ServiceBrowserRef) inObj;
- StringListItem * serviceType;
-
- dispatch_forget( &me->queue );
- check( !me->connection );
- check( !me->domainsQuery );
- ForgetMem( &me->domain );
- while( ( serviceType = me->serviceTypeList ) != NULL )
- {
- me->serviceTypeList = serviceType->next;
- ForgetMem( &serviceType->str );
- free( serviceType );
- }
- check( !me->domainList );
- check( !me->stopTimer );
-}
-
-//===========================================================================================================================
-// ServiceBrowserStart
-//===========================================================================================================================
-
-static void _ServiceBrowserStart( void *inContext );
-
-static void ServiceBrowserStart( ServiceBrowserRef me )
-{
- CFRetain( me );
- dispatch_async_f( me->queue, me, _ServiceBrowserStart );
-}
-
-static void _ServiceBrowserStart( void *inContext )
-{
- OSStatus err;
- ServiceBrowserRef const me = (ServiceBrowserRef) inContext;
-
- err = DNSServiceCreateConnection( &me->connection );
- require_noerr( err, exit );
-
- err = DNSServiceSetDispatchQueue( me->connection, me->queue );
- require_noerr( err, exit );
-
- if( me->domain )
- {
- err = _ServiceBrowserAddDomain( me, me->domain );
- require_noerr( err, exit );
- }
- else
- {
- DNSServiceRef sdRef;
-
- sdRef = me->connection;
- err = DNSServiceQueryRecord( &sdRef, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly,
- "b._dns-sd._udp.local.", kDNSServiceType_PTR, kDNSServiceClass_IN, _ServiceBrowserDomainsQueryCallback, me );
- require_noerr( err, exit );
-
- me->domainsQuery = sdRef;
- }
-
- err = DispatchTimerCreate( dispatch_time_seconds( me->browseTimeSecs ), DISPATCH_TIME_FOREVER,
- 100 * kNanosecondsPerMillisecond, me->queue, _ServiceBrowserTimerHandler, NULL, me, &me->stopTimer );
- require_noerr( err, exit );
- dispatch_resume( me->stopTimer );
-
-exit:
- if( err ) _ServiceBrowserStop( me, err );
-}
-
-//===========================================================================================================================
-// ServiceBrowserAddServiceType
-//===========================================================================================================================
-
-static OSStatus ServiceBrowserAddServiceType( ServiceBrowserRef me, const char *inServiceType )
-{
- OSStatus err;
- StringListItem * item;
- StringListItem ** itemPtr;
- StringListItem * newItem = NULL;
-
- for( itemPtr = &me->serviceTypeList; ( item = *itemPtr ) != NULL; itemPtr = &item->next )
- {
- if( strcmp( item->str, inServiceType ) == 0 ) break;
- }
- if( !item )
- {
- newItem = (StringListItem *) calloc( 1, sizeof( *newItem ) );
- require_action( newItem, exit, err = kNoMemoryErr );
-
- newItem->str = strdup( inServiceType );
- require_action( newItem->str, exit, err = kNoMemoryErr );
-
- *itemPtr = newItem;
- newItem = NULL;
- }
- err = kNoErr;
-
-exit:
- FreeNullSafe( newItem );
- return( err );
-}
-
-//===========================================================================================================================
-// ServiceBrowserSetCallback
-//===========================================================================================================================
-
-static void ServiceBrowserSetCallback( ServiceBrowserRef me, ServiceBrowserCallback_f inCallback, void *inContext )
-{
- me->userCallback = inCallback;
- me->userContext = inContext;
-}
-
-//===========================================================================================================================
-// ServiceBrowserResultsRetain
-//===========================================================================================================================
-
-static void ServiceBrowserResultsRetain( ServiceBrowserResults *inResults )
-{
- ServiceBrowserResultsPrivate * const results = (ServiceBrowserResultsPrivate *) inResults;
-
- atomic_add_32( &results->refCount, 1 );
-}
-
-//===========================================================================================================================
-// ServiceBrowserResultsRelease
-//===========================================================================================================================
-
-static void ServiceBrowserResultsRelease( ServiceBrowserResults *inResults )
-{
- ServiceBrowserResultsPrivate * const results = (ServiceBrowserResultsPrivate *) inResults;
- SBRDomain * domain;
-
- if( atomic_add_and_fetch_32( &results->refCount, -1 ) == 0 )
- {
- while( ( domain = inResults->domainList ) != NULL )
- {
- inResults->domainList = domain->next;
- _SBRDomainFree( domain );
- }
- free( inResults );
- }
-}
-
-//===========================================================================================================================
-// _ServiceBrowserStop
-//===========================================================================================================================
-
-static void _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError )
-{
- OSStatus err;
- SBDomain * d;
- SBServiceType * t;
- SBServiceBrowse * b;
- SBServiceInstance * i;
-
- dispatch_source_forget( &me->stopTimer );
- DNSServiceForget( &me->domainsQuery );
- for( d = me->domainList; d; d = d->next )
- {
- DNSServiceForget( &d->servicesQuery );
- for( t = d->typeList; t; t = t->next )
- {
- for( b = t->browseList; b; b = b->next )
- {
- DNSServiceForget( &b->browse );
- for( i = b->instanceList; i; i = i->next )
- {
- DNSServiceForget( &i->resolve );
- DNSServiceForget( &i->getAddrInfo );
- }
- }
- }
- }
- DNSServiceForget( &me->connection );
-
- if( me->userCallback )
- {
- ServiceBrowserResults * results = NULL;
-
- err = _ServiceBrowserCreateResults( me, &results );
- if( !err ) err = inError;
-
- me->userCallback( results, err, me->userContext );
- me->userCallback = NULL;
- me->userContext = NULL;
- if( results ) ServiceBrowserResultsRelease( results );
- }
-
- while( ( d = me->domainList ) != NULL )
- {
- me->domainList = d->next;
- _SBDomainFree( d );
- }
- CFRelease( me );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserAddDomain
-//===========================================================================================================================
-
-static OSStatus _ServiceBrowserAddDomain( ServiceBrowserRef me, const char *inDomain )
-{
- OSStatus err;
- SBDomain * domain;
- SBDomain ** domainPtr;
- SBDomain * newDomain = NULL;
-
- for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
- {
- if( strcasecmp( domain->name, inDomain ) == 0 ) break;
- }
- require_action_quiet( !domain, exit, err = kDuplicateErr );
-
- err = _SBDomainCreate( inDomain, me, &newDomain );
- require_noerr_quiet( err, exit );
-
- if( me->serviceTypeList )
- {
- const StringListItem * item;
-
- for( item = me->serviceTypeList; item; item = item->next )
- {
- err = _ServiceBrowserAddServiceType( me, newDomain, item->str, me->ifIndex );
- if( err == kDuplicateErr ) err = kNoErr;
- require_noerr( err, exit );
- }
- }
- else
- {
- char * recordName;
- DNSServiceFlags flags;
- DNSServiceRef sdRef;
-
- ASPrintF( &recordName, "_services._dns-sd._udp.%s", newDomain->name );
- require_action( recordName, exit, err = kNoMemoryErr );
-
- flags = kDNSServiceFlagsShareConnection;
- if( ( me->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
-
- sdRef = newDomain->browser->connection;
- err = DNSServiceQueryRecord( &sdRef, flags, me->ifIndex, recordName, kDNSServiceType_PTR, kDNSServiceClass_IN,
- _ServiceBrowserServicesQueryCallback, newDomain );
- free( recordName );
- require_noerr( err, exit );
-
- newDomain->servicesQuery = sdRef;
- }
-
- *domainPtr = newDomain;
- newDomain = NULL;
- err = kNoErr;
-
-exit:
- if( newDomain ) _SBDomainFree( newDomain );
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserRemoveDomain
-//===========================================================================================================================
-
-static OSStatus _ServiceBrowserRemoveDomain( ServiceBrowserRef me, const char *inName )
-{
- OSStatus err;
- SBDomain * domain;
- SBDomain ** domainPtr;
-
- for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
- {
- if( strcasecmp( domain->name, inName ) == 0 ) break;
- }
-
- if( domain )
- {
- *domainPtr = domain->next;
- _SBDomainFree( domain );
- err = kNoErr;
- }
- else
- {
- err = kNotFoundErr;
- }
-
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserTimerHandler
-//===========================================================================================================================
-
-static void _ServiceBrowserTimerHandler( void *inContext )
-{
- ServiceBrowserRef const me = (ServiceBrowserRef) inContext;
-
- _ServiceBrowserStop( me, kNoErr );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserDomainsQueryCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _ServiceBrowserDomainsQueryCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- ServiceBrowserRef const me = (ServiceBrowserRef) inContext;
- OSStatus err;
- char domainStr[ kDNSServiceMaxDomainName ];
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inFullName );
- Unused( inType );
- Unused( inClass );
- Unused( inTTL );
-
- require_noerr( inError, exit );
-
- err = DomainNameToString( inRDataPtr, ( (const uint8_t *) inRDataPtr ) + inRDataLen, domainStr, NULL );
- require_noerr( err, exit );
-
- if( inFlags & kDNSServiceFlagsAdd )
- {
- err = _ServiceBrowserAddDomain( me, domainStr );
- if( err == kDuplicateErr ) err = kNoErr;
- require_noerr( err, exit );
- }
- else
- {
- err = _ServiceBrowserRemoveDomain( me, domainStr );
- if( err == kNotFoundErr ) err = kNoErr;
- require_noerr( err, exit );
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _ServiceBrowserServicesQueryCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _ServiceBrowserServicesQueryCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- uint16_t inType,
- uint16_t inClass,
- uint16_t inRDataLen,
- const void * inRDataPtr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- SBDomain * const domain = (SBDomain *) inContext;
- ServiceBrowserRef const me = domain->browser;
- const uint8_t * src;
- const uint8_t * end;
- uint8_t * dst;
- int i;
- uint8_t serviceType[ 2 * ( 1 + kDomainLabelLengthMax ) + 1 ];
- char serviceTypeStr[ kDNSServiceMaxDomainName ];
-
- Unused( inSDRef );
- Unused( inFullName );
- Unused( inTTL );
- Unused( inType );
- Unused( inClass );
-
- require_noerr( inError, exit );
-
- check( inType == kDNSServiceType_PTR );
- check( inClass == kDNSServiceClass_IN );
-
- // The first two labels of the domain name in the RDATA describe a service type.
- // See <https://tools.ietf.org/html/rfc6763#section-9>.
-
- src = (const uint8_t *) inRDataPtr;
- end = src + inRDataLen;
- dst = serviceType;
- for( i = 0; i < 2; ++i )
- {
- size_t labelLen;
-
- require_action_quiet( ( end - src ) > 0, exit, err = kUnderrunErr );
-
- labelLen = *src;
- require_action_quiet( ( labelLen > 0 ) && ( labelLen <= kDomainLabelLengthMax ), exit, err = kMalformedErr );
- require_action_quiet( ( (size_t)( end - src ) ) >= ( 1 + labelLen ), exit, err = kUnderrunErr );
-
- memcpy( dst, src, 1 + labelLen );
- src += 1 + labelLen;
- dst += 1 + labelLen;
- }
- *dst = 0;
-
- err = DomainNameToString( serviceType, NULL, serviceTypeStr, NULL );
- require_noerr( err, exit );
-
- if( inFlags & kDNSServiceFlagsAdd )
- {
- err = _ServiceBrowserAddServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
- if( err == kDuplicateErr ) err = kNoErr;
- require_noerr( err, exit );
- }
- else
- {
- err = _ServiceBrowserRemoveServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
- if( err == kNotFoundErr ) err = kNoErr;
- require_noerr( err, exit );
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _ServiceBrowserBrowseCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _ServiceBrowserBrowseCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inName,
- const char * inRegType,
- const char * inDomain,
- void * inContext )
-{
- OSStatus err;
- const uint64_t nowTicks = UpTicks();
- SBServiceBrowse * const browse = (SBServiceBrowse *) inContext;
- ServiceBrowserRef const me = (ServiceBrowserRef) browse->browser;
-
- Unused( inSDRef );
-
- require_noerr( inError, exit );
-
- if( inFlags & kDNSServiceFlagsAdd )
- {
- err = _ServiceBrowserAddServiceInstance( me, browse, inInterfaceIndex, inName, inRegType, inDomain,
- UpTicksToMicroseconds( nowTicks - browse->startTicks ) );
- if( err == kDuplicateErr ) err = kNoErr;
- require_noerr( err, exit );
- }
- else
- {
- err = _ServiceBrowserRemoveServiceInstance( me, browse, inName, inInterfaceIndex );
- if( err == kNotFoundErr ) err = kNoErr;
- require_noerr( err, exit );
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _ServiceBrowserResolveCallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _ServiceBrowserResolveCallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inFullName,
- const char * inHostname,
- uint16_t inPort,
- uint16_t inTXTLen,
- const unsigned char * inTXTPtr,
- void * inContext )
-{
- OSStatus err;
- const uint64_t nowTicks = UpTicks();
- SBServiceInstance * const instance = (SBServiceInstance *) inContext;
- ServiceBrowserRef const me = (ServiceBrowserRef) instance->browser;
-
- Unused( inSDRef );
- Unused( inFlags );
- Unused( inInterfaceIndex );
- Unused( inFullName );
-
- require_noerr( inError, exit );
-
- if( !MemEqual( instance->txtPtr, instance->txtLen, inTXTPtr, inTXTLen ) )
- {
- FreeNullSafe( instance->txtPtr );
- instance->txtPtr = memdup( inTXTPtr, inTXTLen );
- require_action( instance->txtPtr, exit, err = kNoMemoryErr );
-
- instance->txtLen = inTXTLen;
- }
-
- instance->port = ntohs( inPort );
-
- if( !instance->hostname || ( strcasecmp( instance->hostname, inHostname ) != 0 ) )
- {
- DNSServiceRef sdRef;
-
- if( !instance->hostname ) instance->resolveTimeUs = UpTicksToMicroseconds( nowTicks - instance->resolveStartTicks );
-
- err = ReplaceString( &instance->hostname, NULL, inHostname, kSizeCString );
- require_noerr( err, exit );
-
- DNSServiceForget( &instance->getAddrInfo );
- ForgetSBIPAddressList( &instance->ipaddrList );
-
- sdRef = me->connection;
- instance->gaiStartTicks = UpTicks();
- err = DNSServiceGetAddrInfo( &sdRef, kDNSServiceFlagsShareConnection, instance->ifIndex,
- kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, instance->hostname, _ServiceBrowserGAICallback, instance );
- require_noerr( err, exit );
-
- instance->getAddrInfo = sdRef;
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _ServiceBrowserGAICallback
-//===========================================================================================================================
-
-static void DNSSD_API
- _ServiceBrowserGAICallback(
- DNSServiceRef inSDRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inError,
- const char * inHostname,
- const struct sockaddr * inSockAddr,
- uint32_t inTTL,
- void * inContext )
-{
- OSStatus err;
- const uint64_t nowTicks = UpTicks();
- SBServiceInstance * const instance = (SBServiceInstance *) inContext;
- ServiceBrowserRef const me = (ServiceBrowserRef) instance->browser;
-
- Unused( inSDRef );
- Unused( inInterfaceIndex );
- Unused( inHostname );
- Unused( inTTL );
-
- require_noerr( inError, exit );
-
- if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
- {
- dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
- goto exit;
- }
-
- if( inFlags & kDNSServiceFlagsAdd )
- {
- err = _ServiceBrowserAddIPAddress( me, instance, inSockAddr,
- UpTicksToMicroseconds( nowTicks - instance->gaiStartTicks ) );
- if( err == kDuplicateErr ) err = kNoErr;
- require_noerr( err, exit );
- }
- else
- {
- err = _ServiceBrowserRemoveIPAddress( me, instance, inSockAddr );
- if( err == kNotFoundErr ) err = kNoErr;
- require_noerr( err, exit );
- }
-
-exit:
- return;
-}
-
-//===========================================================================================================================
-// _ServiceBrowserAddServiceType
-//===========================================================================================================================
-
-static OSStatus
- _ServiceBrowserAddServiceType(
- ServiceBrowserRef me,
- SBDomain * inDomain,
- const char * inName,
- uint32_t inIfIndex )
-{
- OSStatus err;
- SBServiceType * type;
- SBServiceType ** typePtr;
- SBServiceType * newType = NULL;
- SBServiceBrowse * browse;
- SBServiceBrowse ** browsePtr;
- SBServiceBrowse * newBrowse = NULL;
- DNSServiceRef sdRef;
- DNSServiceFlags flags;
-
- for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
- {
- if( strcasecmp( type->name, inName ) == 0 ) break;
- }
- if( !type )
- {
- err = _SBServiceTypeCreate( inName, &newType );
- require_noerr_quiet( err, exit );
-
- type = newType;
- }
-
- for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
- {
- if( browse->ifIndex == inIfIndex ) break;
- }
- require_action_quiet( !browse, exit, err = kDuplicateErr );
-
- err = _SBServiceBrowseCreate( inIfIndex, me, &newBrowse );
- require_noerr_quiet( err, exit );
-
- flags = kDNSServiceFlagsShareConnection;
- if( ( newBrowse->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
-
- sdRef = me->connection;
- newBrowse->startTicks = UpTicks();
- err = DNSServiceBrowse( &sdRef, flags, newBrowse->ifIndex, type->name, inDomain->name, _ServiceBrowserBrowseCallback,
- newBrowse );
- require_noerr( err, exit );
-
- newBrowse->browse = sdRef;
- *browsePtr = newBrowse;
- newBrowse = NULL;
-
- if( newType )
- {
- *typePtr = newType;
- newType = NULL;
- }
-
-exit:
- if( newBrowse ) _SBServiceBrowseFree( newBrowse );
- if( newType ) _SBServiceTypeFree( newType );
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserRemoveServiceType
-//===========================================================================================================================
-
-static OSStatus
- _ServiceBrowserRemoveServiceType(
- ServiceBrowserRef me,
- SBDomain * inDomain,
- const char * inName,
- uint32_t inIfIndex )
-{
- OSStatus err;
- SBServiceType * type;
- SBServiceType ** typePtr;
- SBServiceBrowse * browse;
- SBServiceBrowse ** browsePtr;
-
- Unused( me );
-
- for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
- {
- if( strcasecmp( type->name, inName ) == 0 ) break;
- }
- require_action_quiet( type, exit, err = kNotFoundErr );
-
- for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
- {
- if( browse->ifIndex == inIfIndex ) break;
- }
- require_action_quiet( browse, exit, err = kNotFoundErr );
-
- *browsePtr = browse->next;
- _SBServiceBrowseFree( browse );
- if( !type->browseList )
- {
- *typePtr = type->next;
- _SBServiceTypeFree( type );
- }
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserAddServiceInstance
-//===========================================================================================================================
-
-static OSStatus
- _ServiceBrowserAddServiceInstance(
- ServiceBrowserRef me,
- SBServiceBrowse * inBrowse,
- uint32_t inIfIndex,
- const char * inName,
- const char * inRegType,
- const char * inDomain,
- uint64_t inDiscoverTimeUs )
-{
- OSStatus err;
- DNSServiceRef sdRef;
- SBServiceInstance * instance;
- SBServiceInstance ** instancePtr;
- SBServiceInstance * newInstance = NULL;
-
- for( instancePtr = &inBrowse->instanceList; ( instance = *instancePtr ) != NULL; instancePtr = &instance->next )
- {
- if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
- }
- require_action_quiet( !instance, exit, err = kDuplicateErr );
-
- err = _SBServiceInstanceCreate( inName, inIfIndex, inDiscoverTimeUs, me, &newInstance );
- require_noerr_quiet( err, exit );
-
- sdRef = me->connection;
- newInstance->resolveStartTicks = UpTicks();
- err = DNSServiceResolve( &sdRef, kDNSServiceFlagsShareConnection, newInstance->ifIndex, inName, inRegType, inDomain,
- _ServiceBrowserResolveCallback, newInstance );
- require_noerr( err, exit );
-
- newInstance->resolve = sdRef;
- *instancePtr = newInstance;
- newInstance = NULL;
-
-exit:
- if( newInstance ) _SBServiceInstanceFree( newInstance );
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserRemoveServiceInstance
-//===========================================================================================================================
-
-static OSStatus
- _ServiceBrowserRemoveServiceInstance(
- ServiceBrowserRef me,
- SBServiceBrowse * inBrowse,
- const char * inName,
- uint32_t inIfIndex )
-{
- OSStatus err;
- SBServiceInstance * instance;
- SBServiceInstance ** ptr;
-
- Unused( me );
-
- for( ptr = &inBrowse->instanceList; ( instance = *ptr ) != NULL; ptr = &instance->next )
- {
- if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
- }
- require_action_quiet( instance, exit, err = kNotFoundErr );
-
- *ptr = instance->next;
- _SBServiceInstanceFree( instance );
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserAddIPAddress
-//===========================================================================================================================
-
-static OSStatus
- _ServiceBrowserAddIPAddress(
- ServiceBrowserRef me,
- SBServiceInstance * inInstance,
- const struct sockaddr * inSockAddr,
- uint64_t inResolveTimeUs )
-{
- OSStatus err;
- SBIPAddress * ipaddr;
- SBIPAddress ** ipaddrPtr;
- SBIPAddress * newIPAddr = NULL;
-
- Unused( me );
-
- if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
- {
- dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
- err = kTypeErr;
- goto exit;
- }
-
- for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
- {
- if( SockAddrCompareAddr( &ipaddr->sip, inSockAddr ) == 0 ) break;
- }
- require_action_quiet( !ipaddr, exit, err = kDuplicateErr );
-
- err = _SBIPAddressCreate( inSockAddr, inResolveTimeUs, &newIPAddr );
- require_noerr_quiet( err, exit );
-
- *ipaddrPtr = newIPAddr;
- newIPAddr = NULL;
- err = kNoErr;
-
-exit:
- if( newIPAddr ) _SBIPAddressFree( newIPAddr );
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserRemoveIPAddress
-//===========================================================================================================================
-
-static OSStatus
- _ServiceBrowserRemoveIPAddress(
- ServiceBrowserRef me,
- SBServiceInstance * inInstance,
- const struct sockaddr * inSockAddr )
-{
- OSStatus err;
- SBIPAddress * ipaddr;
- SBIPAddress ** ipaddrPtr;
-
- Unused( me );
-
- for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
- {
- if( SockAddrCompareAddr( &ipaddr->sip.sa, inSockAddr ) == 0 ) break;
- }
- require_action_quiet( ipaddr, exit, err = kNotFoundErr );
-
- *ipaddrPtr = ipaddr->next;
- _SBIPAddressFree( ipaddr );
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _ServiceBrowserCreateResults
-//===========================================================================================================================
-
-static OSStatus _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults )
-{
- OSStatus err;
- SBDomain * d;
- SBServiceType * t;
- SBServiceBrowse * b;
- SBServiceInstance * i;
- SBIPAddress * a;
- ServiceBrowserResultsPrivate * results;
- SBRDomain ** domainPtr;
-
- results = (ServiceBrowserResultsPrivate *) calloc( 1, sizeof( *results ) );
- require_action( results, exit, err = kNoMemoryErr );
-
- results->refCount = 1;
-
- domainPtr = &results->domainList;
- for( d = me->domainList; d; d = d->next )
- {
- SBRDomain * domain;
- SBRServiceType ** typePtr;
-
- err = _SBRDomainCreate( d->name, &domain );
- require_noerr_quiet( err, exit );
- *domainPtr = domain;
- domainPtr = &domain->next;
-
- typePtr = &domain->typeList;
- for( t = d->typeList; t; t = t->next )
- {
- SBRServiceType * type;
- SBRServiceInstance ** instancePtr;
-
- err = _SBRServiceTypeCreate( t->name, &type );
- require_noerr_quiet( err, exit );
- *typePtr = type;
- typePtr = &type->next;
-
- instancePtr = &type->instanceList;
- for( b = t->browseList; b; b = b->next )
- {
- for( i = b->instanceList; i; i = i->next )
- {
- SBRServiceInstance * instance;
- SBRIPAddress ** ipaddrPtr;
-
- err = _SBRServiceInstanceCreate( i->name, i->ifIndex, i->hostname, i->port, i->txtPtr, i->txtLen,
- i->discoverTimeUs, i->resolveTimeUs, &instance );
- require_noerr_quiet( err, exit );
- *instancePtr = instance;
- instancePtr = &instance->next;
-
- ipaddrPtr = &instance->ipaddrList;
- for( a = i->ipaddrList; a; a = a->next )
- {
- SBRIPAddress * ipaddr;
-
- err = _SBRIPAddressCreate( &a->sip.sa, a->resolveTimeUs, &ipaddr );
- require_noerr_quiet( err, exit );
-
- *ipaddrPtr = ipaddr;
- ipaddrPtr = &ipaddr->next;
- }
- }
- }
- }
- }
-
- *outResults = (ServiceBrowserResults *) results;
- results = NULL;
- err = kNoErr;
-
-exit:
- if( results ) ServiceBrowserResultsRelease( (ServiceBrowserResults *) results );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBDomainCreate
-//===========================================================================================================================
-
-static OSStatus _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain )
-{
- OSStatus err;
- SBDomain * obj;
-
- obj = (SBDomain *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- obj->browser = inBrowser;
-
- *outDomain = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _SBDomainFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBDomainFree
-//===========================================================================================================================
-
-static void _SBDomainFree( SBDomain *inDomain )
-{
- SBServiceType * type;
-
- ForgetMem( &inDomain->name );
- DNSServiceForget( &inDomain->servicesQuery );
- while( ( type = inDomain->typeList ) != NULL )
- {
- inDomain->typeList = type->next;
- _SBServiceTypeFree( type );
- }
- free( inDomain );
-}
-
-//===========================================================================================================================
-// _SBServiceTypeCreate
-//===========================================================================================================================
-
-static OSStatus _SBServiceTypeCreate( const char *inName, SBServiceType **outType )
-{
- OSStatus err;
- SBServiceType * obj;
-
- obj = (SBServiceType *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- *outType = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _SBServiceTypeFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBServiceTypeFree
-//===========================================================================================================================
-
-static void _SBServiceTypeFree( SBServiceType *inType )
-{
- SBServiceBrowse * browse;
-
- ForgetMem( &inType->name );
- while( ( browse = inType->browseList ) != NULL )
- {
- inType->browseList = browse->next;
- _SBServiceBrowseFree( browse );
- }
- free( inType );
-}
-
-//===========================================================================================================================
-// _SBServiceBrowseCreate
-//===========================================================================================================================
-
-static OSStatus _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse )
-{
- OSStatus err;
- SBServiceBrowse * obj;
-
- obj = (SBServiceBrowse *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->ifIndex = inIfIndex;
- obj->browser = inBrowser;
- *outBrowse = obj;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _SBServiceBrowseFree
-//===========================================================================================================================
-
-static void _SBServiceBrowseFree( SBServiceBrowse *inBrowse )
-{
- SBServiceInstance * instance;
-
- DNSServiceForget( &inBrowse->browse );
- while( ( instance = inBrowse->instanceList ) != NULL )
- {
- inBrowse->instanceList = instance->next;
- _SBServiceInstanceFree( instance );
- }
- free( inBrowse );
-}
-
-//===========================================================================================================================
-// _SBServiceInstanceCreate
-//===========================================================================================================================
-
-static OSStatus
- _SBServiceInstanceCreate(
- const char * inName,
- uint32_t inIfIndex,
- uint64_t inDiscoverTimeUs,
- ServiceBrowserRef inBrowser,
- SBServiceInstance ** outInstance )
-{
- OSStatus err;
- SBServiceInstance * obj;
-
- obj = (SBServiceInstance *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- obj->ifIndex = inIfIndex;
- obj->discoverTimeUs = inDiscoverTimeUs;
- obj->browser = inBrowser;
-
- *outInstance = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _SBServiceInstanceFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBServiceInstanceFree
-//===========================================================================================================================
-
-static void _SBServiceInstanceFree( SBServiceInstance *inInstance )
-{
- ForgetMem( &inInstance->name );
- DNSServiceForget( &inInstance->resolve );
- ForgetMem( &inInstance->hostname );
- ForgetMem( &inInstance->txtPtr );
- DNSServiceForget( &inInstance->getAddrInfo );
- ForgetSBIPAddressList( &inInstance->ipaddrList );
- free( inInstance );
-}
-
-//===========================================================================================================================
-// _SBIPAddressCreate
-//===========================================================================================================================
-
-static OSStatus _SBIPAddressCreate( const struct sockaddr *inSockAddr, uint64_t inResolveTimeUs, SBIPAddress **outIPAddress )
-{
- OSStatus err;
- SBIPAddress * obj;
-
- obj = (SBIPAddress *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- SockAddrCopy( inSockAddr, &obj->sip );
- obj->resolveTimeUs = inResolveTimeUs;
-
- *outIPAddress = obj;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _SBIPAddressFree
-//===========================================================================================================================
-
-static void _SBIPAddressFree( SBIPAddress *inIPAddress )
-{
- free( inIPAddress );
-}
-
-//===========================================================================================================================
-// _SBIPAddressFreeList
-//===========================================================================================================================
-
-static void _SBIPAddressFreeList( SBIPAddress *inList )
-{
- SBIPAddress * ipaddr;
-
- while( ( ipaddr = inList ) != NULL )
- {
- inList = ipaddr->next;
- _SBIPAddressFree( ipaddr );
- }
-}
-
-//===========================================================================================================================
-// _SBRDomainCreate
-//===========================================================================================================================
-
-static OSStatus _SBRDomainCreate( const char *inName, SBRDomain **outDomain )
-{
- OSStatus err;
- SBRDomain * obj;
-
- obj = (SBRDomain *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- *outDomain = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _SBRDomainFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBRDomainFree
-//===========================================================================================================================
-
-static void _SBRDomainFree( SBRDomain *inDomain )
-{
- SBRServiceType * type;
-
- ForgetMem( &inDomain->name );
- while( ( type = inDomain->typeList ) != NULL )
- {
- inDomain->typeList = type->next;
- _SBRServiceTypeFree( type );
- }
- free( inDomain );
-}
-
-//===========================================================================================================================
-// _SBRServiceTypeCreate
-//===========================================================================================================================
-
-static OSStatus _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType )
-{
- OSStatus err;
- SBRServiceType * obj;
-
- obj = (SBRServiceType *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- *outType = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _SBRServiceTypeFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBRServiceTypeFree
-//===========================================================================================================================
-
-static void _SBRServiceTypeFree( SBRServiceType *inType )
-{
- SBRServiceInstance * instance;
-
- ForgetMem( &inType->name );
- while( ( instance = inType->instanceList ) != NULL )
- {
- inType->instanceList = instance->next;
- _SBRServiceInstanceFree( instance );
- }
- free( inType );
-}
-
-//===========================================================================================================================
-// _SBRServiceInstanceCreate
-//===========================================================================================================================
-
-static OSStatus
- _SBRServiceInstanceCreate(
- const char * inName,
- uint32_t inInterfaceIndex,
- const char * inHostname,
- uint16_t inPort,
- const uint8_t * inTXTPtr,
- size_t inTXTLen,
- uint64_t inDiscoverTimeUs,
- uint64_t inResolveTimeUs,
- SBRServiceInstance ** outInstance )
-{
- OSStatus err;
- SBRServiceInstance * obj;
-
- obj = (SBRServiceInstance *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- obj->name = strdup( inName );
- require_action( obj->name, exit, err = kNoMemoryErr );
-
- if( inHostname )
- {
- obj->hostname = strdup( inHostname );
- require_action( obj->hostname, exit, err = kNoMemoryErr );
- }
- if( inTXTLen > 0 )
- {
- obj->txtPtr = (uint8_t *) memdup( inTXTPtr, inTXTLen );
- require_action( obj->txtPtr, exit, err = kNoMemoryErr );
- obj->txtLen = inTXTLen;
- }
- obj->discoverTimeUs = inDiscoverTimeUs;
- obj->resolveTimeUs = inResolveTimeUs;
- obj->ifIndex = inInterfaceIndex;
- obj->port = inPort;
-
- *outInstance = obj;
- obj = NULL;
- err = kNoErr;
-
-exit:
- if( obj ) _SBRServiceInstanceFree( obj );
- return( err );
-}
-
-//===========================================================================================================================
-// _SBRServiceInstanceFree
-//===========================================================================================================================
-
-static void _SBRServiceInstanceFree( SBRServiceInstance *inInstance )
-{
- SBRIPAddress * ipaddr;
-
- ForgetMem( &inInstance->name );
- ForgetMem( &inInstance->hostname );
- ForgetMem( &inInstance->txtPtr );
- while( ( ipaddr = inInstance->ipaddrList ) != NULL )
- {
- inInstance->ipaddrList = ipaddr->next;
- _SBRIPAddressFree( ipaddr );
- }
- free( inInstance );
-}
-
-//===========================================================================================================================
-// _SBRIPAddressCreate
-//===========================================================================================================================
-
-static OSStatus
- _SBRIPAddressCreate(
- const struct sockaddr * inSockAddr,
- uint64_t inResolveTimeUs,
- SBRIPAddress ** outIPAddress )
-{
- OSStatus err;
- SBRIPAddress * obj;
-
- obj = (SBRIPAddress *) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = kNoMemoryErr );
-
- SockAddrCopy( inSockAddr, &obj->sip );
- obj->resolveTimeUs = inResolveTimeUs;
-
- *outIPAddress = obj;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// _SBRIPAddressFree
-//===========================================================================================================================
-
-static void _SBRIPAddressFree( SBRIPAddress *inIPAddress )
-{
- free( inIPAddress );
-}
-
-//===========================================================================================================================
-// SocketWriteAll
-//
-// Note: This was copied from CoreUtils because the SocketWriteAll function is currently not exported in the framework.
-//===========================================================================================================================
-
-OSStatus SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs )
-{
- OSStatus err;
- const uint8_t * src;
- const uint8_t * end;
- fd_set writeSet;
- struct timeval timeout;
- ssize_t n;
-
- FD_ZERO( &writeSet );
- src = (const uint8_t *) inData;
- end = src + inSize;
- while( src < end )
- {
- FD_SET( inSock, &writeSet );
- timeout.tv_sec = inTimeoutSecs;
- timeout.tv_usec = 0;
- n = select( (int)( inSock + 1 ), NULL, &writeSet, NULL, &timeout );
- if( n == 0 ) { err = kTimeoutErr; goto exit; }
- err = map_socket_value_errno( inSock, n > 0, n );
- require_noerr( err, exit );
-
- n = send( inSock, (char *) src, (size_t)( end - src ), 0 );
- err = map_socket_value_errno( inSock, n >= 0, n );
- if( err == EINTR ) continue;
- require_noerr( err, exit );
-
- src += n;
- }
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ParseIPv4Address
-//
-// Warning: "inBuffer" may be modified even in error cases.
-//
-// Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-static OSStatus ParseIPv4Address( const char *inStr, uint8_t inBuffer[ 4 ], const char **outStr )
-{
- OSStatus err;
- uint8_t * dst;
- int segments;
- int sawDigit;
- int c;
- int v;
-
- check( inBuffer );
- check( outStr );
-
- dst = inBuffer;
- *dst = 0;
- sawDigit = 0;
- segments = 0;
- for( ; ( c = *inStr ) != '\0'; ++inStr )
- {
- if( isdigit_safe( c ) )
- {
- v = ( *dst * 10 ) + ( c - '0' );
- require_action_quiet( v <= 255, exit, err = kRangeErr );
- *dst = (uint8_t) v;
- if( !sawDigit )
- {
- ++segments;
- require_action_quiet( segments <= 4, exit, err = kOverrunErr );
- sawDigit = 1;
- }
- }
- else if( ( c == '.' ) && sawDigit )
- {
- require_action_quiet( segments < 4, exit, err = kMalformedErr );
- *++dst = 0;
- sawDigit = 0;
- }
- else
- {
- break;
- }
- }
- require_action_quiet( segments == 4, exit, err = kUnderrunErr );
-
- *outStr = inStr;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// StringToIPv4Address
-//
-// Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-OSStatus
- StringToIPv4Address(
- const char * inStr,
- StringToIPAddressFlags inFlags,
- uint32_t * outIP,
- int * outPort,
- uint32_t * outSubnet,
- uint32_t * outRouter,
- const char ** outStr )
-{
- OSStatus err;
- uint8_t buf[ 4 ];
- int c;
- uint32_t ip;
- int hasPort;
- int port;
- int hasPrefix;
- int prefix;
- uint32_t subnetMask;
- uint32_t router;
-
- require_action( inStr, exit, err = kParamErr );
-
- // Parse the address-only part of the address (e.g. "1.2.3.4").
-
- err = ParseIPv4Address( inStr, buf, &inStr );
- require_noerr_quiet( err, exit );
- ip = (uint32_t)( ( buf[ 0 ] << 24 ) | ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ] );
- c = *inStr;
-
- // Parse the port (if any).
-
- hasPort = 0;
- port = 0;
- if( c == ':' )
- {
- require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
- while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
- require_action_quiet( port <= 65535, exit, err = kRangeErr );
- hasPort = 1;
- }
-
- // Parse the prefix length (if any).
-
- hasPrefix = 0;
- prefix = 0;
- subnetMask = 0;
- router = 0;
- if( c == '/' )
- {
- require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
- while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
- require_action_quiet( ( prefix >= 0 ) && ( prefix <= 32 ), exit, err = kRangeErr );
- hasPrefix = 1;
-
- subnetMask = ( prefix > 0 ) ? ( UINT32_C( 0xFFFFFFFF ) << ( 32 - prefix ) ) : 0;
- router = ( ip & subnetMask ) | 1;
- }
-
- // Return the results. Only fill in port/prefix/router results if the info was found to allow for defaults.
-
- if( outIP ) *outIP = ip;
- if( outPort && hasPort ) *outPort = port;
- if( outSubnet && hasPrefix ) *outSubnet = subnetMask;
- if( outRouter && hasPrefix ) *outRouter = router;
- if( outStr ) *outStr = inStr;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ParseIPv6Address
-//
-// Note: Parsed according to the rules specified in RFC 3513.
-// Warning: "inBuffer" may be modified even in error cases.
-//
-// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-static OSStatus ParseIPv6Address( const char *inStr, int inAllowV4Mapped, uint8_t inBuffer[ 16 ], const char **outStr )
-{
- // Table to map uppercase hex characters - '0' to their numeric values.
- // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
- static const uint8_t kASCIItoHexTable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
- OSStatus err;
- const char * ptr;
- uint8_t * dst;
- uint8_t * lim;
- uint8_t * colonPtr;
- int c;
- int sawDigit;
- unsigned int v;
- int i;
- int n;
-
- // Pre-zero the address to simplify handling of compressed addresses (e.g. "::1").
-
- for( i = 0; i < 16; ++i ) inBuffer[ i ] = 0;
-
- // Special case leading :: (e.g. "::1") to simplify processing later.
-
- if( *inStr == ':' )
- {
- ++inStr;
- require_action_quiet( *inStr == ':', exit, err = kMalformedErr );
- }
-
- // Parse the address.
-
- ptr = inStr;
- dst = inBuffer;
- lim = dst + 16;
- colonPtr = NULL;
- sawDigit = 0;
- v = 0;
- while( ( ( c = *inStr++ ) != '\0' ) && ( c != '%' ) && ( c != '/' ) && ( c != ']' ) )
- {
- if( ( c >= 'a' ) && ( c <= 'f' ) ) c -= ( 'a' - 'A' );
- if( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) )
- {
- c -= '0';
- check( c < (int) countof( kASCIItoHexTable ) );
- v = ( v << 4 ) | kASCIItoHexTable[ c ];
- require_action_quiet( v <= 0xFFFF, exit, err = kRangeErr );
- sawDigit = 1;
- continue;
- }
- if( c == ':' )
- {
- ptr = inStr;
- if( !sawDigit )
- {
- require_action_quiet( !colonPtr, exit, err = kMalformedErr );
- colonPtr = dst;
- continue;
- }
- require_action_quiet( *inStr != '\0', exit, err = kUnderrunErr );
- require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
- *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
- *dst++ = (uint8_t)( v & 0xFF );
- sawDigit = 0;
- v = 0;
- continue;
- }
-
- // Handle IPv4-mapped/compatible addresses (e.g. ::FFFF:1.2.3.4).
-
- if( inAllowV4Mapped && ( c == '.' ) && ( ( dst + 4 ) <= lim ) )
- {
- err = ParseIPv4Address( ptr, dst, &inStr );
- require_noerr_quiet( err, exit );
- dst += 4;
- sawDigit = 0;
- ++inStr; // Increment because the code below expects the end to be at "inStr - 1".
- }
- break;
- }
- if( sawDigit )
- {
- require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
- *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
- *dst++ = (uint8_t)( v & 0xFF );
- }
- check( dst <= lim );
- if( colonPtr )
- {
- require_action_quiet( dst < lim, exit, err = kOverrunErr );
- n = (int)( dst - colonPtr );
- for( i = 1; i <= n; ++i )
- {
- lim[ -i ] = colonPtr[ n - i ];
- colonPtr[ n - i ] = 0;
- }
- dst = lim;
- }
- require_action_quiet( dst == lim, exit, err = kUnderrunErr );
-
- *outStr = inStr - 1;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ParseIPv6Scope
-//
-// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-static OSStatus ParseIPv6Scope( const char *inStr, uint32_t *outScope, const char **outStr )
-{
-#if( TARGET_OS_POSIX )
- OSStatus err;
- char scopeStr[ 64 ];
- char * dst;
- char * lim;
- int c;
- uint32_t scope;
- const char * ptr;
-
- // Copy into a local NULL-terminated string since that is what if_nametoindex expects.
-
- dst = scopeStr;
- lim = dst + ( countof( scopeStr ) - 1 );
- while( ( ( c = *inStr ) != '\0' ) && ( c != ':' ) && ( c != '/' ) && ( c != ']' ) && ( dst < lim ) )
- {
- *dst++ = *inStr++;
- }
- *dst = '\0';
- check( dst <= lim );
-
- // First try to map as a name and if that fails, treat it as a numeric scope.
-
- scope = if_nametoindex( scopeStr );
- if( scope == 0 )
- {
- for( ptr = scopeStr; ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr )
- {
- scope = ( scope * 10 ) + ( ( (uint8_t) c ) - '0' );
- }
- require_action_quiet( c == '\0', exit, err = kMalformedErr );
- require_action_quiet( ( ptr != scopeStr ) && ( ( (int)( ptr - scopeStr ) ) <= 10 ), exit, err = kMalformedErr );
- }
-
- *outScope = scope;
- *outStr = inStr;
- err = kNoErr;
-
-exit:
- return( err );
-#else
- OSStatus err;
- uint32_t scope;
- const char * start;
- int c;
-
- scope = 0;
- for( start = inStr; ( ( c = *inStr ) >= '0' ) && ( c <= '9' ); ++inStr )
- {
- scope = ( scope * 10 ) + ( c - '0' );
- }
- require_action_quiet( ( inStr != start ) && ( ( (int)( inStr - start ) ) <= 10 ), exit, err = kMalformedErr );
-
- *outScope = scope;
- *outStr = inStr;
- err = kNoErr;
-
-exit:
- return( err );
-#endif
-}
-
-//===========================================================================================================================
-// StringToIPv6Address
-//
-// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-OSStatus
- StringToIPv6Address(
- const char * inStr,
- StringToIPAddressFlags inFlags,
- uint8_t outIPv6[ 16 ],
- uint32_t * outScope,
- int * outPort,
- int * outPrefix,
- const char ** outStr )
-{
- OSStatus err;
- uint8_t ipv6[ 16 ];
- int c;
- int hasScope;
- uint32_t scope;
- int hasPort;
- int port;
- int hasPrefix;
- int prefix;
- int hasBracket;
- int i;
-
- require_action( inStr, exit, err = kParamErr );
-
- if( *inStr == '[' ) ++inStr; // Skip a leading bracket for []-wrapped addresses (e.g. "[::1]:80").
-
- // Parse the address-only part of the address (e.g. "1::1").
-
- err = ParseIPv6Address( inStr, !( inFlags & kStringToIPAddressFlagsNoIPv4Mapped ), ipv6, &inStr );
- require_noerr_quiet( err, exit );
- c = *inStr;
-
- // Parse the scope, port, or prefix length.
-
- hasScope = 0;
- scope = 0;
- hasPort = 0;
- port = 0;
- hasPrefix = 0;
- prefix = 0;
- hasBracket = 0;
- for( ;; )
- {
- if( c == '%' ) // Scope (e.g. "%en0" or "%5")
- {
- require_action_quiet( !hasScope, exit, err = kMalformedErr );
- require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoScope ), exit, err = kUnexpectedErr );
- ++inStr;
- err = ParseIPv6Scope( inStr, &scope, &inStr );
- require_noerr_quiet( err, exit );
- hasScope = 1;
- c = *inStr;
- }
- else if( c == ':' ) // Port (e.g. ":80")
- {
- require_action_quiet( !hasPort, exit, err = kMalformedErr );
- require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
- while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
- require_action_quiet( port <= 65535, exit, err = kRangeErr );
- hasPort = 1;
- }
- else if( c == '/' ) // Prefix Length (e.g. "/64")
- {
- require_action_quiet( !hasPrefix, exit, err = kMalformedErr );
- require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
- while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
- require_action_quiet( ( prefix >= 0 ) && ( prefix <= 128 ), exit, err = kRangeErr );
- hasPrefix = 1;
- }
- else if( c == ']' )
- {
- require_action_quiet( !hasBracket, exit, err = kMalformedErr );
- hasBracket = 1;
- c = *( ++inStr );
- }
- else
- {
- break;
- }
- }
-
- // Return the results. Only fill in scope/port/prefix results if the info was found to allow for defaults.
-
- if( outIPv6 ) for( i = 0; i < 16; ++i ) outIPv6[ i ] = ipv6[ i ];
- if( outScope && hasScope ) *outScope = scope;
- if( outPort && hasPort ) *outPort = port;
- if( outPrefix && hasPrefix ) *outPrefix = prefix;
- if( outStr ) *outStr = inStr;
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// StringArray_Free
-//
-// Note: This was copied from CoreUtils because the StringArray_Free function is currently not exported in the framework.
-//===========================================================================================================================
-
-void StringArray_Free( char **inArray, size_t inCount )
-{
- size_t i;
-
- for( i = 0; i < inCount; ++i )
- {
- free( inArray[ i ] );
- }
- if( inCount > 0 ) free( inArray );
-}
-
-//===========================================================================================================================
-// ParseQuotedEscapedString
-//
-// Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-Boolean
- ParseQuotedEscapedString(
- const char * inSrc,
- const char * inEnd,
- const char * inDelimiters,
- char * inBuf,
- size_t inMaxLen,
- size_t * outCopiedLen,
- size_t * outTotalLen,
- const char ** outSrc )
-{
- const unsigned char * src;
- const unsigned char * end;
- unsigned char * dst;
- unsigned char * lim;
- unsigned char c;
- unsigned char c2;
- size_t totalLen;
- Boolean singleQuote;
- Boolean doubleQuote;
-
- if( inEnd == NULL ) inEnd = inSrc + strlen( inSrc );
- src = (const unsigned char *) inSrc;
- end = (const unsigned char *) inEnd;
- dst = (unsigned char *) inBuf;
- lim = dst + inMaxLen;
- while( ( src < end ) && isspace_safe( *src ) ) ++src; // Skip leading spaces.
- if( src >= end ) return( false );
-
- // Parse each argument from the string.
- //
- // See <http://resources.mpi-inf.mpg.de/departments/rg1/teaching/unixffb-ss98/quoting-guide.html> for details.
-
- totalLen = 0;
- singleQuote = false;
- doubleQuote = false;
- while( src < end )
- {
- c = *src++;
- if( singleQuote )
- {
- // Single quotes protect everything (even backslashes, newlines, etc.) except single quotes.
-
- if( c == '\'' )
- {
- singleQuote = false;
- continue;
- }
- }
- else if( doubleQuote )
- {
- // Double quotes protect everything except double quotes and backslashes. A backslash can be
- // used to protect " or \ within double quotes. A backslash-newline pair disappears completely.
- // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
- // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
- // A backslash that does not precede ", \, x, X, or a newline is taken literally.
-
- if( c == '"' )
- {
- doubleQuote = false;
- continue;
- }
- else if( c == '\\' )
- {
- if( src < end )
- {
- c2 = *src;
- if( ( c2 == '"' ) || ( c2 == '\\' ) )
- {
- ++src;
- c = c2;
- }
- else if( c2 == '\n' )
- {
- ++src;
- continue;
- }
- else if( ( c2 == 'x' ) || ( c2 == 'X' ) )
- {
- ++src;
- c = c2;
- if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
- {
- c = HexPairToByte( src );
- src += 2;
- }
- }
- else if( isoctal_safe( c2 ) )
- {
- if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
- {
- c = OctalTripleToByte( src );
- src += 3;
- }
- }
- }
- }
- }
- else if( strchr( inDelimiters, c ) )
- {
- break;
- }
- else if( c == '\\' )
- {
- // A backslash protects the next character, except a newline, x, X and 2 hex bytes or 3 octal bytes.
- // A backslash followed by a newline disappears completely.
- // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
- // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
-
- if( src < end )
- {
- c = *src;
- if( c == '\n' )
- {
- ++src;
- continue;
- }
- else if( ( c == 'x' ) || ( c == 'X' ) )
- {
- ++src;
- if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
- {
- c = HexPairToByte( src );
- src += 2;
- }
- }
- else if( isoctal_safe( c ) )
- {
- if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
- {
- c = OctalTripleToByte( src );
- src += 3;
- }
- else
- {
- ++src;
- }
- }
- else
- {
- ++src;
- }
- }
- }
- else if( c == '\'' )
- {
- singleQuote = true;
- continue;
- }
- else if( c == '"' )
- {
- doubleQuote = true;
- continue;
- }
-
- if( dst < lim )
- {
- if( inBuf ) *dst = c;
- ++dst;
- }
- ++totalLen;
- }
-
- if( outCopiedLen ) *outCopiedLen = (size_t)( dst - ( (unsigned char *) inBuf ) );
- if( outTotalLen ) *outTotalLen = totalLen;
- if( outSrc ) *outSrc = (const char *) src;
- return( true );
-}
-
-//===========================================================================================================================
-// _ServerSocketOpenEx2
-//
-// Note: Based on ServerSocketOpenEx() from CoreUtils. Added parameter to not use SO_REUSEPORT.
-//===========================================================================================================================
-
-static OSStatus
- _ServerSocketOpenEx2(
- int inFamily,
- int inType,
- int inProtocol,
- const void * inAddr,
- int inPort,
- int * outPort,
- int inRcvBufSize,
- Boolean inNoPortReuse,
- SocketRef * outSock )
-{
- OSStatus err;
- int port;
- SocketRef sock;
- int name;
- int option;
- sockaddr_ip sip;
- socklen_t len;
-
- port = ( inPort < 0 ) ? -inPort : inPort; // Negated port number means "try this port, but allow dynamic".
-
- sock = socket( inFamily, inType, inProtocol );
- err = map_socket_creation_errno( sock );
- require_noerr_quiet( err, exit );
-
-#if( defined( SO_NOSIGPIPE ) )
- setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, (socklen_t) sizeof( int ) );
-#endif
-
- err = SocketMakeNonBlocking( sock );
- require_noerr( err, exit );
-
- // Set receive buffer size. This has to be done on the listening socket *before* listen is called because
- // accept does not return until after the window scale option is exchanged during the 3-way handshake.
- // Since accept returns a new socket, the only way to use a larger window scale option is to set the buffer
- // size on the listening socket since SO_RCVBUF is inherited by the accepted socket. See UNPv1e3 Section 7.5.
-
- err = SocketSetBufferSize( sock, SO_RCVBUF, inRcvBufSize );
- check_noerr( err );
-
- // Allow port or address reuse because we may bind separate IPv4 and IPv6 sockets to the same port.
-
- if( ( inType != SOCK_DGRAM ) || !inNoPortReuse )
- {
- option = 1;
- name = ( inType == SOCK_DGRAM ) ? SO_REUSEPORT : SO_REUSEADDR;
- err = setsockopt( sock, SOL_SOCKET, name, (char *) &option, (socklen_t) sizeof( option ) );
- err = map_socket_noerr_errno( sock, err );
- require_noerr( err, exit );
- }
-
- if( inFamily == AF_INET )
- {
- // Bind to the port. If it fails, retry with a dynamic port.
-
- memset( &sip.v4, 0, sizeof( sip.v4 ) );
- SIN_LEN_SET( &sip.v4 );
- sip.v4.sin_family = AF_INET;
- sip.v4.sin_port = htons( (uint16_t) port );
- sip.v4.sin_addr.s_addr = inAddr ? *( (const uint32_t *) inAddr ) : htonl( INADDR_ANY );
- err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
- err = map_socket_noerr_errno( sock, err );
- if( err && ( inPort < 0 ) )
- {
- sip.v4.sin_port = 0;
- err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
- err = map_socket_noerr_errno( sock, err );
- }
- require_noerr( err, exit );
- }
-#if( defined( AF_INET6 ) )
- else if( inFamily == AF_INET6 )
- {
- // Restrict this socket to IPv6 only because we're going to use a separate socket for IPv4.
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, (socklen_t) sizeof( option ) );
- err = map_socket_noerr_errno( sock, err );
- require_noerr( err, exit );
-
- // Bind to the port. If it fails, retry with a dynamic port.
-
- memset( &sip.v6, 0, sizeof( sip.v6 ) );
- SIN6_LEN_SET( &sip.v6 );
- sip.v6.sin6_family = AF_INET6;
- sip.v6.sin6_port = htons( (uint16_t) port );
- sip.v6.sin6_addr = inAddr ? *( (const struct in6_addr *) inAddr ) : in6addr_any;
- err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
- err = map_socket_noerr_errno( sock, err );
- if( err && ( inPort < 0 ) )
- {
- sip.v6.sin6_port = 0;
- err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
- err = map_socket_noerr_errno( sock, err );
- }
- require_noerr( err, exit );
- }
-#endif
- else
- {
- dlogassert( "Unsupported family: %d", inFamily );
- err = kUnsupportedErr;
- goto exit;
- }
-
- if( inType == SOCK_STREAM )
- {
- err = listen( sock, SOMAXCONN );
- err = map_socket_noerr_errno( sock, err );
- if( err )
- {
- err = listen( sock, 5 );
- err = map_socket_noerr_errno( sock, err );
- require_noerr( err, exit );
- }
- }
-
- if( outPort )
- {
- len = (socklen_t) sizeof( sip );
- err = getsockname( sock, &sip.sa, &len );
- err = map_socket_noerr_errno( sock, err );
- require_noerr( err, exit );
-
- *outPort = SockAddrGetPort( &sip );
- }
- *outSock = sock;
- sock = kInvalidSocketRef;
-
-exit:
- ForgetSocket( &sock );
- return( err );
-}
-
-//===========================================================================================================================
-// memdup
-//
-// Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-void * memdup( const void *inPtr, size_t inLen )
-{
- void * mem;
-
- mem = malloc( ( inLen > 0 ) ? inLen : 1 ); // If inLen is 0, use 1 since malloc( 0 ) is not well defined.
- require( mem, exit );
- if( inLen > 0 ) memcpy( mem, inPtr, inLen );
-
-exit:
- return( mem );
-}
-
-#if( !TARGET_OS_WINDOWS )
-//===========================================================================================================================
-// memicmp
-//
-// Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-int memicmp( const void *inP1, const void *inP2, size_t inLen )
-{
- const unsigned char * p1;
- const unsigned char * e1;
- const unsigned char * p2;
- int c1;
- int c2;
-
- p1 = (const unsigned char *) inP1;
- e1 = p1 + inLen;
- p2 = (const unsigned char *) inP2;
- while( p1 < e1 )
- {
- c1 = *p1++;
- c2 = *p2++;
- c1 = tolower( c1 );
- c2 = tolower( c2 );
- if( c1 < c2 ) return( -1 );
- if( c1 > c2 ) return( 1 );
- }
- return( 0 );
-}
-#endif
-
-//===========================================================================================================================
-// FNV1
-//
-// Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-uint32_t FNV1( const void *inData, size_t inSize )
-{
- const uint8_t * src = (const uint8_t *) inData;
- const uint8_t * const end = src + inSize;
- uint32_t hash;
-
- hash = 0x811c9dc5U;
- while( src != end )
- {
- hash *= 0x01000193;
- hash ^= *src++;
- }
- return( hash );
-}
--- /dev/null
+/*
+ Copyright (c) 2016-2019 Apple Inc. All rights reserved.
+*/
+
+#include "DNSMessage.h"
+
+//===========================================================================================================================
+
+#define IsCompressionByte( X ) ( ( ( X ) & 0xC0 ) == 0xC0 )
+
+OSStatus
+ DNSMessageExtractDomainName(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t outName[ kDomainNameLengthMax ],
+ const uint8_t ** outPtr )
+{
+ OSStatus err;
+ const uint8_t * label;
+ uint8_t labelLen;
+ const uint8_t * nextLabel;
+ const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
+ uint8_t * dst = outName;
+ const uint8_t * const dstLim = outName ? ( outName + kDomainNameLengthMax ) : NULL;
+ const uint8_t * nameEnd = NULL;
+
+ require_action_quiet( ( inPtr >= inMsgPtr ) && ( inPtr < msgEnd ), exit, err = kRangeErr );
+
+ for( label = inPtr; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
+ {
+ if( labelLen <= kDomainLabelLengthMax )
+ {
+ nextLabel = label + 1 + labelLen;
+ require_action_quiet( nextLabel < msgEnd, exit, err = kUnderrunErr );
+ if( dst )
+ {
+ require_action_quiet( ( dstLim - dst ) > ( 1 + labelLen ), exit, err = kOverrunErr );
+ memcpy( dst, label, 1 + labelLen );
+ dst += ( 1 + labelLen );
+ }
+ }
+ else if( IsCompressionByte( labelLen ) )
+ {
+ uint16_t offset;
+
+ require_action_quiet( ( msgEnd - label ) >= 2, exit, err = kUnderrunErr );
+ if( !nameEnd )
+ {
+ nameEnd = label + 2;
+ if( !dst ) break;
+ }
+ offset = (uint16_t)( ( ( label[ 0 ] & 0x3F ) << 8 ) | label[ 1 ] );
+ nextLabel = inMsgPtr + offset;
+ require_action_quiet( nextLabel < msgEnd, exit, err = kUnderrunErr );
+ require_action_quiet( !IsCompressionByte( nextLabel[ 0 ] ), exit, err = kMalformedErr );
+ }
+ else
+ {
+ err = kMalformedErr;
+ goto exit;
+ }
+ }
+
+ if( dst ) *dst = 0;
+ if( !nameEnd ) nameEnd = label + 1;
+
+ if( outPtr ) *outPtr = nameEnd;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DNSMessageExtractDomainNameString(
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ const void * inPtr,
+ char inBuf[ kDNSServiceMaxDomainName ],
+ const uint8_t ** outPtr )
+{
+ OSStatus err;
+ const uint8_t * nextPtr;
+ uint8_t domainName[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, domainName, &nextPtr );
+ require_noerr_quiet( err, exit );
+
+ err = DomainNameToString( domainName, NULL, inBuf, NULL );
+ require_noerr_quiet( err, exit );
+
+ if( outPtr ) *outPtr = nextPtr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DNSMessageExtractQuestion(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t outName[ kDomainNameLengthMax ],
+ uint16_t * outType,
+ uint16_t * outClass,
+ const uint8_t ** outPtr )
+{
+ OSStatus err;
+ const uint8_t * const msgEnd = &inMsgPtr[ inMsgLen ];
+ const uint8_t * ptr;
+ const dns_fixed_fields_question * fields;
+
+ err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, outName, &ptr );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( (size_t)( msgEnd - ptr ) >= sizeof( dns_fixed_fields_question ), exit, err = kUnderrunErr );
+
+ fields = (const dns_fixed_fields_question *) ptr;
+ if( outType ) *outType = dns_fixed_fields_question_get_type( fields );
+ if( outClass ) *outClass = dns_fixed_fields_question_get_class( fields );
+ if( outPtr ) *outPtr = (const uint8_t *) &fields[ 1 ];
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DNSMessageExtractRecord(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t outName[ kDomainNameLengthMax ],
+ uint16_t * outType,
+ uint16_t * outClass,
+ uint32_t * outTTL,
+ const uint8_t ** outRDataPtr,
+ size_t * outRDataLen,
+ const uint8_t ** outPtr )
+{
+ OSStatus err;
+ const uint8_t * const msgEnd = inMsgPtr + inMsgLen;
+ const uint8_t * ptr;
+ const dns_fixed_fields_record * fields;
+ const uint8_t * rdata;
+ size_t rdLength;
+
+ err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, outName, &ptr );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( (size_t)( msgEnd - ptr ) >= sizeof( *fields ), exit, err = kUnderrunErr );
+
+ fields = (const dns_fixed_fields_record *) ptr;
+ rdata = ptr + sizeof( *fields );
+
+ rdLength = dns_fixed_fields_record_get_rdlength( fields );
+ require_action_quiet( (size_t)( msgEnd - rdata ) >= rdLength , exit, err = kUnderrunErr );
+
+ if( outType ) *outType = dns_fixed_fields_record_get_type( fields );
+ if( outClass ) *outClass = dns_fixed_fields_record_get_class( fields );
+ if( outTTL ) *outTTL = dns_fixed_fields_record_get_ttl( fields );
+ if( outRDataPtr ) *outRDataPtr = rdata;
+ if( outRDataLen ) *outRDataLen = rdLength;
+ if( outPtr ) *outPtr = &rdata[ rdLength ];
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr )
+{
+ OSStatus err;
+ unsigned int questionCount, i;
+ const DNSHeader * hdr;
+ const uint8_t * ptr;
+
+ require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+
+ hdr = (DNSHeader *) inMsgPtr;
+ questionCount = DNSHeaderGetQuestionCount( hdr );
+
+ ptr = (const uint8_t *) &hdr[ 1 ];
+ for( i = 0; i < questionCount; ++i )
+ {
+ err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, NULL, NULL, NULL, &ptr );
+ require_noerr_quiet( err, exit );
+ }
+
+ if( outPtr ) *outPtr = ptr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DNSMessageWriteQuery(
+ uint16_t inMsgID,
+ uint16_t inFlags,
+ const uint8_t * inQName,
+ uint16_t inQType,
+ uint16_t inQClass,
+ uint8_t outMsg[ STATIC_PARAM kDNSQueryMessageMaxLen ],
+ size_t * outLen )
+{
+ OSStatus err;
+ DNSHeader * const hdr = (DNSHeader *) outMsg;
+ uint8_t * ptr;
+ size_t qnameLen;
+ size_t msgLen;
+
+ memset( hdr, 0, sizeof( *hdr ) );
+ DNSHeaderSetID( hdr, inMsgID );
+ DNSHeaderSetFlags( hdr, inFlags );
+ DNSHeaderSetQuestionCount( hdr, 1 );
+
+ qnameLen = DomainNameLength( inQName );
+ require_action_quiet( qnameLen <= kDomainNameLengthMax, exit, err = kSizeErr );
+
+ ptr = (uint8_t *) &hdr[ 1 ];
+ memcpy( ptr, inQName, qnameLen );
+ ptr += qnameLen;
+
+ dns_fixed_fields_question_init( (dns_fixed_fields_question *) ptr, inQType, inQClass );
+ ptr += sizeof( dns_fixed_fields_question );
+
+ msgLen = (size_t)( ptr - outMsg );
+
+ if( outLen ) *outLen = msgLen;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DomainNameAppendString(
+ uint8_t inDomainName[ STATIC_PARAM kDomainNameLengthMax ],
+ const char * inString,
+ uint8_t ** outEnd )
+{
+ OSStatus err;
+ const char * src;
+ uint8_t * root;
+ const uint8_t * const nameLim = inDomainName + kDomainNameLengthMax;
+
+ for( root = inDomainName; ( root < nameLim ) && *root; root += ( 1 + *root ) ) {}
+ require_action_quiet( root < nameLim, exit, err = kMalformedErr );
+
+ // If the string is a single dot, denoting the root domain, then there are no non-empty labels.
+
+ src = inString;
+ if( ( src[ 0 ] == '.' ) && ( src[ 1 ] == '\0' ) ) ++src;
+ while( *src )
+ {
+ uint8_t * const label = root;
+ const uint8_t * const labelLim = Min( &label[ 1 + kDomainLabelLengthMax ], nameLim - 1 );
+ uint8_t * dst;
+ int c;
+ size_t labelLen;
+
+ dst = &label[ 1 ];
+ while( *src && ( ( c = *src++ ) != '.' ) )
+ {
+ if( c == '\\' )
+ {
+ require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
+ c = *src++;
+ if( isdigit_safe( c ) && isdigit_safe( src[ 0 ] ) && isdigit_safe( src[ 1 ] ) )
+ {
+ const int decimal = ( ( c - '0' ) * 100 ) + ( ( src[ 0 ] - '0' ) * 10 ) + ( src[ 1 ] - '0' );
+
+ if( decimal <= 255 )
+ {
+ c = decimal;
+ src += 2;
+ }
+ }
+ }
+ require_action_quiet( dst < labelLim, exit, err = kOverrunErr );
+ *dst++ = (uint8_t) c;
+ }
+
+ labelLen = (size_t)( dst - &label[ 1 ] );
+ require_action_quiet( labelLen > 0, exit, err = kMalformedErr );
+
+ label[ 0 ] = (uint8_t) labelLen;
+ root = dst;
+ *root = 0;
+ }
+
+ if( outEnd ) *outEnd = root + 1;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen )
+{
+ OSStatus err;
+ uint8_t * namePtr;
+ const size_t nameLen = DomainNameLength( inName );
+
+ namePtr = (uint8_t *) malloc( nameLen );
+ require_action_quiet( namePtr, exit, err = kNoMemoryErr );
+
+ if( inLower )
+ {
+ const uint8_t * src;
+ uint8_t * dst;
+ unsigned int len;
+
+ src = inName;
+ dst = namePtr;
+ while( ( len = *src ) != 0 )
+ {
+ *dst++ = *src++;
+ while( len-- > 0 )
+ {
+ const int c = *src++;
+ *dst++ = (uint8_t) tolower_safe( c );
+ }
+ }
+ *dst = 0;
+ }
+ else
+ {
+ memcpy( namePtr, inName, nameLen );
+ }
+
+ *outNamePtr = namePtr;
+ if( outNameLen ) *outNameLen = nameLen;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 )
+{
+ const uint8_t * p1 = inName1;
+ const uint8_t * p2 = inName2;
+ if( p1 == p2 ) return( true );
+ for( ;; )
+ {
+ int len1 = *p1++;
+ const int len2 = *p2++;
+ if( len1 != len2 ) return( false );
+ if( len1 == 0 ) return( true );
+ while( len1-- > 0 )
+ {
+ const int c1 = *p1++;
+ const int c2 = *p2++;
+ if( tolower_safe( c1 ) != tolower_safe( c2 ) ) return( false );
+ }
+ }
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DomainNameFromString(
+ uint8_t outName[ STATIC_PARAM kDomainNameLengthMax ],
+ const char * inString,
+ uint8_t ** outEnd )
+{
+ outName[ 0 ] = 0;
+ return( DomainNameAppendString( outName, inString, outEnd ) );
+}
+
+//===========================================================================================================================
+
+OSStatus
+ DomainNameToString(
+ const uint8_t * inName,
+ const uint8_t * inLimit,
+ char outString[ STATIC_PARAM kDNSServiceMaxDomainName ],
+ const uint8_t ** outPtr )
+{
+ OSStatus err;
+ const uint8_t * label;
+ uint8_t labelLen;
+ const uint8_t * nextLabel;
+ char * dst;
+ const uint8_t * src;
+
+ require_action_quiet( !inLimit || ( inName < inLimit ), exit, err = kUnderrunErr );
+
+ // Convert each label up until the root label, i.e., the zero-length label.
+
+ dst = outString;
+ for( label = inName; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
+ {
+ require_action_quiet( labelLen <= kDomainLabelLengthMax, exit, err = kMalformedErr );
+
+ nextLabel = &label[ 1 + labelLen ];
+ require_action_quiet( ( nextLabel - inName ) < kDomainNameLengthMax, exit, err = kMalformedErr );
+ require_action_quiet( !inLimit || ( nextLabel < inLimit ), exit, err = kUnderrunErr );
+
+ for( src = &label[ 1 ]; src < nextLabel; ++src )
+ {
+ // Only allow 7-bit ASCII characters.
+ if( ( *src >= 32 ) && ( *src <= 126 ) )
+ {
+ if( ( *src == '.' ) || ( *src == '\\' ) || ( *src == ' ' ) ) *dst++ = '\\';
+ *dst++ = (char) *src;
+ }
+ else
+ {
+ *dst++ = '\\';
+ *dst++ = '0' + ( *src / 100 );
+ *dst++ = '0' + ( ( *src / 10 ) % 10 );
+ *dst++ = '0' + ( *src % 10 );
+ }
+ }
+ *dst++ = '.';
+ }
+
+ // At this point, label points to the root label.
+ // If the root label was the only label, then write a dot for it.
+
+ if( label == inName ) *dst++ = '.';
+ *dst = '\0';
+ if( outPtr ) *outPtr = label + 1;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
--- /dev/null
+/*
+ Copyright (c) 2016-2019 Apple Inc. All rights reserved.
+*/
+
+#ifndef __DNSMessage_h
+#define __DNSMessage_h
+
+#include <CoreUtils/CoreUtils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @group DNS domain name size limits
+
+ @discussion See <https://tools.ietf.org/html/rfc1035#section-2.3.4>.
+*/
+#define kDomainLabelLengthMax 63
+#define kDomainNameLengthMax 256 // For compatibility with mDNS. See <https://tools.ietf.org/html/rfc6762#appendix-C>.
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @group DNS message header
+*/
+typedef struct
+{
+ uint8_t id[ 2 ];
+ uint8_t flags[ 2 ];
+ uint8_t questionCount[ 2 ];
+ uint8_t answerCount[ 2 ];
+ uint8_t authorityCount[ 2 ];
+ uint8_t additionalCount[ 2 ];
+
+} DNSHeader;
+
+#define kDNSHeaderLength 12
+check_compile_time( sizeof( DNSHeader ) == kDNSHeaderLength );
+
+#define DNSHeaderGetID( HDR ) ReadBig16( ( HDR )->id )
+#define DNSHeaderGetFlags( HDR ) ReadBig16( ( HDR )->flags )
+#define DNSHeaderGetQuestionCount( HDR ) ReadBig16( ( HDR )->questionCount )
+#define DNSHeaderGetAnswerCount( HDR ) ReadBig16( ( HDR )->answerCount )
+#define DNSHeaderGetAuthorityCount( HDR ) ReadBig16( ( HDR )->authorityCount )
+#define DNSHeaderGetAdditionalCount( HDR ) ReadBig16( ( HDR )->additionalCount )
+
+#define DNSHeaderSetID( HDR, X ) WriteBig16( ( HDR )->id, (X) )
+#define DNSHeaderSetFlags( HDR, X ) WriteBig16( ( HDR )->flags, (X) )
+#define DNSHeaderSetQuestionCount( HDR, X ) WriteBig16( ( HDR )->questionCount, (X) )
+#define DNSHeaderSetAnswerCount( HDR, X ) WriteBig16( ( HDR )->answerCount, (X) )
+#define DNSHeaderSetAuthorityCount( HDR, X ) WriteBig16( ( HDR )->authorityCount, (X) )
+#define DNSHeaderSetAdditionalCount( HDR, X ) WriteBig16( ( HDR )->additionalCount, (X) )
+
+// Single-bit DNS header fields
+
+#define kDNSHeaderFlag_Response ( 1U << 15 ) // QR (bit 15), Query (0)/Response (1)
+#define kDNSHeaderFlag_AuthAnswer ( 1U << 10 ) // AA (bit 10), Authoritative Answer
+#define kDNSHeaderFlag_Truncation ( 1U << 9 ) // TC (bit 9), TrunCation
+#define kDNSHeaderFlag_RecursionDesired ( 1U << 8 ) // RD (bit 8), Recursion Desired
+#define kDNSHeaderFlag_RecursionAvailable ( 1U << 7 ) // RA (bit 7), Recursion Available
+#define kDNSHeaderFlag_Z ( 1U << 6 ) // Z (bit 6), Reserved (must be zero)
+#define kDNSHeaderFlag_AuthenticData ( 1U << 5 ) // AD (bit 5), Authentic Data (RFC 2535, Section 6)
+#define kDNSHeaderFlag_CheckingDisabled ( 1U << 4 ) // CD (bit 4), Checking Disabled (RFC 2535, Section 6)
+
+// OPCODE (bits 14-11), Operation Code
+
+#define DNSFlagsGetOpCode( FLAGS ) ( ( (FLAGS) >> 11 ) & 0x0FU )
+#define DNSFlagsSetOpCode( FLAGS, OPCODE ) \
+ do { (FLAGS) = ( (FLAGS) & ~0x7800U ) | ( ( (OPCODE) & 0x0FU ) << 11 ); } while( 0 )
+
+#define kDNSOpCode_Query 0 // QUERY (standard query)
+#define kDNSOpCode_InverseQuery 1 // IQUERY (inverse query)
+#define kDNSOpCode_Status 2 // STATUS
+#define kDNSOpCode_Notify 4 // NOTIFY
+#define kDNSOpCode_Update 5 // UPDATE
+
+// RCODE (bits 3-0), Response Code
+
+#define DNSFlagsGetRCode( FLAGS ) ( (FLAGS) & 0x0FU )
+#define DNSFlagsSetRCode( FLAGS, RCODE ) \
+ do { (FLAGS) = ( (FLAGS) & ~0x000FU ) | ( (RCODE) & 0x0FU ); } while( 0 )
+
+#define kDNSRCode_NoError 0
+#define kDNSRCode_FormatError 1
+#define kDNSRCode_ServerFailure 2
+#define kDNSRCode_NXDomain 3
+#define kDNSRCode_NotImplemented 4
+#define kDNSRCode_Refused 5
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @group Misc. DNS message data structures
+*/
+
+#define dns_fixed_fields_define_accessors( TYPE, FIELD, BIT_SIZE ) \
+ STATIC_INLINE uint ## BIT_SIZE ##_t \
+ dns_fixed_fields_ ## TYPE ## _get_ ## FIELD ( \
+ const dns_fixed_fields_ ## TYPE * inFields ) \
+ { \
+ return ReadBig ## BIT_SIZE ( inFields->FIELD ); \
+ } \
+ \
+ STATIC_INLINE void \
+ dns_fixed_fields_ ## TYPE ## _set_ ## FIELD ( \
+ dns_fixed_fields_ ## TYPE * inFields, \
+ uint ## BIT_SIZE ## _t inValue ) \
+ { \
+ WriteBig ## BIT_SIZE ( inFields->FIELD, inValue ); \
+ } \
+ check_compile_time( ( sizeof_field( dns_fixed_fields_ ## TYPE, FIELD ) * 8 ) == (BIT_SIZE) )
+
+// DNS question fixed-length fields (see <https://tools.ietf.org/html/rfc1035#section-4.1.2>)
+
+typedef struct
+{
+ uint8_t type[ 2 ];
+ uint8_t class[ 2 ];
+
+} dns_fixed_fields_question;
+
+check_compile_time( sizeof( dns_fixed_fields_question ) == 4 );
+
+dns_fixed_fields_define_accessors( question, type, 16 );
+dns_fixed_fields_define_accessors( question, class, 16 );
+
+STATIC_INLINE void
+ dns_fixed_fields_question_init(
+ dns_fixed_fields_question * inFields,
+ uint16_t inQType,
+ uint16_t inQClass )
+{
+ dns_fixed_fields_question_set_type( inFields, inQType );
+ dns_fixed_fields_question_set_class( inFields, inQClass );
+}
+
+// DNS resource record fixed-length fields (see <https://tools.ietf.org/html/rfc1035#section-4.1.3>)
+
+typedef struct
+{
+ uint8_t type[ 2 ];
+ uint8_t class[ 2 ];
+ uint8_t ttl[ 4 ];
+ uint8_t rdlength[ 2 ];
+
+} dns_fixed_fields_record;
+
+check_compile_time( sizeof( dns_fixed_fields_record ) == 10 );
+
+dns_fixed_fields_define_accessors( record, type, 16 );
+dns_fixed_fields_define_accessors( record, class, 16 );
+dns_fixed_fields_define_accessors( record, ttl, 32 );
+dns_fixed_fields_define_accessors( record, rdlength, 16 );
+
+STATIC_INLINE void
+ dns_fixed_fields_record_init(
+ dns_fixed_fields_record * inFields,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ uint16_t inRDLength )
+{
+ dns_fixed_fields_record_set_type( inFields, inType );
+ dns_fixed_fields_record_set_class( inFields, inClass );
+ dns_fixed_fields_record_set_ttl( inFields, inTTL );
+ dns_fixed_fields_record_set_rdlength( inFields, inRDLength );
+}
+
+// DNS SRV record data fixed-length fields (see <https://tools.ietf.org/html/rfc2782>)
+
+typedef struct
+{
+ uint8_t priority[ 2 ];
+ uint8_t weight[ 2 ];
+ uint8_t port[ 2 ];
+
+} dns_fixed_fields_srv;
+
+check_compile_time( sizeof( dns_fixed_fields_srv ) == 6 );
+
+dns_fixed_fields_define_accessors( srv, priority, 16 );
+dns_fixed_fields_define_accessors( srv, weight, 16 );
+dns_fixed_fields_define_accessors( srv, port, 16 );
+
+STATIC_INLINE void
+ dns_fixed_fields_srv_init(
+ dns_fixed_fields_srv * inFields,
+ uint16_t inPriority,
+ uint16_t inWeight,
+ uint16_t inPort )
+{
+ dns_fixed_fields_srv_set_priority( inFields, inPriority );
+ dns_fixed_fields_srv_set_weight( inFields, inWeight );
+ dns_fixed_fields_srv_set_port( inFields, inPort );
+}
+
+// DNS SOA record data fixed-length fields (see <https://tools.ietf.org/html/rfc1035#section-3.3.13>)
+
+typedef struct
+{
+ uint8_t serial[ 4 ];
+ uint8_t refresh[ 4 ];
+ uint8_t retry[ 4 ];
+ uint8_t expire[ 4 ];
+ uint8_t minimum[ 4 ];
+
+} dns_fixed_fields_soa;
+
+check_compile_time( sizeof( dns_fixed_fields_soa ) == 20 );
+
+dns_fixed_fields_define_accessors( soa, serial, 32 );
+dns_fixed_fields_define_accessors( soa, refresh, 32 );
+dns_fixed_fields_define_accessors( soa, retry, 32 );
+dns_fixed_fields_define_accessors( soa, expire, 32 );
+dns_fixed_fields_define_accessors( soa, minimum, 32 );
+
+STATIC_INLINE void
+ dns_fixed_fields_soa_init(
+ dns_fixed_fields_soa * inFields,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimum )
+{
+ dns_fixed_fields_soa_set_serial( inFields, inSerial );
+ dns_fixed_fields_soa_set_refresh( inFields, inRefresh );
+ dns_fixed_fields_soa_set_retry( inFields, inRetry );
+ dns_fixed_fields_soa_set_expire( inFields, inExpire );
+ dns_fixed_fields_soa_set_minimum( inFields, inMinimum );
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Extracts a domain name from a DNS message.
+
+ @param inMsgPtr Pointer to the beginning of the DNS message containing the domain name.
+ @param inMsgLen Length of the DNS message containing the domain name.
+ @param inPtr Pointer to the domain name field.
+ @param outName Buffer to write extracted domain name. (Optional)
+ @param outPtr Gets set to point to the end of the domain name field. (Optional)
+*/
+OSStatus
+ DNSMessageExtractDomainName(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t outName[ kDomainNameLengthMax ],
+ const uint8_t ** outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Extracts a domain name from a DNS message as a C string.
+
+ @param inMsgPtr Pointer to the beginning of the DNS message containing the domain name.
+ @param inMsgLen Length of the DNS message containing the domain name.
+ @param inPtr Pointer to the domain name field.
+ @param outName Buffer to write extracted domain name. (Optional)
+ @param outPtr Gets set to point to the end of the domain name field. (Optional)
+*/
+OSStatus
+ DNSMessageExtractDomainNameString(
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ const void * inPtr,
+ char outName[ kDNSServiceMaxDomainName ],
+ const uint8_t ** outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Extracts a question from a DNS message.
+
+ @param inMsgPtr Pointer to the beginning of the DNS message containing a question.
+ @param inMsgLen Length of the DNS message containing the question.
+ @param inPtr Pointer to the question.
+ @param outName Buffer to write the question's QNAME. (Optional)
+ @param outType Gets set to question's QTYPE value. (Optional)
+ @param outClass Gets set to question's QCLASS value. (Optional)
+ @param outPtr Gets set to point to the end of the question. (Optional)
+*/
+OSStatus
+ DNSMessageExtractQuestion(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t outName[ kDomainNameLengthMax ],
+ uint16_t * outType,
+ uint16_t * outClass,
+ const uint8_t ** outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Extracts a resource record from a DNS message.
+
+ @param inMsgPtr Pointer to the beginning of the DNS message containing the resource record.
+ @param inMsgLen Length of the DNS message containing the resource record.
+ @param inPtr Pointer to the resource record.
+ @param outName Buffer to write the resource record's NAME. (Optional)
+ @param outType Gets set to resource record's TYPE value. (Optional)
+ @param outClass Gets set to resource record's CLASS value. (Optional)
+ @param outTTL Gets set to resource record's TTL value. (Optional)
+ @param outRDataPtr Gets set to point to the resource record's RDATA. (Optional)
+ @param outRDataLen Gets set to the resource record's RDLENGTH. (Optional)
+ @param outPtr Gets set to point to the end of the resource record. (Optional)
+*/
+OSStatus
+ DNSMessageExtractRecord(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const uint8_t * inPtr,
+ uint8_t outName[ kDomainNameLengthMax ],
+ uint16_t * outType,
+ uint16_t * outClass,
+ uint32_t * outTTL,
+ const uint8_t ** outRDataPtr,
+ size_t * outRDataLen,
+ const uint8_t ** outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Returns pointer to the start of the answer section, i.e., the end of the question section, of a DNS message.
+
+ @param inMsgPtr Pointer to the beginning of the DNS message.
+ @param inMsgLen Length of the DNS message.
+ @param outPtr Gets set to point to the start of the answer section. (Optional)
+*/
+OSStatus DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Writes a DNS message compression label pointer.
+
+ @param inLabelPtr Pointer to the two bytes to which to write the label pointer.
+ @param inOffset The label pointer's offset value. This offset is relative to the start of the DNS message.
+
+ @discussion See <https://tools.ietf.org/html/rfc1035#section-4.1.4>.
+*/
+STATIC_INLINE void DNSMessageWriteLabelPointer( uint8_t inLabelPtr[ STATIC_PARAM 2 ], size_t inOffset )
+{
+ inLabelPtr[ 0 ] = (uint8_t)( ( ( inOffset >> 8 ) & 0x3F ) | 0xC0 );
+ inLabelPtr[ 1 ] = (uint8_t)( inOffset & 0xFF );
+}
+
+#define kDNSCompressionOffsetMax 0x3FFF
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Writes a single-question DNS query message.
+
+ @param inMsgID The query message's ID.
+ @param inFlags The query message's flags.
+ @param inQName The question's QNAME in label format.
+ @param inQType The question's QTYPE.
+ @param inQClass The question's QCLASS.
+ @param outMsg Buffer to write DNS query message.
+ @param outLen Gets set to the length of the DNS query message.
+
+ @discussion The duplicate domain name must be freed with free() when no longer needed.
+*/
+#define kDNSQueryMessageMaxLen ( kDNSHeaderLength + kDomainNameLengthMax + sizeof( dns_fixed_fields_question ) )
+
+OSStatus
+ DNSMessageWriteQuery(
+ uint16_t inMsgID,
+ uint16_t inFlags,
+ const uint8_t * inQName,
+ uint16_t inQType,
+ uint16_t inQClass,
+ uint8_t outMsg[ STATIC_PARAM kDNSQueryMessageMaxLen ],
+ size_t * outLen );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Appends a C string representing a textual sequence of labels to a domain name.
+
+ @param inName Pointer to the domain name.
+ @param inString Pointer to textual sequence of labels as a C string. (Optional)
+ @param outEnd Gets set to point to the new end of the domain name if the append succeeded. (Optional)
+*/
+OSStatus
+ DomainNameAppendString(
+ uint8_t inName[ STATIC_PARAM kDomainNameLengthMax ],
+ const char * inString,
+ uint8_t ** outEnd );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Creates a duplicate domain name.
+
+ @param inName The domain name to duplicate.
+ @param inLower If true, uppercase letters in the duplicate are converted to lowercase.
+ @param outNamePtr Gets set to point to a dynamically allocated duplicate.
+ @param outNameLen Gets set to the length of the duplicate.
+
+ @discussion The duplicate domain name must be freed with free() when no longer needed.
+*/
+OSStatus DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen );
+
+#define DomainNameDup( IN_NAME, OUT_NAME, OUT_LEN ) DomainNameDupEx( IN_NAME, false, OUT_NAME, OUT_LEN )
+#define DomainNameDupLower( IN_NAME, OUT_NAME, OUT_LEN ) DomainNameDupEx( IN_NAME, true, OUT_NAME, OUT_LEN )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Compares two domain names in label format for case-insensitive equality.
+
+ @param inName1 Pointer to the first domain name.
+ @param inName2 Pointer to the second domain name.
+
+ @result If the domain names are equal, returns true, otherwise, returns false.
+*/
+Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Converts a domain name's textual representation to a domain name in label format.
+
+ @param outName Buffer to write the domain name in label format.
+ @param inString Textual representation of a domain name as a C string.
+ @param outEnd Gets set to point to the new end of the domain name if the append succeeded. (Optional)
+
+ @discussion The duplicate domain name must be freed with free() when no longer needed.
+*/
+OSStatus
+ DomainNameFromString(
+ uint8_t outName[ STATIC_PARAM kDomainNameLengthMax ],
+ const char * inString,
+ uint8_t ** outEnd );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Gets the next label in a domain name label sequence.
+
+ @param inLabel Pointer to the current label.
+
+ @result If the current label is a root label, returns NULL. Otherwise, returns the next label.
+*/
+STATIC_INLINE const uint8_t * DomainNameGetNextLabel( const uint8_t *inLabel )
+{
+ const int len = *inLabel;
+ return ( ( len == 0 ) ? NULL : &inLabel[ 1 + len ] );
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Computes the length of a domain name in label format.
+
+ @param inName The domain name.
+*/
+STATIC_INLINE size_t DomainNameLength( const uint8_t *inName )
+{
+ const uint8_t * label;
+ int len;
+
+ for( label = inName; ( len = *label ) != 0; label = &label[ 1 + len ] ) {}
+ return( (size_t)( label - inName ) + 1 );
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*! @brief Converts a domain name in label format to its textual representation as a C string.
+
+ @param inName Pointer to the domain name.
+ @param inLimit Pointer to not exceed while parsing a potentially truncated domain name. (Optional)
+ @param outString Buffer to write the C string.
+ @param outPtr Gets set to point to the end of the domain name. (Optional)
+*/
+OSStatus
+ DomainNameToString(
+ const uint8_t * inName,
+ const uint8_t * inLimit,
+ char outString[ STATIC_PARAM kDNSServiceMaxDomainName ],
+ const uint8_t ** outPtr );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DNSMessage_h
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.mDNSResponder.dnsproxy</key>
+ <true/>
+ <key>com.apple.mDNSResponder_Helper</key>
+ <true/>
+ <key>com.apple.security.network.client</key>
+ <true/>
+ <key>com.apple.security.network.server</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.SCPreferences-write-access</key>
+ <array>
+ <string>preferences.plist</string>
+ </array>
+</dict>
+</plist>
--- /dev/null
+/*
+ Copyright (c) 2016-2019 Apple Inc. All rights reserved.
+
+ dnssdutil is a command-line utility for testing the DNS-SD API.
+*/
+
+#include "DNSMessage.h"
+
+#include <CoreUtils/CoreUtils.h>
+#include <dns_sd.h>
+#include <dns_sd_private.h>
+
+#include CF_RUNTIME_HEADER
+
+#if( TARGET_OS_DARWIN )
+ #include <CFNetwork/CFHost.h>
+ #include <CoreFoundation/CoreFoundation.h>
+ #include <SystemConfiguration/SCPrivate.h>
+ #include <dnsinfo.h>
+ #include <libproc.h>
+ #include <netdb.h>
+ #include <pcap.h>
+ #include <spawn.h>
+ #include <sys/proc_info.h>
+ #include <xpc/xpc.h>
+#endif
+
+#if( TARGET_OS_POSIX )
+ #include <sys/resource.h>
+#endif
+
+#if( !defined( DNSSDUTIL_INCLUDE_DNSCRYPT ) )
+ #define DNSSDUTIL_INCLUDE_DNSCRYPT 0
+#endif
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+ #include "tweetnacl.h" // TweetNaCl from <https://tweetnacl.cr.yp.to/software.html>.
+#endif
+
+#if( !defined( MDNSRESPONDER_PROJECT ) )
+ #define MDNSRESPONDER_PROJECT 0
+#endif
+
+#if( MDNSRESPONDER_PROJECT )
+ #include <dns_services.h>
+ #include "mdns_private.h"
+#endif
+
+//===========================================================================================================================
+// Versioning
+//===========================================================================================================================
+
+#define kDNSSDUtilNumVersion NumVersionBuild( 2, 0, 0, kVersionStageBeta, 0 )
+
+#if( !MDNSRESPONDER_PROJECT && !defined( DNSSDUTIL_SOURCE_VERSION ) )
+ #define DNSSDUTIL_SOURCE_VERSION "0.0.0"
+#endif
+
+#define kDNSSDUtilIdentifier "com.apple.dnssdutil"
+
+//===========================================================================================================================
+// DNS-SD
+//===========================================================================================================================
+
+// DNS-SD API flag descriptors
+
+#define kDNSServiceFlagsDescriptors \
+ "\x00" "AutoTrigger\0" \
+ "\x01" "Add\0" \
+ "\x02" "Default\0" \
+ "\x03" "NoAutoRename\0" \
+ "\x04" "Shared\0" \
+ "\x05" "Unique\0" \
+ "\x06" "BrowseDomains\0" \
+ "\x07" "RegistrationDomains\0" \
+ "\x08" "LongLivedQuery\0" \
+ "\x09" "AllowRemoteQuery\0" \
+ "\x0A" "ForceMulticast\0" \
+ "\x0B" "KnownUnique\0" \
+ "\x0C" "ReturnIntermediates\0" \
+ "\x0D" "DenyConstrained\0" \
+ "\x0E" "ShareConnection\0" \
+ "\x0F" "SuppressUnusable\0" \
+ "\x10" "Timeout\0" \
+ "\x11" "IncludeP2P\0" \
+ "\x12" "WakeOnResolve\0" \
+ "\x13" "BackgroundTrafficClass\0" \
+ "\x14" "IncludeAWDL\0" \
+ "\x15" "Validate\0" \
+ "\x16" "UnicastResponse\0" \
+ "\x17" "ValidateOptional\0" \
+ "\x18" "WakeOnlyService\0" \
+ "\x19" "ThresholdOne\0" \
+ "\x1A" "ThresholdFinder\0" \
+ "\x1B" "DenyCellular\0" \
+ "\x1C" "ServiceIndex\0" \
+ "\x1D" "DenyExpensive\0" \
+ "\x1E" "PathEvaluationDone\0" \
+ "\x1F" "AllowExpiredAnswers\0" \
+ "\x00"
+
+#define DNSServiceFlagsToAddRmvStr( FLAGS ) ( ( (FLAGS) & kDNSServiceFlagsAdd ) ? "Add" : "Rmv" )
+
+#define kDNSServiceProtocolDescriptors \
+ "\x00" "IPv4\0" \
+ "\x01" "IPv6\0" \
+ "\x04" "UDP\0" \
+ "\x05" "TCP\0" \
+ "\x00"
+
+#define kBadDNSServiceRef ( (DNSServiceRef)(intptr_t) -1 )
+
+//===========================================================================================================================
+// DNS
+//===========================================================================================================================
+
+#define kDNSPort 53
+#define kDNSMaxUDPMessageSize 512
+#define kDNSMaxTCPMessageSize UINT16_MAX
+
+#define kDNSRecordDataLengthMax UINT16_MAX
+
+//===========================================================================================================================
+// mDNS
+//===========================================================================================================================
+
+#define kMDNSPort 5353
+
+#define kDefaultMDNSMessageID 0
+#define kDefaultMDNSQueryFlags 0
+
+#define kQClassUnicastResponseBit ( 1U << 15 )
+#define kRRClassCacheFlushBit ( 1U << 15 )
+
+// Recommended Resource Record TTL values. See <https://tools.ietf.org/html/rfc6762#section-10>.
+
+#define kMDNSRecordTTL_Host 120 // TTL for resource records related to a host name, e.g., A, AAAA, SRV, etc.
+#define kMDNSRecordTTL_Other 4500 // TTL for other resource records.
+
+// Maximum mDNS Message Size. See <https://tools.ietf.org/html/rfc6762#section-17>.
+
+#define kMDNSMessageSizeMax 8952 // 9000 B (Ethernet jumbo frame max size) - 40 B (IPv6 header) - 8 B (UDP header)
+
+#define kLocalStr "\x05" "local"
+#define kLocalLabel ( (const uint8_t *) kLocalStr )
+#define kLocalName ( (const uint8_t *) kLocalStr )
+#define kLocalNameLen sizeof( kLocalStr )
+
+//===========================================================================================================================
+// Test Address Blocks
+//===========================================================================================================================
+
+// IPv4 address block 203.0.113.0/24 (TEST-NET-3) is reserved for documentation. See <https://tools.ietf.org/html/rfc5737>.
+
+#define kDNSServerBaseAddrV4 UINT32_C( 0xCB007100 ) // 203.0.113.0/24
+
+// IPv6 address block 2001:db8::/32 is reserved for documentation. See <https://tools.ietf.org/html/rfc3849>.
+
+static const uint8_t kDNSServerBaseAddrV6[] =
+{
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 2001:db8:1::/120
+};
+
+static const uint8_t kMDNSReplierBaseAddrV6[] =
+{
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 2001:db8:2::/96
+};
+
+check_compile_time( sizeof( kDNSServerBaseAddrV6 ) == 16 );
+check_compile_time( sizeof( kMDNSReplierBaseAddrV6 ) == 16 );
+
+// Bad IPv4 and IPv6 Address Blocks
+// Used by the DNS server when it needs to respond with intentionally "bad" A/AAAA record data, i.e., IP addresses neither
+// in 203.0.113.0/24 nor 2001:db8:1::/120.
+
+#define kDNSServerBadBaseAddrV4 UINT32_C( 0x00000000 ) // 0.0.0.0/24
+
+static const uint8_t kDNSServerBadBaseAddrV6[] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 // ::ffff:0:0/120
+};
+
+check_compile_time( sizeof( kDNSServerBadBaseAddrV6 ) == 16 );
+
+//===========================================================================================================================
+// Misc.
+//===========================================================================================================================
+
+#define kLowerAlphaNumericCharSet "abcdefghijklmnopqrstuvwxyz0123456789"
+#define kLowerAlphaNumericCharSetSize sizeof_string( kLowerAlphaNumericCharSet )
+
+#if( !defined( kWhiteSpaceCharSet ) )
+ #define kWhiteSpaceCharSet "\t\n\v\f\r "
+#endif
+
+// Note: strcpy_literal() appears in CoreUtils code, but isn't currently defined in framework headers.
+
+#if( !defined( strcpy_literal ) )
+ #define strcpy_literal( DST, SRC ) memcpy( DST, SRC, sizeof( SRC ) )
+#endif
+
+#define _RandomStringExact( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, OUT_STRING ) \
+ RandomString( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, CHAR_COUNT, OUT_STRING )
+
+#define kNoSuchRecordStr "No Such Record"
+#define kNoSuchRecordAStr "No Such Record (A)"
+#define kNoSuchRecordAAAAStr "No Such Record (AAAA)"
+
+#define kRootLabel ( (const uint8_t *) "" )
+
+//===========================================================================================================================
+// Gerneral Command Options
+//===========================================================================================================================
+
+// Command option macros
+
+#define Command( NAME, CALLBACK, SUB_OPTIONS, SHORT_HELP, IS_NOTCOMMON ) \
+ CLI_COMMAND_EX( NAME, CALLBACK, SUB_OPTIONS, (IS_NOTCOMMON) ? kCLIOptionFlags_NotCommon : kCLIOptionFlags_None, \
+ (SHORT_HELP), NULL )
+
+#define kRequiredOptionSuffix " [REQUIRED]"
+
+#define MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
+ CLI_OPTION_MULTI_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
+
+#define MultiStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
+
+#define IntegerOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ CLI_OPTION_INTEGER_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+#define DoubleOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ CLI_OPTION_DOUBLE_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+#define BooleanOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP ) \
+ CLI_OPTION_BOOLEAN( (SHORT_CHAR), (LONG_NAME), (VAL_PTR), (SHORT_HELP), NULL )
+
+#define StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
+ CLI_OPTION_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
+
+#define StringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
+
+#define CFStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+ CLI_OPTION_CFSTRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, \
+ (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP, \
+ (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+// DNS-SD API flag options
+
+static int gDNSSDFlags = 0;
+static int gDNSSDFlag_AllowExpiredAnswers = false;
+static int gDNSSDFlag_BrowseDomains = false;
+static int gDNSSDFlag_DenyCellular = false;
+static int gDNSSDFlag_DenyConstrained = false;
+static int gDNSSDFlag_DenyExpensive = false;
+static int gDNSSDFlag_ForceMulticast = false;
+static int gDNSSDFlag_IncludeAWDL = false;
+static int gDNSSDFlag_KnownUnique = false;
+static int gDNSSDFlag_NoAutoRename = false;
+static int gDNSSDFlag_PathEvaluationDone = false;
+static int gDNSSDFlag_RegistrationDomains = false;
+static int gDNSSDFlag_ReturnIntermediates = false;
+static int gDNSSDFlag_Shared = false;
+static int gDNSSDFlag_SuppressUnusable = false;
+static int gDNSSDFlag_Timeout = false;
+static int gDNSSDFlag_UnicastResponse = false;
+static int gDNSSDFlag_Unique = false;
+static int gDNSSDFlag_WakeOnResolve = false;
+
+#define DNSSDFlagsOption() \
+ IntegerOption( 'f', "flags", &gDNSSDFlags, "flags", \
+ "DNSServiceFlags as an integer. This value is bitwise ORed with other single flag options.", false )
+
+#define DNSSDFlagOption( SHORT_CHAR, FLAG_NAME ) \
+ BooleanOption( SHORT_CHAR, # FLAG_NAME, &gDNSSDFlag_ ## FLAG_NAME, "Use kDNSServiceFlags" # FLAG_NAME "." )
+
+#define DNSSDFlagsOption_AllowExpiredAnswers() DNSSDFlagOption( 'X', AllowExpiredAnswers )
+#define DNSSDFlagsOption_DenyCellular() DNSSDFlagOption( 'C', DenyCellular )
+#define DNSSDFlagsOption_DenyConstrained() DNSSDFlagOption( 'R', DenyConstrained)
+#define DNSSDFlagsOption_DenyExpensive() DNSSDFlagOption( 'E', DenyExpensive )
+#define DNSSDFlagsOption_ForceMulticast() DNSSDFlagOption( 'M', ForceMulticast )
+#define DNSSDFlagsOption_IncludeAWDL() DNSSDFlagOption( 'A', IncludeAWDL )
+#define DNSSDFlagsOption_KnownUnique() DNSSDFlagOption( 'K', KnownUnique )
+#define DNSSDFlagsOption_NoAutoRename() DNSSDFlagOption( 'N', NoAutoRename )
+#define DNSSDFlagsOption_PathEvalDone() DNSSDFlagOption( 'P', PathEvaluationDone )
+#define DNSSDFlagsOption_ReturnIntermediates() DNSSDFlagOption( 'I', ReturnIntermediates )
+#define DNSSDFlagsOption_Shared() DNSSDFlagOption( 'S', Shared )
+#define DNSSDFlagsOption_SuppressUnusable() DNSSDFlagOption( 'S', SuppressUnusable )
+#define DNSSDFlagsOption_Timeout() DNSSDFlagOption( 'T', Timeout )
+#define DNSSDFlagsOption_UnicastResponse() DNSSDFlagOption( 'U', UnicastResponse )
+#define DNSSDFlagsOption_Unique() DNSSDFlagOption( 'U', Unique )
+#define DNSSDFlagsOption_WakeOnResolve() DNSSDFlagOption( 'W', WakeOnResolve )
+
+// Interface option
+
+static const char * gInterface = NULL;
+
+#define InterfaceOption() \
+ StringOption( 'i', "interface", &gInterface, "interface", \
+ "Network interface by name or index. Use index -1 for local-only.", false )
+
+// Connection options
+
+#define kConnectionArg_Normal ""
+#define kConnectionArgPrefix_PID "pid:"
+#define kConnectionArgPrefix_UUID "uuid:"
+
+static const char * gConnectionOpt = kConnectionArg_Normal;
+
+#define ConnectionOptions() \
+ { kCLIOptionType_String, 0, "connection", &gConnectionOpt, NULL, (intptr_t) kConnectionArg_Normal, "type", \
+ kCLIOptionFlags_OptionalArgument, NULL, NULL, NULL, NULL, \
+ "Specifies the type of main connection to use. See " kConnectionSection_Name " below.", NULL }
+
+#define kConnectionSection_Name "Connection Option"
+#define kConnectionSection_Text \
+ "The default behavior is to create a main connection with DNSServiceCreateConnection() and perform operations on\n" \
+ "the main connection using the kDNSServiceFlagsShareConnection flag. This behavior can be explicitly invoked by\n" \
+ "specifying the connection option without an argument, i.e.,\n" \
+ "\n" \
+ " --connection\n" \
+ "\n" \
+ "To instead use a delegate connection created with DNSServiceCreateDelegateConnection(), use\n" \
+ "\n" \
+ " --connection=pid:<PID>\n" \
+ "\n" \
+ "to specify the delegator by PID, or use\n" \
+ "\n" \
+ " --connection=uuid:<UUID>\n" \
+ "\n" \
+ "to specify the delegator by UUID.\n" \
+ "\n" \
+ "To not use a main connection at all, but instead perform operations on their own implicit connections, use\n" \
+ "\n" \
+ " --no-connection\n"
+
+#define ConnectionSection() CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
+
+// Help text for record data options
+
+#define kRDataArgPrefix_Domain "domain:"
+#define kRDataArgPrefix_File "file:"
+#define kRDataArgPrefix_HexString "hex:"
+#define kRDataArgPrefix_IPv4 "ipv4:"
+#define kRDataArgPrefix_IPv6 "ipv6:"
+#define kRDataArgPrefix_SRV "srv:"
+#define kRDataArgPrefix_String "string:"
+#define kRDataArgPrefix_TXT "txt:"
+
+#define kRecordDataSection_Name "Record Data Arguments"
+#define kRecordDataSection_Text \
+ "A record data argument is specified in one of the following formats:\n" \
+ "\n" \
+ "Format Syntax Example\n" \
+ "Domain name domain:<domain name> domain:demo._test._tcp.local\n" \
+ "File containing record data file:<file path> file:/path/to/binary-rdata-file\n" \
+ "Hexadecimal string hex:<hex string> hex:c0000201 or hex:'C0 00 02 01'\n" \
+ "IPv4 address ipv4:<IPv4 address> ipv4:192.0.2.1\n" \
+ "IPv6 address ipv6:<IPv6 address> ipv6:2001:db8::1\n" \
+ "SRV record srv:<priority>,<weight>,<port>,<target> srv:0,0,64206,example.local\n" \
+ "String string:<string> string:'\\x09color=red'\n" \
+ "TXT record strings txt:<comma-delimited strings> txt:'vers=1.0,lang=en\\,es\\,fr,passreq'\n" \
+ "\n" \
+ "Note: The string format converts each \\xHH escape sequence into the octet represented by the HH hex digit pair.\n"
+
+#define RecordDataSection() CLI_SECTION( kRecordDataSection_Name, kRecordDataSection_Text )
+
+//===========================================================================================================================
+// Output Formatting
+//===========================================================================================================================
+
+#define kOutputFormatStr_JSON "json"
+#define kOutputFormatStr_XML "xml"
+#define kOutputFormatStr_Binary "binary"
+
+typedef enum
+{
+ kOutputFormatType_Invalid = 0,
+ kOutputFormatType_JSON = 1,
+ kOutputFormatType_XML = 2,
+ kOutputFormatType_Binary = 3
+
+} OutputFormatType;
+
+#define FormatOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP, IS_REQUIRED ) \
+ StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, "format", SHORT_HELP, IS_REQUIRED, \
+ "\n" \
+ "Use '" kOutputFormatStr_JSON "' for JavaScript Object Notation (JSON).\n" \
+ "Use '" kOutputFormatStr_XML "' for property list XML version 1.0.\n" \
+ "Use '" kOutputFormatStr_Binary "' for property list binary version 1.0.\n" \
+ "\n" \
+ )
+
+//===========================================================================================================================
+// Browse Command Options
+//===========================================================================================================================
+
+static char ** gBrowse_ServiceTypes = NULL;
+static size_t gBrowse_ServiceTypesCount = 0;
+static const char * gBrowse_Domain = NULL;
+static int gBrowse_DoResolve = false;
+static int gBrowse_QueryTXT = false;
+static int gBrowse_TimeLimitSecs = 0;
+
+static CLIOption kBrowseOpts[] =
+{
+ InterfaceOption(),
+ MultiStringOption( 't', "type", &gBrowse_ServiceTypes, &gBrowse_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\".", true ),
+ StringOption( 'd', "domain", &gBrowse_Domain, "domain", "Domain in which to browse for the service type(s).", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 0 , "resolve", &gBrowse_DoResolve, "Resolve service instances." ),
+ BooleanOption( 0 , "queryTXT", &gBrowse_QueryTXT, "Query TXT records of service instances." ),
+ IntegerOption( 'l', "timeLimit", &gBrowse_TimeLimitSecs, "seconds", "Specifies the max duration of the browse operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// GetAddrInfo Command Options
+//===========================================================================================================================
+
+static const char * gGetAddrInfo_Name = NULL;
+static int gGetAddrInfo_ProtocolIPv4 = false;
+static int gGetAddrInfo_ProtocolIPv6 = false;
+static int gGetAddrInfo_OneShot = false;
+static int gGetAddrInfo_TimeLimitSecs = 0;
+
+static CLIOption kGetAddrInfoOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gGetAddrInfo_Name, "domain name", "Domain name to resolve.", true ),
+ BooleanOption( 0 , "ipv4", &gGetAddrInfo_ProtocolIPv4, "Use kDNSServiceProtocol_IPv4." ),
+ BooleanOption( 0 , "ipv6", &gGetAddrInfo_ProtocolIPv6, "Use kDNSServiceProtocol_IPv6." ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_AllowExpiredAnswers(),
+ DNSSDFlagsOption_DenyCellular(),
+ DNSSDFlagsOption_DenyConstrained(),
+ DNSSDFlagsOption_DenyExpensive(),
+ DNSSDFlagsOption_PathEvalDone(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+ DNSSDFlagsOption_Timeout(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 'o', "oneshot", &gGetAddrInfo_OneShot, "Finish after first set of results." ),
+ IntegerOption( 'l', "timeLimit", &gGetAddrInfo_TimeLimitSecs, "seconds", "Maximum duration of the GetAddrInfo operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// QueryRecord Command Options
+//===========================================================================================================================
+
+static const char * gQueryRecord_Name = NULL;
+static const char * gQueryRecord_Type = NULL;
+static int gQueryRecord_OneShot = false;
+static int gQueryRecord_TimeLimitSecs = 0;
+static int gQueryRecord_RawRData = false;
+
+static CLIOption kQueryRecordOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gQueryRecord_Name, "domain name", "Full domain name of record to query.", true ),
+ StringOption( 't', "type", &gQueryRecord_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_AllowExpiredAnswers(),
+ DNSSDFlagsOption_DenyCellular(),
+ DNSSDFlagsOption_DenyConstrained(),
+ DNSSDFlagsOption_DenyExpensive(),
+ DNSSDFlagsOption_ForceMulticast(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_PathEvalDone(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+ DNSSDFlagsOption_Timeout(),
+ DNSSDFlagsOption_UnicastResponse(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 'o', "oneshot", &gQueryRecord_OneShot, "Finish after first set of results." ),
+ IntegerOption( 'l', "timeLimit", &gQueryRecord_TimeLimitSecs, "seconds", "Maximum duration of the query record operation. Use '0' for no time limit.", false ),
+ BooleanOption( 0 , "raw", &gQueryRecord_RawRData, "Show record data as a hexdump." ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Register Command Options
+//===========================================================================================================================
+
+static const char * gRegister_Name = NULL;
+static const char * gRegister_Type = NULL;
+static const char * gRegister_Domain = NULL;
+static int gRegister_Port = 0;
+static const char * gRegister_TXT = NULL;
+static int gRegister_LifetimeMs = -1;
+static const char ** gAddRecord_Types = NULL;
+static size_t gAddRecord_TypesCount = 0;
+static const char ** gAddRecord_Data = NULL;
+static size_t gAddRecord_DataCount = 0;
+static const char ** gAddRecord_TTLs = NULL;
+static size_t gAddRecord_TTLsCount = 0;
+static const char * gUpdateRecord_Data = NULL;
+static int gUpdateRecord_DelayMs = 0;
+static int gUpdateRecord_TTL = 0;
+
+static CLIOption kRegisterOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gRegister_Name, "service name", "Name of service.", false ),
+ StringOption( 't', "type", &gRegister_Type, "service type", "Service type, e.g., \"_ssh._tcp\".", true ),
+ StringOption( 'd', "domain", &gRegister_Domain, "domain", "Domain in which to advertise the service.", false ),
+ IntegerOption( 'p', "port", &gRegister_Port, "port number", "Service's port number.", true ),
+ StringOption( 0 , "txt", &gRegister_TXT, "record data", "The TXT record data. See " kRecordDataSection_Name " below.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_KnownUnique(),
+ DNSSDFlagsOption_NoAutoRename(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 'l', "lifetime", &gRegister_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
+
+ CLI_OPTION_GROUP( "Options for updating the registered service's primary TXT record with DNSServiceUpdateRecord()\n" ),
+ StringOption( 0 , "updateData", &gUpdateRecord_Data, "record data", "Record data for the record update. See " kRecordDataSection_Name " below.", false ),
+ IntegerOption( 0 , "updateDelay", &gUpdateRecord_DelayMs, "ms", "Number of milliseconds after registration to wait before record update.", false ),
+ IntegerOption( 0 , "updateTTL", &gUpdateRecord_TTL, "seconds", "Time-to-live of the updated record.", false ),
+
+ CLI_OPTION_GROUP( "Options for adding extra record(s) to the registered service with DNSServiceAddRecord()\n" ),
+ MultiStringOption( 0 , "addType", &gAddRecord_Types, &gAddRecord_TypesCount, "record type", "Type of additional record by name (e.g., TXT, SRV, etc.) or number.", false ),
+ MultiStringOptionEx( 0 , "addData", &gAddRecord_Data, &gAddRecord_DataCount, "record data", "Additional record's data. See " kRecordDataSection_Name " below.", false, NULL ),
+ MultiStringOption( 0 , "addTTL", &gAddRecord_TTLs, &gAddRecord_TTLsCount, "seconds", "Time-to-live of additional record in seconds. Use '0' for default.", false ),
+
+ RecordDataSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// RegisterRecord Command Options
+//===========================================================================================================================
+
+static const char * gRegisterRecord_Name = NULL;
+static const char * gRegisterRecord_Type = NULL;
+static const char * gRegisterRecord_Data = NULL;
+static int gRegisterRecord_TTL = 0;
+static int gRegisterRecord_LifetimeMs = -1;
+static const char * gRegisterRecord_UpdateData = NULL;
+static int gRegisterRecord_UpdateDelayMs = 0;
+static int gRegisterRecord_UpdateTTL = 0;
+
+static CLIOption kRegisterRecordOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gRegisterRecord_Name, "record name", "Fully qualified domain name of record.", true ),
+ StringOption( 't', "type", &gRegisterRecord_Type, "record type", "Record type by name (e.g., TXT, PTR, A) or number.", true ),
+ StringOption( 'd', "data", &gRegisterRecord_Data, "record data", "The record data. See " kRecordDataSection_Name " below.", false ),
+ IntegerOption( 0 , "ttl", &gRegisterRecord_TTL, "seconds", "Time-to-live in seconds. Use '0' for default.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_KnownUnique(),
+ DNSSDFlagsOption_Shared(),
+ DNSSDFlagsOption_Unique(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 'l', "lifetime", &gRegisterRecord_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
+
+ CLI_OPTION_GROUP( "Options for updating the registered record with DNSServiceUpdateRecord()\n" ),
+ StringOption( 0 , "updateData", &gRegisterRecord_UpdateData, "record data", "Record data for the record update.", false ),
+ IntegerOption( 0 , "updateDelay", &gRegisterRecord_UpdateDelayMs, "ms", "Number of milliseconds after registration to wait before record update.", false ),
+ IntegerOption( 0 , "updateTTL", &gRegisterRecord_UpdateTTL, "seconds", "Time-to-live of the updated record.", false ),
+
+ RecordDataSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Resolve Command Options
+//===========================================================================================================================
+
+static char * gResolve_Name = NULL;
+static char * gResolve_Type = NULL;
+static char * gResolve_Domain = NULL;
+static int gResolve_TimeLimitSecs = 0;
+
+static CLIOption kResolveOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gResolve_Name, "service name", "Name of the service instance to resolve.", true ),
+ StringOption( 't', "type", &gResolve_Type, "service type", "Type of the service instance to resolve.", true ),
+ StringOption( 'd', "domain", &gResolve_Domain, "domain", "Domain of the service instance to resolve.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_ForceMulticast(),
+ DNSSDFlagsOption_IncludeAWDL(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_WakeOnResolve(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ IntegerOption( 'l', "timeLimit", &gResolve_TimeLimitSecs, "seconds", "Maximum duration of the resolve operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Reconfirm Command Options
+//===========================================================================================================================
+
+static const char * gReconfirmRecord_Name = NULL;
+static const char * gReconfirmRecord_Type = NULL;
+static const char * gReconfirmRecord_Class = NULL;
+static const char * gReconfirmRecord_Data = NULL;
+
+static CLIOption kReconfirmOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'n', "name", &gReconfirmRecord_Name, "record name", "Full name of the record to reconfirm.", true ),
+ StringOption( 't', "type", &gReconfirmRecord_Type, "record type", "Type of the record to reconfirm.", true ),
+ StringOption( 'c', "class", &gReconfirmRecord_Class, "record class", "Class of the record to reconfirm. Default class is IN.", false ),
+ StringOption( 'd', "data", &gReconfirmRecord_Data, "record data", "The record data. See " kRecordDataSection_Name " below.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+
+ RecordDataSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// getaddrinfo-POSIX Command Options
+//===========================================================================================================================
+
+static const char * gGAIPOSIX_HostName = NULL;
+static const char * gGAIPOSIX_ServName = NULL;
+static const char * gGAIPOSIX_Family = NULL;
+static int gGAIPOSIXFlag_AddrConfig = false;
+static int gGAIPOSIXFlag_All = false;
+static int gGAIPOSIXFlag_CanonName = false;
+static int gGAIPOSIXFlag_NumericHost = false;
+static int gGAIPOSIXFlag_NumericServ = false;
+static int gGAIPOSIXFlag_Passive = false;
+static int gGAIPOSIXFlag_V4Mapped = false;
+#if( defined( AI_V4MAPPED_CFG ) )
+static int gGAIPOSIXFlag_V4MappedCFG = false;
+#endif
+#if( defined( AI_DEFAULT ) )
+static int gGAIPOSIXFlag_Default = false;
+#endif
+#if( defined( AI_UNUSABLE ) )
+static int gGAIPOSIXFlag_Unusable = false;
+#endif
+
+static CLIOption kGetAddrInfoPOSIXOpts[] =
+{
+ StringOption( 'n', "hostname", &gGAIPOSIX_HostName, "hostname", "Domain name to resolve or an IPv4 or IPv6 address.", true ),
+ StringOption( 's', "servname", &gGAIPOSIX_ServName, "servname", "Port number in decimal or service name from services(5).", false ),
+
+ CLI_OPTION_GROUP( "Hints" ),
+ StringOptionEx( 'f', "family", &gGAIPOSIX_Family, "address family", "Address family to use for hints ai_family field.", false,
+ "\n"
+ "Possible address family values are 'inet' for AF_INET, 'inet6' for AF_INET6, or 'unspec' for AF_UNSPEC. If no\n"
+ "address family is specified, then AF_UNSPEC is used.\n"
+ "\n" ),
+ BooleanOption( 0 , "flag-addrconfig", &gGAIPOSIXFlag_AddrConfig, "In hints ai_flags field, set AI_ADDRCONFIG." ),
+ BooleanOption( 0 , "flag-all", &gGAIPOSIXFlag_All, "In hints ai_flags field, set AI_ALL." ),
+ BooleanOption( 0 , "flag-canonname", &gGAIPOSIXFlag_CanonName, "In hints ai_flags field, set AI_CANONNAME." ),
+ BooleanOption( 0 , "flag-numerichost", &gGAIPOSIXFlag_NumericHost, "In hints ai_flags field, set AI_NUMERICHOST." ),
+ BooleanOption( 0 , "flag-numericserv", &gGAIPOSIXFlag_NumericServ, "In hints ai_flags field, set AI_NUMERICSERV." ),
+ BooleanOption( 0 , "flag-passive", &gGAIPOSIXFlag_Passive, "In hints ai_flags field, set AI_PASSIVE." ),
+ BooleanOption( 0 , "flag-v4mapped", &gGAIPOSIXFlag_V4Mapped, "In hints ai_flags field, set AI_V4MAPPED." ),
+#if( defined( AI_V4MAPPED_CFG ) )
+ BooleanOption( 0 , "flag-v4mappedcfg", &gGAIPOSIXFlag_V4MappedCFG, "In hints ai_flags field, set AI_V4MAPPED_CFG." ),
+#endif
+#if( defined( AI_DEFAULT ) )
+ BooleanOption( 0 , "flag-default", &gGAIPOSIXFlag_Default, "In hints ai_flags field, set AI_DEFAULT." ),
+#endif
+#if( defined( AI_UNUSABLE ) )
+ BooleanOption( 0 , "flag-unusable", &gGAIPOSIXFlag_Unusable, "In hints ai_flags field, set AI_UNUSABLE." ),
+#endif
+
+ CLI_SECTION( "Notes", "See getaddrinfo(3) man page for more details.\n" ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// ReverseLookup Command Options
+//===========================================================================================================================
+
+static const char * gReverseLookup_IPAddr = NULL;
+static int gReverseLookup_OneShot = false;
+static int gReverseLookup_TimeLimitSecs = 0;
+
+static CLIOption kReverseLookupOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'a', "address", &gReverseLookup_IPAddr, "IP address", "IPv4 or IPv6 address for which to perform a reverse IP lookup.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+ DNSSDFlagsOption_ForceMulticast(),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+ BooleanOption( 'o', "oneshot", &gReverseLookup_OneShot, "Finish after first set of results." ),
+ IntegerOption( 'l', "timeLimit", &gReverseLookup_TimeLimitSecs, "seconds", "Specifies the max duration of the query record operation. Use '0' for no time limit.", false ),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// PortMapping Command Options
+//===========================================================================================================================
+
+static int gPortMapping_ProtocolTCP = false;
+static int gPortMapping_ProtocolUDP = false;
+static int gPortMapping_InternalPort = 0;
+static int gPortMapping_ExternalPort = 0;
+static int gPortMapping_TTL = 0;
+
+static CLIOption kPortMappingOpts[] =
+{
+ InterfaceOption(),
+ BooleanOption( 0, "tcp", &gPortMapping_ProtocolTCP, "Use kDNSServiceProtocol_TCP." ),
+ BooleanOption( 0, "udp", &gPortMapping_ProtocolUDP, "Use kDNSServiceProtocol_UDP." ),
+ IntegerOption( 0, "internalPort", &gPortMapping_InternalPort, "port number", "Internal port.", false ),
+ IntegerOption( 0, "externalPort", &gPortMapping_ExternalPort, "port number", "Requested external port. Use '0' for any external port.", false ),
+ IntegerOption( 0, "ttl", &gPortMapping_TTL, "seconds", "Requested TTL (renewal period) in seconds. Use '0' for a default value.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ ConnectionOptions(),
+
+ ConnectionSection(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// BrowseAll Command Options
+//===========================================================================================================================
+
+static const char * gBrowseAll_Domain = NULL;
+static const char ** gBrowseAll_ServiceTypes = NULL;
+static size_t gBrowseAll_ServiceTypesCount = 0;
+static int gBrowseAll_BrowseTimeSecs = 5;
+static int gBrowseAll_ConnectTimeout = 0;
+
+static CLIOption kBrowseAllOpts[] =
+{
+ InterfaceOption(),
+ StringOption( 'd', "domain", &gBrowseAll_Domain, "domain", "Domain in which to browse for the service.", false ),
+ MultiStringOption( 't', "type", &gBrowseAll_ServiceTypes, &gBrowseAll_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\". All services are browsed for if none is specified.", false ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption_IncludeAWDL(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 'b', "browseTime", &gBrowseAll_BrowseTimeSecs, "seconds", "Amount of time to spend browsing in seconds. (default: 5)", false ),
+ IntegerOption( 'c', "connectTimeout", &gBrowseAll_ConnectTimeout, "seconds", "Timeout for connection attempts. If <= 0, no connections are attempted. (default: 0)", false ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// GetNameInfo Command Options
+//===========================================================================================================================
+
+static void GetNameInfoCmd( void );
+
+static char * gGetNameInfo_IPAddress = NULL;
+static int gGetNameInfoFlag_DGram = false;
+static int gGetNameInfoFlag_NameReqd = false;
+static int gGetNameInfoFlag_NoFQDN = false;
+static int gGetNameInfoFlag_NumericHost = false;
+static int gGetNameInfoFlag_NumericScope = false;
+static int gGetNameInfoFlag_NumericServ = false;
+
+static CLIOption kGetNameInfoOpts[] =
+{
+ StringOption( 'a', "address", &gGetNameInfo_IPAddress, "IP address", "IPv4 or IPv6 address to use in sockaddr structure.", true ),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ BooleanOption( 0 , "flag-dgram", &gGetNameInfoFlag_DGram, "Use NI_DGRAM flag." ),
+ BooleanOption( 0 , "flag-namereqd", &gGetNameInfoFlag_NameReqd, "Use NI_NAMEREQD flag." ),
+ BooleanOption( 0 , "flag-nofqdn", &gGetNameInfoFlag_NoFQDN, "Use NI_NOFQDN flag." ),
+ BooleanOption( 0 , "flag-numerichost", &gGetNameInfoFlag_NumericHost, "Use NI_NUMERICHOST flag." ),
+ BooleanOption( 0 , "flag-numericscope", &gGetNameInfoFlag_NumericScope, "Use NI_NUMERICSCOPE flag." ),
+ BooleanOption( 0 , "flag-numericserv", &gGetNameInfoFlag_NumericServ, "Use NI_NUMERICSERV flag." ),
+
+ CLI_SECTION( "Notes", "See getnameinfo(3) man page for more details.\n" ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// GetAddrInfoStress Command Options
+//===========================================================================================================================
+
+static int gGAIStress_TestDurationSecs = 0;
+static int gGAIStress_ConnectionCount = 0;
+static int gGAIStress_DurationMinMs = 0;
+static int gGAIStress_DurationMaxMs = 0;
+static int gGAIStress_RequestCountMax = 0;
+
+static CLIOption kGetAddrInfoStressOpts[] =
+{
+ InterfaceOption(),
+
+ CLI_OPTION_GROUP( "Flags" ),
+ DNSSDFlagsOption_ReturnIntermediates(),
+ DNSSDFlagsOption_SuppressUnusable(),
+
+ CLI_OPTION_GROUP( "Operation" ),
+ IntegerOption( 0, "testDuration", &gGAIStress_TestDurationSecs, "seconds", "Stress test duration in seconds. Use '0' for forever.", false ),
+ IntegerOption( 0, "connectionCount", &gGAIStress_ConnectionCount, "integer", "Number of simultaneous DNS-SD connections.", true ),
+ IntegerOption( 0, "requestDurationMin", &gGAIStress_DurationMinMs, "ms", "Minimum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
+ IntegerOption( 0, "requestDurationMax", &gGAIStress_DurationMaxMs, "ms", "Maximum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
+ IntegerOption( 0, "consecutiveRequestMax", &gGAIStress_RequestCountMax, "integer", "Maximum number of requests on a connection before restarting it.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// DNSQuery Command Options
+//===========================================================================================================================
+
+static char * gDNSQuery_Name = NULL;
+static char * gDNSQuery_Type = "A";
+static char * gDNSQuery_Server = NULL;
+static int gDNSQuery_TimeLimitSecs = 5;
+static int gDNSQuery_UseTCP = false;
+static int gDNSQuery_Flags = kDNSHeaderFlag_RecursionDesired;
+static int gDNSQuery_RawRData = false;
+static int gDNSQuery_Verbose = false;
+
+#if( TARGET_OS_DARWIN )
+ #define kDNSQueryServerOptionIsRequired false
+#else
+ #define kDNSQueryServerOptionIsRequired true
+#endif
+
+static CLIOption kDNSQueryOpts[] =
+{
+ StringOption( 'n', "name", &gDNSQuery_Name, "name", "Question name (QNAME) to put in DNS query message.", true ),
+ StringOption( 't', "type", &gDNSQuery_Type, "type", "Question type (QTYPE) to put in DNS query message. Default value is 'A'.", false ),
+ StringOption( 's', "server", &gDNSQuery_Server, "IP address", "DNS server's IPv4 or IPv6 address.", kDNSQueryServerOptionIsRequired ),
+ IntegerOption( 'l', "timeLimit", &gDNSQuery_TimeLimitSecs, "seconds", "Specifies query time limit. Use '-1' for no limit and '0' to exit immediately after sending.", false ),
+ BooleanOption( 0 , "tcp", &gDNSQuery_UseTCP, "Send the DNS query via TCP instead of UDP." ),
+ IntegerOption( 'f', "flags", &gDNSQuery_Flags, "flags", "16-bit value for DNS header flags/codes field. Default value is 0x0100 (Recursion Desired).", false ),
+ BooleanOption( 0 , "raw", &gDNSQuery_RawRData, "Present record data as a hexdump." ),
+ BooleanOption( 'v', "verbose", &gDNSQuery_Verbose, "Prints the DNS message to be sent to the server." ),
+ CLI_OPTION_END()
+};
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+//===========================================================================================================================
+// DNSCrypt Command Options
+//===========================================================================================================================
+
+static char * gDNSCrypt_ProviderName = NULL;
+static char * gDNSCrypt_ProviderKey = NULL;
+static char * gDNSCrypt_Name = NULL;
+static char * gDNSCrypt_Type = NULL;
+static char * gDNSCrypt_Server = NULL;
+static int gDNSCrypt_TimeLimitSecs = 5;
+static int gDNSCrypt_RawRData = false;
+static int gDNSCrypt_Verbose = false;
+
+static CLIOption kDNSCryptOpts[] =
+{
+ StringOption( 'p', "providerName", &gDNSCrypt_ProviderName, "name", "The DNSCrypt provider name.", true ),
+ StringOption( 'k', "providerKey", &gDNSCrypt_ProviderKey, "hex string", "The DNSCrypt provider's public signing key.", true ),
+ StringOption( 'n', "name", &gDNSCrypt_Name, "name", "Question name (QNAME) to put in DNS query message.", true ),
+ StringOption( 't', "type", &gDNSCrypt_Type, "type", "Question type (QTYPE) to put in DNS query message.", true ),
+ StringOption( 's', "server", &gDNSCrypt_Server, "IP address", "DNS server's IPv4 or IPv6 address.", true ),
+ IntegerOption( 'l', "timeLimit", &gDNSCrypt_TimeLimitSecs, "seconds", "Specifies query time limit. Use '-1' for no time limit and '0' to exit immediately after sending.", false ),
+ BooleanOption( 0 , "raw", &gDNSCrypt_RawRData, "Present record data as a hexdump." ),
+ BooleanOption( 'v', "verbose", &gDNSCrypt_Verbose, "Prints the DNS message to be sent to the server." ),
+ CLI_OPTION_END()
+};
+#endif
+
+//===========================================================================================================================
+// MDNSQuery Command Options
+//===========================================================================================================================
+
+static char * gMDNSQuery_Name = NULL;
+static char * gMDNSQuery_Type = NULL;
+static int gMDNSQuery_SourcePort = 0;
+static int gMDNSQuery_IsQU = false;
+static int gMDNSQuery_RawRData = false;
+static int gMDNSQuery_UseIPv4 = false;
+static int gMDNSQuery_UseIPv6 = false;
+static int gMDNSQuery_AllResponses = false;
+static int gMDNSQuery_ReceiveSecs = 1;
+
+static CLIOption kMDNSQueryOpts[] =
+{
+ StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+ StringOption( 'n', "name", &gMDNSQuery_Name, "name", "Question name (QNAME) to put in mDNS message.", true ),
+ StringOption( 't', "type", &gMDNSQuery_Type, "type", "Question type (QTYPE) to put in mDNS message.", true ),
+ IntegerOption( 'p', "sourcePort", &gMDNSQuery_SourcePort, "port number", "UDP source port to use when sending mDNS messages. Default is 5353 for QM questions.", false ),
+ BooleanOption( 'u', "QU", &gMDNSQuery_IsQU, "Set the unicast-response bit, i.e., send a QU question." ),
+ BooleanOption( 0 , "raw", &gMDNSQuery_RawRData, "Present record data as a hexdump." ),
+ BooleanOption( 0 , "ipv4", &gMDNSQuery_UseIPv4, "Use IPv4." ),
+ BooleanOption( 0 , "ipv6", &gMDNSQuery_UseIPv6, "Use IPv6." ),
+ BooleanOption( 'a', "allResponses", &gMDNSQuery_AllResponses, "Print all received mDNS messages, not just those containing answers." ),
+ IntegerOption( 'r', "receiveTime", &gMDNSQuery_ReceiveSecs, "seconds", "Amount of time to spend receiving messages after the query is sent. The default is one second. Use -1 for unlimited time.", false ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// MDNSCollider Command Options
+//===========================================================================================================================
+
+#define kMDNSColliderProgramSection_Intro \
+ "Programs dictate when the collider sends out unsolicited response messages for its record and how the collider\n" \
+ "ought to react to probe queries that match its record's name, if at all.\n" \
+ "\n" \
+ "For example, suppose that the goal is to cause a specific unique record in the verified state to be renamed.\n" \
+ "The collider should be invoked such that its record's name is equal to that of the record being targeted. Also,\n" \
+ "the record's type and data should be such that no record with that name, type, and data combination currently\n" \
+ "exists. If the mDNS responder that owns the record follows sections 8.1 and 9 of RFC 6762, then the goal can be\n" \
+ "accomplished with the following program:\n" \
+ "\n" \
+ " probes 3r; send; wait 5000\n" \
+ "\n" \
+ "The first command, 'probes 3r', tells the collider to respond to the next three probe queries that match its\n" \
+ "record's name. The second command, makes the collider send an unsolicited response message that contains its\n" \
+ "record in the answer section. The third command makes the collider wait for five seconds before exiting, which\n" \
+ "is more than enough time for the collider to respond to probe queries.\n" \
+ "\n" \
+ "The send command will cause the targeted record to go into the probing state per section 9 since the collider's\n" \
+ "record conflicts with target record. Per the probes command, the subsequent probe query sent during the probing\n" \
+ "state will be answered by the collider, which will cause the record to be renamed per section 8.1.\n"
+
+#define kMDNSColliderProgramSection_Probes \
+ "The probes command defines how the collider ought to react to probe queries that match its record's name.\n" \
+ "\n" \
+ "Usage: probes [<action-string>]\n" \
+ "\n" \
+ "The syntax for an action-string is\n" \
+ "\n" \
+ " <action-string> ::= <action> | <action-string> \"-\" <action>\n" \
+ " <action> ::= [<repeat-count>] <action-code>\n" \
+ " <repeat-count> ::= \"1\" | \"2\" | ... | \"10\"\n" \
+ " <action-code> ::= \"n\" | \"r\" | \"u\" | \"m\" | \"p\"\n" \
+ "\n" \
+ "An expanded action-string is defined as\n" \
+ "\n" \
+ " <expanded-action-string> ::= <action-code> | <expanded-action-string> \"-\" <action-code>\n" \
+ "\n" \
+ "The action-string argument is converted into an expanded-action-string by expanding each action with a\n" \
+ "repeat-count into an expanded-action-string consisting of exactly <repeat-count> <action-code>s. For example,\n" \
+ "2n-r expands to n-n-r. Action-strings that expand to expanded-action-strings with more than 10 action-codes\n" \
+ "are not allowed.\n" \
+ "\n" \
+ "When the probes command is executed, it does two things. Firstly, it resets to zero the collider's count of\n" \
+ "probe queries that match its record's name. Secondly, it defines how the collider ought to react to such probe\n" \
+ "queries based on the action-string argument. Specifically, the nth action-code in the expanded version of the\n" \
+ "action-string argument defines how the collider ought to react to the nth received probe query:\n" \
+ "\n" \
+ " Code Action\n" \
+ " ---- ------\n" \
+ " n Do nothing.\n" \
+ " r Respond to the probe query.\n" \
+ " u Respond to the probe query via unicast.\n" \
+ " m Respond to the probe query via multicast.\n" \
+ " p Multicast own probe query. (Useful for causing simultaneous probe scenarios.)\n" \
+ "\n" \
+ "Note: If no action is defined for a received probe query, then the collider does nothing, i.e., it doesn't send\n" \
+ "a response nor does it multicast its own probe query.\n"
+
+#define kMDNSColliderProgramSection_Send \
+ "The send command multicasts an unsolicited mDNS response containing the collider's record in the answer\n" \
+ "section, which can be used to force unique records with the same record name into the probing state.\n" \
+ "\n" \
+ "Usage: send\n"
+
+#define kMDNSColliderProgramSection_Wait \
+ "The wait command pauses program execution for the interval of time specified by its argument.\n" \
+ "\n" \
+ "Usage: wait <milliseconds>\n"
+
+#define kMDNSColliderProgramSection_Loop \
+ "The loop command starts a counting loop. The done statement marks the end of the loop body. The loop command's\n" \
+ "argument specifies the number of loop iterations. Note: Loop nesting is supported up to a depth of 16.\n" \
+ "\n" \
+ "Usage: loop <non-zero count>; ... ; done\n" \
+ "\n" \
+ "For example, the following program sends three unsolicited responses at an approximate rate of one per second:\n" \
+ "\n" \
+ " loop 3; wait 1000; send; done"
+
+#define ConnectionSection() CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
+
+static const char * gMDNSCollider_Name = NULL;
+static const char * gMDNSCollider_Type = NULL;
+static const char * gMDNSCollider_RecordData = NULL;
+static int gMDNSCollider_UseIPv4 = false;
+static int gMDNSCollider_UseIPv6 = false;
+static const char * gMDNSCollider_Program = NULL;
+
+static CLIOption kMDNSColliderOpts[] =
+{
+ StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+ StringOption( 'n', "name", &gMDNSCollider_Name, "name", "Collider's record name.", true ),
+ StringOption( 't', "type", &gMDNSCollider_Type, "type", "Collider's record type.", true ),
+ StringOption( 'd', "data", &gMDNSCollider_RecordData, "record data", "Collider's record data. See " kRecordDataSection_Name " below.", true ),
+ StringOption( 'p', "program", &gMDNSCollider_Program, "program", "Program to execute. See Program section below.", true ),
+ BooleanOption( 0 , "ipv4", &gMDNSCollider_UseIPv4, "Use IPv4." ),
+ BooleanOption( 0 , "ipv6", &gMDNSCollider_UseIPv6, "Use IPv6." ),
+
+ RecordDataSection(),
+ CLI_SECTION( "Program", kMDNSColliderProgramSection_Intro ),
+ CLI_SECTION( "Program Command: probes", kMDNSColliderProgramSection_Probes ),
+ CLI_SECTION( "Program Command: send", kMDNSColliderProgramSection_Send ),
+ CLI_SECTION( "Program Command: wait", kMDNSColliderProgramSection_Wait ),
+ CLI_SECTION( "Program Command: loop", kMDNSColliderProgramSection_Loop ),
+ CLI_OPTION_END()
+};
+
+static void MDNSColliderCmd( void );
+
+//===========================================================================================================================
+// PIDToUUID Command Options
+//===========================================================================================================================
+
+static int gPIDToUUID_PID = 0;
+
+static CLIOption kPIDToUUIDOpts[] =
+{
+ IntegerOption( 'p', "pid", &gPIDToUUID_PID, "PID", "Process ID.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// DNSServer Command Options
+//===========================================================================================================================
+
+#define kDNSServerInfoText_Intro \
+ "The DNS server answers certain queries in the d.test. domain. Responses are dynamically generated based on the\n" \
+ "presence of special labels in the query's QNAME. There are currently eight types of special labels that can be\n" \
+ "used to generate specific responses: Alias labels, Alias-TTL labels, Count labels, Tag labels, TTL labels, the\n" \
+ "IPv4 label, the IPv6 label, and SRV labels.\n" \
+ "\n" \
+ "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
+
+#define kDNSServerInfoText_NameExistence \
+ "A name is considered to exist if it's an Address name or an SRV name.\n" \
+ "\n" \
+ "An Address name is defined as a name that ends with d.test., and the other labels, if any, and in no particular\n" \
+ "order, unless otherwise noted, consist of\n" \
+ "\n" \
+ " 1. at most one Alias or Alias-TTL label as the first label;\n" \
+ " 2. at most one Count label;\n" \
+ " 3. zero or more Tag labels;\n" \
+ " 4. at most one TTL label; and\n" \
+ " 5. at most one IPv4 or IPv6 label.\n" \
+ "\n" \
+ "An SRV name is defined as a name with the following form:\n" \
+ "\n" \
+ " _<service>._<proto>[.<parent domain>][.<SRV label 1>[.<target 1>][.<SRV label 2>[.<target 2>][...]]].d.test.\n" \
+ "\n" \
+ "See \"SRV Names\" for details.\n"
+
+#define kDNSServerInfoText_ResourceRecords \
+ "Currently, the server only supports CNAME, A, AAAA, and SRV records.\n" \
+ "\n" \
+ "Address names that begin with an Alias or Alias-TTL label are aliases of canonical names, i.e., they're the\n" \
+ "names of CNAME records. See \"Alias Labels\" and \"Alias-TTL Labels\" for details.\n" \
+ "\n" \
+ "A canonical Address name can exclusively be the name of one or more A records, can exclusively be the name or\n" \
+ "one or more AAAA records, or can be the name of both A and AAAA records. Address names that contain an IPv4\n" \
+ "label have at least one A record, but no AAAA records. Address names that contain an IPv6 label, have at least\n" \
+ "one AAAA record, but no A records. All other Address names have at least one A record and at least one AAAA\n" \
+ "record. See \"Count Labels\" for how the number of address records for a given Address name is determined.\n" \
+ "\n" \
+ "A records contain IPv4 addresses in the 203.0.113.0/24 block, while AAAA records contain IPv6 addresses in the\n" \
+ "2001:db8:1::/120 block. Both of these address blocks are reserved for documentation. See\n" \
+ "<https://tools.ietf.org/html/rfc5737> and <https://tools.ietf.org/html/rfc3849>.\n" \
+ "\n" \
+ "SRV names are names of SRV records.\n" \
+ "\n" \
+ "Unless otherwise specified, all resource records will use a default TTL. The default TTL can be set with the\n" \
+ "--defaultTTL option. See \"Alias-TTL Labels\" and \"TTL Labels\" for details on how to query for CNAME, A, and\n" \
+ "AAAA records with specific TTL values.\n"
+
+#define kDNSServerInfoText_AliasLabel \
+ "Alias labels are of the form \"alias\" or \"alias-N\", where N is an integer in [2, 2^31 - 1].\n" \
+ "\n" \
+ "If QNAME is an Address name and its first label is Alias label \"alias-N\", then the response will contain\n" \
+ "exactly N CNAME records:\n" \
+ "\n" \
+ " 1. For each i in [3, N], the response will contain a CNAME record whose name is identical to QNAME, except\n" \
+ " that the first label is \"alias-i\" instead, and whose RDATA is the name of the other CNAME record whose\n" \
+ " name has \"alias-(i - 1)\" as its first label.\n" \
+ "\n" \
+ " 2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n" \
+ " is \"alias-2\" instead, and whose RDATA is the name identical to QNAME, except that the first label is\n" \
+ " \"alias\" instead.\n" \
+ "\n" \
+ " 3. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n" \
+ " is \"alias\" instead, and whose RDATA is the name identical to QNAME minus its first label.\n" \
+ "\n" \
+ "If QNAME is an Address name and its first label is Alias label \"alias\", then the response will contain a\n" \
+ "single CNAME record. The CNAME record's name will be equal to QNAME and its RDATA will be the name identical to\n" \
+ "QNAME minus its first label.\n" \
+ "\n" \
+ "Example. A response to a query with a QNAME of alias-3.count-5.d.test will contain the following CNAME\n" \
+ "records:\n" \
+ "\n" \
+ " alias-4.count-5.d.test. 60 IN CNAME alias-3.count-5.d.test.\n" \
+ " alias-3.count-5.d.test. 60 IN CNAME alias-2.count-5.d.test.\n" \
+ " alias-2.count-5.d.test. 60 IN CNAME alias.count-5.d.test.\n" \
+ " alias.count-5.d.test. 60 IN CNAME count-5.d.test.\n"
+
+#define kDNSServerInfoText_AliasTTLLabel \
+ "Alias-TTL labels are of the form \"alias-ttl-T_1[-T_2[...-T_N]]\", where each T_i is an integer in\n" \
+ "[0, 2^31 - 1] and N is a positive integer bounded by the size of the maximum legal label length (63 octets).\n" \
+ "\n" \
+ "If QNAME is an Address name and its first label is Alias-TTL label \"alias-ttl-T_1...-T_N\", then the response\n" \
+ "will contain exactly N CNAME records:\n" \
+ "\n" \
+ " 1. For each i in [1, N - 1], the response will contain a CNAME record whose name is identical to QNAME,\n" \
+ " except that the first label is \"alias-ttl-T_i...-T_N\" instead, whose TTL value is T_i, and whose RDATA\n" \
+ " is the name of the other CNAME record whose name has \"alias-ttl-T_(i+1)...-T_N\" as its first label.\n" \
+ "\n" \
+ " 2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n" \
+ " is \"alias-ttl-T_N\", whose TTL is T_N, and whose RDATA is identical to QNAME stripped of its first\n" \
+ " label.\n" \
+ "\n" \
+ "Example. A response to a query with a QNAME of alias-ttl-20-40-80.count-5.d.test will contain the following\n" \
+ "CNAME records:\n" \
+ "\n" \
+ " alias-ttl-20-40-80.count-5.d.test. 20 IN CNAME alias-ttl-40-80.count-5.d.test.\n" \
+ " alias-ttl-40-80.count-5.d.test. 40 IN CNAME alias-ttl-80.count-5.d.test.\n" \
+ " alias-ttl-80.count-5.d.test. 80 IN CNAME count-5.d.test.\n"
+
+#define kDNSServerInfoText_CountLabel \
+ "Count labels are of the form \"count-N_1\" or \"count-N_1-N_2\", where N_1 is an integer in [1, 255] and N_2 is\n" \
+ "an integer in [N_1, 255].\n" \
+ "\n" \
+ "If QNAME is an Address name, contains Count label \"count-N\", and has the type of address records specified by\n" \
+ "QTYPE, then the response will contain exactly N address records:\n" \
+ "\n" \
+ " 1. For i in [1, N], the response will contain an address record of type QTYPE whose name is equal to QNAME\n" \
+ " and whose RDATA is an address equal to a constant base address + i.\n" \
+ "\n" \
+ " 2. The address records will be ordered by the address contained in RDATA in ascending order.\n" \
+ "\n" \
+ "Example. A response to an A record query with a QNAME of alias.count-3.d.test will contain the following A\n" \
+ "records:\n" \
+ "\n" \
+ " count-3.d.test. 60 IN A 203.0.113.1\n" \
+ " count-3.d.test. 60 IN A 203.0.113.2\n" \
+ " count-3.d.test. 60 IN A 203.0.113.3\n" \
+ "\n" \
+ "If QNAME is an Address name, contains Count label \"count-N_1-N_2\", and has the type of address records\n" \
+ "specified by QTYPE, then the response will contain exactly N_1 address records:\n" \
+ "\n" \
+ " 1. Each of the address records will be of type QTYPE, have name equal to QNAME, and have as its RDATA a\n" \
+ " unique address equal to a constant base address + i, where i is a randomly chosen integer in [1, N_2].\n" \
+ "\n" \
+ " 2. The order of the address records will be random.\n" \
+ "\n" \
+ "Example. A response to a AAAA record query with a QNAME of count-3-100.ttl-20.d.test could contain the\n" \
+ "following AAAA records:\n" \
+ "\n" \
+ " count-3-100.ttl-20.d.test. 20 IN AAAA 2001:db8:1::c\n" \
+ " count-3-100.ttl-20.d.test. 20 IN AAAA 2001:db8:1::3a\n" \
+ " count-3-100.ttl-20.d.test. 20 IN AAAA 2001:db8:1::4f\n" \
+ "\n" \
+ "If QNAME is an Address name, but doesn't have the type of address records specified by QTYPE, then the response\n" \
+ "will contain no address records, regardless of whether it contains a Count label.\n" \
+ "\n" \
+ "Address names that don't have a Count label are treated as though they contain a count label equal to\n" \
+ "count-1\".\n"
+
+#define kDNSServerInfoText_TagLabel \
+ "Tag labels are labels prefixed with \"tag-\" and contain zero or more arbitrary octets after the prefix.\n" \
+ "\n" \
+ "This type of label exists to allow testers to \"uniquify\" domain names. Tag labels can also serve as padding\n" \
+ "to increase the sizes of domain names.\n"
+
+#define kDNSServerInfoText_TTLLabel \
+ "TTL labels are of the form \"ttl-T\", where T is an integer in [0, 2^31 - 1].\n" \
+ "\n" \
+ "If QNAME is an Address name and contains TTL label \"ttl-T\", then all non-CNAME records contained in the\n" \
+ "response will have a TTL value equal to T.\n"
+
+#define kDNSServerInfoText_IPv4Label \
+ "The IPv4 label is \"ipv4\". See \"Resource Records\" for the affect of this label.\n"
+
+#define kDNSServerInfoText_IPv6Label \
+ "The IPv6 label is \"ipv6\". See \"Resource Records\" for the affect of this label.\n"
+
+#define kDNSServerInfoText_SRVNames \
+ "SRV labels are of the form \"srv-R-W-P\", where R, W, and P are integers in [0, 2^16 - 1].\n" \
+ "\n" \
+ "After the first two labels, i.e., the service and protocol labels, the sequence of labels, which may be empty,\n" \
+ "leading up to the the first SRV label, if one exists, or the d.test. labels will be used as a parent domain for\n" \
+ "the target hostname of each of the SRV name's SRV records.\n" \
+ "\n" \
+ "If QNAME is an SRV name and QTYPE is SRV, then for each SRV label, the response will contain an SRV record with\n" \
+ "priority R, weight W, port P, and target hostname <target>[.<parent domain>]., where <target> is the sequence\n" \
+ "of labels, which may be empty, that follows the SRV label leading up to either the next SRV label or the\n" \
+ "d.test. labels, whichever comes first.\n" \
+ "\n" \
+ "Example. A response to an SRV record query with a QNAME of\n" \
+ "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. will contain the following SRV records:\n" \
+ "\n" \
+ "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. 60 IN SRV 0 0 80 www.example.com.\n" \
+ "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. 60 IN SRV 1 0 8080 www.example.com.\n"
+
+#define kDNSServerInfoText_BadUDPMode \
+ "The purpose of Bad UDP mode is to test mDNSResponder's TCP fallback mechanism by which mDNSResponder reissues a\n" \
+ "UDP query as a TCP query if the UDP response contains the expected QNAME, QTYPE, and QCLASS, but a message ID\n" \
+ "that's not equal to the query's message ID.\n" \
+ "\n" \
+ "This mode is identical to the normal mode except that all responses sent via UDP have a message ID equal to the\n" \
+ "query's message ID plus one. Also, in this mode, to aid in debugging, A records in responses sent via UDP have\n" \
+ "IPv4 addresses in the 0.0.0.0/24 block instead of the 203.0.113.0/24 block, i.e., 0.0.0.0 is used as the IPv4\n" \
+ "base address, and AAAA records in responses sent via UDP have IPv6 addresses in the ::ffff:0:0/120 block\n" \
+ "instead of the 2001:db8:1::/120 block, i.e., ::ffff:0:0 is used as the IPv6 base address.\n"
+
+static int gDNSServer_LoopbackOnly = false;
+static int gDNSServer_Foreground = false;
+static int gDNSServer_ResponseDelayMs = 0;
+static int gDNSServer_DefaultTTL = 60;
+static int gDNSServer_Port = kDNSPort;
+static const char * gDNSServer_DomainOverride = NULL;
+#if( TARGET_OS_DARWIN )
+static const char * gDNSServer_FollowPID = NULL;
+#endif
+static int gDNSServer_BadUDPMode = false;
+
+static CLIOption kDNSServerOpts[] =
+{
+ BooleanOption( 'l', "loopback", &gDNSServer_LoopbackOnly, "Bind to to the loopback interface." ),
+ BooleanOption( 'f', "foreground", &gDNSServer_Foreground, "Direct log output to stdout instead of system logging." ),
+ IntegerOption( 'd', "responseDelay", &gDNSServer_ResponseDelayMs, "ms", "The amount of additional delay in milliseconds to apply to responses. (default: 0)", false ),
+ IntegerOption( 0 , "defaultTTL", &gDNSServer_DefaultTTL, "seconds", "Resource record TTL value to use when unspecified. (default: 60)", false ),
+ IntegerOption( 'p', "port", &gDNSServer_Port, "port number", "UDP/TCP port number to use. Use 0 for any port. (default: 53)", false ),
+ StringOption( 0 , "domain", &gDNSServer_DomainOverride, "domain", "Used to override 'd.test.' as the server's domain.", false ),
+#if( TARGET_OS_DARWIN )
+ StringOption( 0 , "follow", &gDNSServer_FollowPID, "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
+#endif
+ BooleanOption( 0 , "badUDPMode", &gDNSServer_BadUDPMode, "Run in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
+
+ CLI_SECTION( "Intro", kDNSServerInfoText_Intro ),
+ CLI_SECTION( "Name Existence", kDNSServerInfoText_NameExistence ),
+ CLI_SECTION( "Resource Records", kDNSServerInfoText_ResourceRecords ),
+ CLI_SECTION( "Alias Labels", kDNSServerInfoText_AliasLabel ),
+ CLI_SECTION( "Alias-TTL Labels", kDNSServerInfoText_AliasTTLLabel ),
+ CLI_SECTION( "Count Labels", kDNSServerInfoText_CountLabel ),
+ CLI_SECTION( "Tag Labels", kDNSServerInfoText_TagLabel ),
+ CLI_SECTION( "TTL Labels", kDNSServerInfoText_TTLLabel ),
+ CLI_SECTION( "IPv4 Label", kDNSServerInfoText_IPv4Label ),
+ CLI_SECTION( "IPv6 Label", kDNSServerInfoText_IPv6Label ),
+ CLI_SECTION( "SRV Names", kDNSServerInfoText_SRVNames ),
+ CLI_SECTION( "Bad UDP Mode", kDNSServerInfoText_BadUDPMode ),
+ CLI_OPTION_END()
+};
+
+static void DNSServerCmd( void );
+
+//===========================================================================================================================
+// MDNSReplier Command Options
+//===========================================================================================================================
+
+#define kMDNSReplierPortBase 50000
+
+#define kMDNSReplierInfoText_Intro \
+ "The mDNS replier answers mDNS queries for its authoritative records. These records are of class IN and of types\n" \
+ "PTR, SRV, TXT, A, and AAAA as described below.\n" \
+ "\n" \
+ "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
+
+#define kMDNSReplierInfoText_Parameters \
+ "There are five parameters that control the replier's set of authoritative records.\n" \
+ "\n" \
+ " 1. <hostname> is the base name used for service instance names and the names of A and AAAA records. This\n" \
+ " parameter is specified with the --hostname option.\n" \
+ " 2. <tag> is an arbitrary string used to uniquify service types. This parameter is specified with the --tag\n" \
+ " option.\n" \
+ " 3. N_max in an integer in [1, 65535] and limits service types to those that have no more than N_max\n" \
+ " instances. It also limits the number of hostnames to N_max, i.e., <hostname>.local.,\n" \
+ " <hostname>-1.local., ..., <hostname>-N_max.local. This parameter is specified with the\n" \
+ " --maxInstanceCount option.\n" \
+ " 4. N_a is an integer in [1, 255] and the number of A records per hostname. This parameter is specified\n" \
+ " with the --countA option.\n" \
+ " 5. N_aaaa is an integer in [1, 255] and the number of AAAA records per hostname. This parameter is\n" \
+ " specified with the --countAAAA option.\n"
+
+#define kMDNSReplierInfoText_PTR \
+ "The replier's authoritative PTR records have names of the form _t-<tag>-<L>-<N>._tcp.local., where L is an\n" \
+ "integer in [1, 65535], and N is an integer in [1, N_max].\n" \
+ "\n" \
+ "For a given L and N, the replier has exactly N authoritative PTR records:\n" \
+ "\n" \
+ " 1. The first PTR record is defined as\n" \
+ "\n" \
+ " NAME: _t-<tag>-<L>-<N>._tcp.local.\n" \
+ " TYPE: PTR\n" \
+ " CLASS: IN\n" \
+ " TTL: 4500\n" \
+ " RDATA: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n" \
+ "\n" \
+ " 2. For each i in [2, N], there is one PTR record defined as\n" \
+ "\n" \
+ " NAME: _t-<tag>-<L>-<N>._tcp.local.\n" \
+ " TYPE: PTR\n" \
+ " CLASS: IN\n" \
+ " TTL: 4500\n" \
+ " RDATA: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"
+
+#define kMDNSReplierInfoText_SRV \
+ "The replier's authoritative SRV records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n" \
+ "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n" \
+ "\"<hostname> (<i>)\", where i is in [2, N].\n" \
+ "\n" \
+ "For a given L and N, the replier has exactly N authoritative SRV records:\n" \
+ "\n" \
+ " 1. The first SRV record is defined as\n" \
+ "\n" \
+ " NAME: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n" \
+ " TYPE: SRV\n" \
+ " CLASS: IN\n" \
+ " TTL: 120\n" \
+ " RDATA:\n" \
+ " Priority: 0\n" \
+ " Weight: 0\n" \
+ " Port: (50000 + L) mod 2^16\n" \
+ " Target: <hostname>.local.\n" \
+ "\n" \
+ " 2. For each i in [2, N], there is one SRV record defined as:\n" \
+ "\n" \
+ " NAME: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n" \
+ " TYPE: SRV\n" \
+ " CLASS: IN\n" \
+ " TTL: 120\n" \
+ " RDATA:\n" \
+ " Priority: 0\n" \
+ " Weight: 0\n" \
+ " Port: (50000 + L) mod 2^16\n" \
+ " Target: <hostname>-<i>.local.\n"
+
+#define kMDNSReplierInfoText_TXT \
+ "The replier's authoritative TXT records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n" \
+ "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n" \
+ "\"<hostname> (<i>)\", where i is in [2, N].\n" \
+ "\n" \
+ "For a given L and N, the replier has exactly N authoritative TXT records:\n" \
+ "\n" \
+ " 1. The first TXT record is defined as\n" \
+ "\n" \
+ " NAME: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n" \
+ " TYPE: TXT\n" \
+ " CLASS: IN\n" \
+ " TTL: 4500\n" \
+ " RDLENGTH: L\n" \
+ " RDATA: <one or more strings with an aggregate length of L octets>\n" \
+ "\n" \
+ " 2. For each i in [2, N], there is one TXT record:\n" \
+ "\n" \
+ " NAME: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n" \
+ " TYPE: TXT\n" \
+ " CLASS: IN\n" \
+ " TTL: 4500\n" \
+ " RDLENGTH: L\n" \
+ " RDATA: <one or more strings with an aggregate length of L octets>\n" \
+ "\n" \
+ "The RDATA of each TXT record is exactly L octets and consists of a repeating series of the 15-byte string\n" \
+ "\"hash=0x<32-bit FNV-1 hash of the record name as an 8-character hexadecimal string>\". The last instance of\n" \
+ "the string may be truncated to satisfy the TXT record data's size requirement.\n"
+
+#define kMDNSReplierInfoText_A \
+ "The replier has exactly N_max x N_a authoritative A records:\n" \
+ "\n" \
+ " 1. For each j in [1, N_a], an A record is defined as\n" \
+ "\n" \
+ " NAME: <hostname>.local.\n" \
+ " TYPE: A\n" \
+ " CLASS: IN\n" \
+ " TTL: 120\n" \
+ " RDLENGTH: 4\n" \
+ " RDATA: 0.0.1.<j>\n" \
+ "\n" \
+ " 2. For each i in [2, N_max], for each j in [1, N_a], an A record is defined as\n" \
+ "\n" \
+ " NAME: <hostname>-<i>.local.\n" \
+ " TYPE: A\n" \
+ " CLASS: IN\n" \
+ " TTL: 120\n" \
+ " RDLENGTH: 4\n" \
+ " RDATA: 0.<ceil(i / 256)>.<i mod 256>.<j>\n"
+
+#define kMDNSReplierInfoText_AAAA \
+ "The replier has exactly N_max x N_aaaa authoritative AAAA records:\n" \
+ "\n" \
+ " 1. For each j in [1, N_aaaa], a AAAA record is defined as\n" \
+ "\n" \
+ " NAME: <hostname>.local.\n" \
+ " TYPE: AAAA\n" \
+ " CLASS: IN\n" \
+ " TTL: 120\n" \
+ " RDLENGTH: 16\n" \
+ " RDATA: 2001:db8:2::1:<j>\n" \
+ "\n" \
+ " 2. For each i in [2, N_max], for each j in [1, N_aaaa], a AAAA record is defined as\n" \
+ "\n" \
+ " NAME: <hostname>-<i>.local.\n" \
+ " TYPE: AAAA\n" \
+ " CLASS: IN\n" \
+ " TTL: 120\n" \
+ " RDLENGTH: 16\n" \
+ " RDATA: 2001:db8:2::<i>:<j>\n"
+
+#define kMDNSReplierInfoText_Responses \
+ "When generating answers for a query message, any two records pertaining to the same hostname will be grouped\n" \
+ "together in the same response message, and any two records pertaining to different hostnames will be in\n" \
+ "separate response messages.\n"
+
+static const char * gMDNSReplier_Hostname = NULL;
+static const char * gMDNSReplier_ServiceTypeTag = NULL;
+static int gMDNSReplier_MaxInstanceCount = 1000;
+static int gMDNSReplier_NoAdditionals = false;
+static int gMDNSReplier_RecordCountA = 1;
+static int gMDNSReplier_RecordCountAAAA = 1;
+static double gMDNSReplier_UnicastDropRate = 0.0;
+static double gMDNSReplier_MulticastDropRate = 0.0;
+static int gMDNSReplier_MaxDropCount = 0;
+static int gMDNSReplier_UseIPv4 = false;
+static int gMDNSReplier_UseIPv6 = false;
+static int gMDNSReplier_Foreground = false;
+static const char * gMDNSReplier_FollowPID = NULL;
+
+static CLIOption kMDNSReplierOpts[] =
+{
+ StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+ StringOption( 'n', "hostname", &gMDNSReplier_Hostname, "string", "Base name to use for hostnames and service instance names.", true ),
+ StringOption( 't', "tag", &gMDNSReplier_ServiceTypeTag, "string", "Tag to use for service types, e.g., _t-<tag>-<TXT size>-<count>._tcp.", true ),
+ IntegerOption( 'c', "maxInstanceCount", &gMDNSReplier_MaxInstanceCount, "count", "Maximum number of service instances. (default: 1000)", false ),
+ BooleanOption( 0 , "noAdditionals", &gMDNSReplier_NoAdditionals, "When answering queries, don't include any additional records." ),
+ IntegerOption( 0 , "countA", &gMDNSReplier_RecordCountA, "count", "Number of A records per hostname. (default: 1)", false ),
+ IntegerOption( 0 , "countAAAA", &gMDNSReplier_RecordCountAAAA, "count", "Number of AAAA records per hostname. (default: 1)", false ),
+ DoubleOption( 0 , "udrop", &gMDNSReplier_UnicastDropRate, "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
+ DoubleOption( 0 , "mdrop", &gMDNSReplier_MulticastDropRate, "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
+ IntegerOption( 0 , "maxDropCount", &gMDNSReplier_MaxDropCount, "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
+ BooleanOption( 0 , "ipv4", &gMDNSReplier_UseIPv4, "Use IPv4." ),
+ BooleanOption( 0 , "ipv6", &gMDNSReplier_UseIPv6, "Use IPv6." ),
+ BooleanOption( 'f', "foreground", &gMDNSReplier_Foreground, "Direct log output to stdout instead of system logging." ),
+#if( TARGET_OS_DARWIN )
+ StringOption( 0 , "follow", &gMDNSReplier_FollowPID, "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
+#endif
+
+ CLI_SECTION( "Intro", kMDNSReplierInfoText_Intro ),
+ CLI_SECTION( "Authoritative Record Parameters", kMDNSReplierInfoText_Parameters ),
+ CLI_SECTION( "Authoritative PTR Records", kMDNSReplierInfoText_PTR ),
+ CLI_SECTION( "Authoritative SRV Records", kMDNSReplierInfoText_SRV ),
+ CLI_SECTION( "Authoritative TXT Records", kMDNSReplierInfoText_TXT ),
+ CLI_SECTION( "Authoritative A Records", kMDNSReplierInfoText_A ),
+ CLI_SECTION( "Authoritative AAAA Records", kMDNSReplierInfoText_AAAA ),
+ CLI_SECTION( "Responses", kMDNSReplierInfoText_Responses ),
+ CLI_OPTION_END()
+};
+
+static void MDNSReplierCmd( void );
+
+//===========================================================================================================================
+// Test Command Options
+//===========================================================================================================================
+
+#define kTestExitStatusSection_Name "Exit Status"
+#define kTestExitStatusSection_Text \
+ "This test command can exit with one of three status codes:\n" \
+ "\n" \
+ "0 - The test ran to completion and passed.\n" \
+ "1 - A fatal error prevented the test from completing.\n" \
+ "2 - The test ran to completion, but it or a subtest failed. See test output for details.\n" \
+ "\n" \
+ "Note: The pass/fail status applies to the correctness or results. It does not necessarily imply anything about\n" \
+ "performance.\n"
+
+#define TestExitStatusSection() CLI_SECTION( kTestExitStatusSection_Name, kTestExitStatusSection_Text )
+
+#define kGAIPerfTestSuiteName_Basic "basic"
+#define kGAIPerfTestSuiteName_Advanced "advanced"
+
+static const char * gGAIPerf_TestSuite = NULL;
+static int gGAIPerf_CallDelayMs = 10;
+static int gGAIPerf_ServerDelayMs = 10;
+static int gGAIPerf_SkipPathEvalulation = false;
+static int gGAIPerf_BadUDPMode = false;
+static int gGAIPerf_IterationCount = 100;
+static int gGAIPerf_IterationTimeLimitMs = 100;
+static const char * gGAIPerf_OutputFilePath = NULL;
+static const char * gGAIPerf_OutputFormat = kOutputFormatStr_JSON;
+static int gGAIPerf_OutputAppendNewline = false;
+
+static void GAIPerfCmd( void );
+
+#define kGAIPerfSectionText_TestSuiteBasic \
+ "This test suite consists of the following three test cases:\n" \
+ "\n" \
+ "Test Case #1: Resolve a domain name with\n" \
+ "\n" \
+ " 2 CNAME records, 4 A records, and 4 AAAA records\n" \
+ "\n" \
+ "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n" \
+ "server queries.\n" \
+ "\n" \
+ "Test Case #2: Resolve a domain name with\n" \
+ "\n" \
+ " 2 CNAME records, 4 A records, and 4 AAAA records\n" \
+ "\n" \
+ "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n" \
+ "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n" \
+ "which should ideally require no additional server queries, i.e., the results should come from the cache.\n" \
+ "\n" \
+ "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n" \
+ "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n" \
+ "domain name in the preliminary iteration isn't counted in the performance stats.\n" \
+ "\n" \
+ "Test Case #3: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
+
+#define kGAIPerfSectionText_TestSuiteAdvanced \
+ "This test suite consists of 33 test cases. Test cases 1 through 32 can be described in the following way\n" \
+ "\n" \
+ "Test Case #N (where N is in [1, 32] and odd): Resolve a domain name with\n" \
+ "\n" \
+ " N_c CNAME records, N_a A records, and N_a AAAA records\n" \
+ "\n" \
+ "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n" \
+ "server queries.\n" \
+ "\n" \
+ "Test Case #N (where N is in [1, 32] and even): Resolve a domain name with\n" \
+ "\n" \
+ " N_c CNAME records, N_a A records, and N_a AAAA records\n" \
+ "\n" \
+ "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n" \
+ "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n" \
+ "which should ideally require no additional server queries, i.e., the results should come from the cache.\n" \
+ "\n" \
+ "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n" \
+ "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n" \
+ "domain name in the preliminary iteration isn't counted in the performance stats.\n" \
+ "\n" \
+ "N_c and N_a take on the following values, depending on the value of N:\n" \
+ "\n" \
+ " N_c is 0 if N is in [1, 8].\n" \
+ " N_c is 1 if N is in [9, 16].\n" \
+ " N_c is 2 if N is in [17, 24].\n" \
+ " N_c is 4 if N is in [25, 32].\n" \
+ "\n" \
+ " N_a is 1 if N mod 8 is 1 or 2.\n" \
+ " N_a is 2 if N mod 8 is 3 or 4.\n" \
+ " N_a is 4 if N mod 8 is 5 or 6.\n" \
+ " N_a is 8 if N mod 8 is 7 or 0.\n" \
+ "\n" \
+ "Finally,\n" \
+ "\n" \
+ "Test Case #33: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
+
+static CLIOption kGAIPerfOpts[] =
+{
+ StringOptionEx( 's', "suite", &gGAIPerf_TestSuite, "name", "Name of the predefined test suite to run.", true,
+ "\n"
+ "There are currently two predefined test suites, '" kGAIPerfTestSuiteName_Basic "' and '" kGAIPerfTestSuiteName_Advanced "', which are described below.\n"
+ "\n"
+ ),
+ StringOption( 'o', "output", &gGAIPerf_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+ FormatOption( 'f', "format", &gGAIPerf_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+ BooleanOption( 'n', "appendNewline", &gGAIPerf_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
+ IntegerOption( 'i', "iterations", &gGAIPerf_IterationCount, "count", "The number of iterations per test case. (default: 100)", false ),
+ IntegerOption( 'l', "timeLimit", &gGAIPerf_IterationTimeLimitMs, "ms", "Time limit for each DNSServiceGetAddrInfo() operation in milliseconds. (default: 100)", false ),
+ IntegerOption( 0 , "callDelay", &gGAIPerf_CallDelayMs, "ms", "Time to wait before calling DNSServiceGetAddrInfo() in milliseconds. (default: 10)", false ),
+ BooleanOption( 0 , "skipPathEval", &gGAIPerf_SkipPathEvalulation, "Use kDNSServiceFlagsPathEvaluationDone when calling DNSServiceGetAddrInfo()." ),
+
+ CLI_OPTION_GROUP( "DNS Server Options" ),
+ IntegerOption( 0 , "responseDelay", &gGAIPerf_ServerDelayMs, "ms", "Additional delay in milliseconds to have the server apply to responses. (default: 10)", false ),
+ BooleanOption( 0 , "badUDPMode", &gGAIPerf_BadUDPMode, "Run server in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
+
+ CLI_SECTION( "Test Suite \"Basic\"", kGAIPerfSectionText_TestSuiteBasic ),
+ CLI_SECTION( "Test Suite \"Advanced\"", kGAIPerfSectionText_TestSuiteAdvanced ),
+ TestExitStatusSection(),
+ CLI_OPTION_END()
+};
+
+static void MDNSDiscoveryTestCmd( void );
+
+static int gMDNSDiscoveryTest_InstanceCount = 100;
+static int gMDNSDiscoveryTest_TXTSize = 100;
+static int gMDNSDiscoveryTest_BrowseTimeSecs = 2;
+static int gMDNSDiscoveryTest_FlushCache = false;
+static char * gMDNSDiscoveryTest_Interface = NULL;
+static int gMDNSDiscoveryTest_NoAdditionals = false;
+static int gMDNSDiscoveryTest_RecordCountA = 1;
+static int gMDNSDiscoveryTest_RecordCountAAAA = 1;
+static double gMDNSDiscoveryTest_UnicastDropRate = 0.0;
+static double gMDNSDiscoveryTest_MulticastDropRate = 0.0;
+static int gMDNSDiscoveryTest_MaxDropCount = 0;
+static int gMDNSDiscoveryTest_UseIPv4 = false;
+static int gMDNSDiscoveryTest_UseIPv6 = false;
+static const char * gMDNSDiscoveryTest_OutputFormat = kOutputFormatStr_JSON;
+static int gMDNSDiscoveryTest_OutputAppendNewline = false;
+static const char * gMDNSDiscoveryTest_OutputFilePath = NULL;
+
+static CLIOption kMDNSDiscoveryTestOpts[] =
+{
+ IntegerOption( 'c', "instanceCount", &gMDNSDiscoveryTest_InstanceCount, "count", "Number of service instances to discover. (default: 100)", false ),
+ IntegerOption( 's', "txtSize", &gMDNSDiscoveryTest_TXTSize, "bytes", "Desired size of each service instance's TXT record data. (default: 100)", false ),
+ IntegerOption( 'b', "browseTime", &gMDNSDiscoveryTest_BrowseTimeSecs, "seconds", "Amount of time to spend browsing in seconds. (default: 2)", false ),
+ BooleanOption( 0 , "flushCache", &gMDNSDiscoveryTest_FlushCache, "Flush mDNSResponder's record cache before browsing. Requires root privileges." ),
+
+ CLI_OPTION_GROUP( "mDNS Replier Parameters" ),
+ StringOption( 'i', "interface", &gMDNSDiscoveryTest_Interface, "name or index", "Network interface. If unspecified, any available mDNS-capable interface will be used.", false ),
+ BooleanOption( 0 , "noAdditionals", &gMDNSDiscoveryTest_NoAdditionals, "When answering queries, don't include any additional records." ),
+ IntegerOption( 0 , "countA", &gMDNSDiscoveryTest_RecordCountA, "count", "Number of A records per hostname. (default: 1)", false ),
+ IntegerOption( 0 , "countAAAA", &gMDNSDiscoveryTest_RecordCountAAAA, "count", "Number of AAAA records per hostname. (default: 1)", false ),
+ DoubleOption( 0 , "udrop", &gMDNSDiscoveryTest_UnicastDropRate, "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
+ DoubleOption( 0 , "mdrop", &gMDNSDiscoveryTest_MulticastDropRate, "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
+ IntegerOption( 0 , "maxDropCount", &gMDNSDiscoveryTest_MaxDropCount, "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
+ BooleanOption( 0 , "ipv4", &gMDNSDiscoveryTest_UseIPv4, "Use IPv4." ),
+ BooleanOption( 0 , "ipv6", &gMDNSDiscoveryTest_UseIPv6, "Use IPv6." ),
+
+ CLI_OPTION_GROUP( "Results" ),
+ FormatOption( 'f', "format", &gMDNSDiscoveryTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+ StringOption( 'o', "output", &gMDNSDiscoveryTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+
+ TestExitStatusSection(),
+ CLI_OPTION_END()
+};
+
+static void DotLocalTestCmd( void );
+
+static const char * gDotLocalTest_Interface = NULL;
+static const char * gDotLocalTest_OutputFormat = kOutputFormatStr_JSON;
+static const char * gDotLocalTest_OutputFilePath = NULL;
+
+#define kDotLocalTestSubtestDesc_GAIMDNSOnly "GAI for a dotlocal name that has only MDNS A and AAAA records."
+#define kDotLocalTestSubtestDesc_GAIDNSOnly "GAI for a dotlocal name that has only DNS A and AAAA records."
+#define kDotLocalTestSubtestDesc_GAIBoth "GAI for a dotlocal name that has both mDNS and DNS A and AAAA records."
+#define kDotLocalTestSubtestDesc_GAINeither "GAI for a dotlocal name that has no A or AAAA records."
+#define kDotLocalTestSubtestDesc_GAINoSuchRecord \
+ "GAI for a dotlocal name that has no A or AAAA records, but is a subdomain name of a search domain."
+#define kDotLocalTestSubtestDesc_QuerySRV "SRV query for a dotlocal name that has only a DNS SRV record."
+
+#define kDotLocalTestSectionText_Description \
+ "The goal of the dotlocal test is to verify that mDNSResponder properly handles queries for domain names in the\n" \
+ "local domain when a local SOA record exists. As part of the test setup, a test DNS server and an mdnsreplier are\n" \
+ "spawned, and a dummy local SOA record is registered with DNSServiceRegisterRecord(). The server is invoked such\n" \
+ "that its domain is a second-level subdomain of the local domain, i.e., <some label>.local, while the mdnsreplier is\n" \
+ "invoked such that its base hostname is equal to the server's domain, e.g., if the server's domain is test.local.,\n" \
+ "then the mdnsreplier's base hostname is test.local.\n" \
+ "\n" \
+ "The dotlocal test consists of six subtests that perform either a DNSServiceGetAddrInfo (GAI) operation for a\n" \
+ "hostname in the local domain or a DNSServiceQueryRecord operation to query for an SRV record in the local domain:\n" \
+ "\n" \
+ "1. " kDotLocalTestSubtestDesc_GAIMDNSOnly "\n" \
+ "2. " kDotLocalTestSubtestDesc_GAIDNSOnly "\n" \
+ "3. " kDotLocalTestSubtestDesc_GAIBoth "\n" \
+ "4. " kDotLocalTestSubtestDesc_GAINeither "\n" \
+ "5. " kDotLocalTestSubtestDesc_GAINoSuchRecord "\n" \
+ "6. " kDotLocalTestSubtestDesc_QuerySRV "\n" \
+ "\n" \
+ "Each subtest runs for five seconds.\n"
+
+static CLIOption kDotLocalTestOpts[] =
+{
+ StringOption( 'i', "interface", &gDotLocalTest_Interface, "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
+
+ CLI_OPTION_GROUP( "Results" ),
+ FormatOption( 'f', "format", &gDotLocalTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+ StringOption( 'o', "output", &gDotLocalTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+
+ CLI_SECTION( "Description", kDotLocalTestSectionText_Description ),
+ TestExitStatusSection(),
+ CLI_OPTION_END()
+};
+
+static void ProbeConflictTestCmd( void );
+
+static const char * gProbeConflictTest_Interface = NULL;
+static int gProbeConflictTest_UseComputerName = false;
+static const char * gProbeConflictTest_OutputFormat = kOutputFormatStr_JSON;
+static const char * gProbeConflictTest_OutputFilePath = NULL;
+
+static CLIOption kProbeConflictTestOpts[] =
+{
+ StringOption( 'i', "interface", &gProbeConflictTest_Interface, "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
+ BooleanOption( 'c', "useComputerName", &gProbeConflictTest_UseComputerName, "Use the device's \"computer name\" for the test service's name." ),
+
+ CLI_OPTION_GROUP( "Results" ),
+ FormatOption( 'f', "format", &gProbeConflictTest_OutputFormat, "Specifies the test report output format. (default: " kOutputFormatStr_JSON ")", false ),
+ StringOption( 'o', "output", &gProbeConflictTest_OutputFilePath, "path", "Path of the file to write test report to instead of standard output (stdout).", false ),
+
+ TestExitStatusSection(),
+ CLI_OPTION_END()
+};
+
+static void RegistrationTestCmd( void );
+
+static int gRegistrationTest_BATSEnvironment = false;
+static const char * gRegistrationTest_OutputFormat = kOutputFormatStr_JSON;
+static const char * gRegistrationTest_OutputFilePath = NULL;
+
+static CLIOption kRegistrationTestOpts[] =
+{
+ CLI_OPTION_BOOLEAN( 0, "bats", &gRegistrationTest_BATSEnvironment, "Informs the test that it's running in a BATS environment.",
+ "\n"
+ "This option allows the test to take special measures while running in a BATS environment. Currently, this option\n"
+ "only has an effect on watchOS. Because it has been observed that the Wi-Fi interface sometimes goes down during\n"
+ "watchOS BATS testing, for watchOS, when a service is registered using kDNSServiceInterfaceIndexAny,\n"
+ "\n"
+ " 1. missing browse and query \"add\" results for Wi-Fi interfaces aren't enough for a subtest to fail; and\n"
+ " 2. unexpected browse and query results for Wi-Fi interfaces are ignored.\n"
+ ),
+ CLI_OPTION_GROUP( "Results" ),
+ FormatOption( 'f', "format", &gRegistrationTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+ StringOption( 'o', "output", &gRegistrationTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+
+ TestExitStatusSection(),
+ CLI_OPTION_END()
+};
+
+static void ExpensiveConstrainedTestCmd( void );
+
+static const char * gExpensiveConstrainedTest_Interface = NULL;
+static const char * gExpensiveConstrainedTest_Name = NULL;
+static Boolean gExpensiveConstrainedTest_DenyExpensive = false;
+static Boolean gExpensiveConstrainedTest_DenyConstrained = false;
+static Boolean gExpensiveConstrainedTest_StartFromExpensive = false;
+static int gExpensiveConstrainedTest_ProtocolIPv4 = false;
+static int gExpensiveConstrainedTest_ProtocolIPv6 = false;
+static const char * gExpensiveConstrainedTest_OutputFormat = kOutputFormatStr_JSON;
+static const char * gExpensiveConstrainedTest_OutputFilePath = NULL;
+
+static CLIOption kExpensiveConstrainedTestOpts[] =
+{
+ CLI_OPTION_GROUP( "Results" ),
+ FormatOption( 'f', "format", &gExpensiveConstrainedTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+ StringOption( 'o', "output", &gExpensiveConstrainedTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+
+ TestExitStatusSection(),
+ CLI_OPTION_END()
+};
+
+static CLIOption kTestOpts[] =
+{
+ Command( "gaiperf", GAIPerfCmd, kGAIPerfOpts, "Runs DNSServiceGetAddrInfo() performance tests.", false ),
+ Command( "mdnsdiscovery", MDNSDiscoveryTestCmd, kMDNSDiscoveryTestOpts, "Tests mDNS service discovery for correctness.", false ),
+ Command( "dotlocal", DotLocalTestCmd, kDotLocalTestOpts, "Tests DNS and mDNS queries for domain names in the local domain.", false ),
+ Command( "probeconflicts", ProbeConflictTestCmd, kProbeConflictTestOpts, "Tests various probing conflict scenarios.", false ),
+ Command( "registration", RegistrationTestCmd, kRegistrationTestOpts, "Tests service registrations.", false ),
+ Command( "expensive_constrained_updates", ExpensiveConstrainedTestCmd, kExpensiveConstrainedTestOpts, "Tests if the mDNSResponder can handle expensive and constrained property change correctly", false),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// SSDP Command Options
+//===========================================================================================================================
+
+static int gSSDPDiscover_MX = 1;
+static const char * gSSDPDiscover_ST = "ssdp:all";
+static int gSSDPDiscover_ReceiveSecs = 1;
+static int gSSDPDiscover_UseIPv4 = false;
+static int gSSDPDiscover_UseIPv6 = false;
+static int gSSDPDiscover_Verbose = false;
+
+static CLIOption kSSDPDiscoverOpts[] =
+{
+ StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+ IntegerOption( 'm', "mx", &gSSDPDiscover_MX, "seconds", "MX value in search request, i.e., max response delay in seconds. (Default: 1 second)", false ),
+ StringOption( 's', "st", &gSSDPDiscover_ST, "string", "ST value in search request, i.e., the search target. (Default: \"ssdp:all\")", false ),
+ IntegerOption( 'r', "receiveTime", &gSSDPDiscover_ReceiveSecs, "seconds", "Amount of time to spend receiving responses. -1 means unlimited. (Default: 1 second)", false ),
+ BooleanOption( 0 , "ipv4", &gSSDPDiscover_UseIPv4, "Use IPv4, i.e., multicast to 239.255.255.250:1900." ),
+ BooleanOption( 0 , "ipv6", &gSSDPDiscover_UseIPv6, "Use IPv6, i.e., multicast to [ff02::c]:1900" ),
+ BooleanOption( 'v', "verbose", &gSSDPDiscover_Verbose, "Prints the search request(s) that were sent." ),
+ CLI_OPTION_END()
+};
+
+static void SSDPDiscoverCmd( void );
+
+static CLIOption kSSDPOpts[] =
+{
+ Command( "discover", SSDPDiscoverCmd, kSSDPDiscoverOpts, "Crafts and multicasts an SSDP search message.", false ),
+ CLI_OPTION_END()
+};
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// res_query Command Options
+//===========================================================================================================================
+
+static void ResQueryCmd( void );
+
+static const char * gResQuery_Name = NULL;
+static const char * gResQuery_Type = NULL;
+static const char * gResQuery_Class = NULL;
+static int gResQuery_UseLibInfo = false;
+
+static CLIOption kResQueryOpts[] =
+{
+ StringOption( 'n', "name", &gResQuery_Name, "domain name", "Full domain name of record to query.", true ),
+ StringOption( 't', "type", &gResQuery_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+ StringOption( 'c', "class", &gResQuery_Class, "record class", "Record class by name or number. Default class is IN.", false ),
+ BooleanOption( 0 , "libinfo", &gResQuery_UseLibInfo, "Use res_query from libinfo instead of libresolv." ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// dns_query Command Options
+//===========================================================================================================================
+
+static void ResolvDNSQueryCmd( void );
+
+static const char * gResolvDNSQuery_Name = NULL;
+static const char * gResolvDNSQuery_Type = NULL;
+static const char * gResolvDNSQuery_Class = NULL;
+static const char * gResolvDNSQuery_Path = NULL;
+
+static CLIOption kResolvDNSQueryOpts[] =
+{
+ StringOption( 'n', "name", &gResolvDNSQuery_Name, "domain name", "Full domain name of record to query.", true ),
+ StringOption( 't', "type", &gResolvDNSQuery_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+ StringOption( 'c', "class", &gResolvDNSQuery_Class, "record class", "Record class by name or number. Default class is IN.", false ),
+ StringOption( 'p', "path", &gResolvDNSQuery_Path, "file path", "The path argument to pass to dns_open() before calling dns_query(). Default value is NULL.", false ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// CFHost Command Options
+//===========================================================================================================================
+
+static void CFHostCmd( void );
+
+static const char * gCFHost_Name = NULL;
+static int gCFHost_WaitSecs = 0;
+
+static CLIOption kCFHostOpts[] =
+{
+ StringOption( 'n', "name", &gCFHost_Name, "hostname", "Hostname to resolve.", true ),
+ IntegerOption( 'w', "wait", &gCFHost_WaitSecs, "seconds", "Time in seconds to wait before a normal exit. (default: 0)", false ),
+ CLI_OPTION_END()
+};
+
+static CLIOption kLegacyOpts[] =
+{
+ Command( "res_query", ResQueryCmd, kResQueryOpts, "Uses res_query() from either libresolv or libinfo to query for a record.", true ),
+ Command( "dns_query", ResolvDNSQueryCmd, kResolvDNSQueryOpts, "Uses dns_query() from libresolv to query for a record.", true ),
+ Command( "cfhost", CFHostCmd, kCFHostOpts, "Uses CFHost to resolve a hostname.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// DNSConfigAdd Command Options
+//===========================================================================================================================
+
+static void DNSConfigAddCmd( void );
+
+static CFStringRef gDNSConfigAdd_ID = NULL;
+static char ** gDNSConfigAdd_IPAddrArray = NULL;
+static size_t gDNSConfigAdd_IPAddrCount = 0;
+static char ** gDNSConfigAdd_DomainArray = NULL;
+static size_t gDNSConfigAdd_DomainCount = 0;
+static const char * gDNSConfigAdd_Interface = NULL;
+
+static CLIOption kDNSConfigAddOpts[] =
+{
+ CFStringOption( 0 , "id", &gDNSConfigAdd_ID, "ID", "Arbitrary ID to use for resolver entry.", true ),
+ MultiStringOption( 'a', "address", &gDNSConfigAdd_IPAddrArray, &gDNSConfigAdd_IPAddrCount, "IP address", "DNS server IP address(es). Can be specified more than once.", true ),
+ MultiStringOption( 'd', "domain", &gDNSConfigAdd_DomainArray, &gDNSConfigAdd_DomainCount, "domain", "Specific domain(s) for the resolver entry. Can be specified more than once.", false ),
+ StringOption( 'i', "interface", &gDNSConfigAdd_Interface, "interface name", "Specific interface for the resolver entry.", false ),
+
+ CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// DNSConfigRemove Command Options
+//===========================================================================================================================
+
+static void DNSConfigRemoveCmd( void );
+
+static CFStringRef gDNSConfigRemove_ID = NULL;
+
+static CLIOption kDNSConfigRemoveOpts[] =
+{
+ CFStringOption( 0, "id", &gDNSConfigRemove_ID, "ID", "ID of resolver entry to remove.", true ),
+
+ CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
+ CLI_OPTION_END()
+};
+
+static CLIOption kDNSConfigOpts[] =
+{
+ Command( "add", DNSConfigAddCmd, kDNSConfigAddOpts, "Add a supplemental resolver entry to the system's DNS configuration.", true ),
+ Command( "remove", DNSConfigRemoveCmd, kDNSConfigRemoveOpts, "Remove a supplemental resolver entry from the system's DNS configuration.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// XPCSend
+//===========================================================================================================================
+
+static void XPCSendCmd( void );
+
+static const char * gXPCSend_ServiceName = NULL;
+static const char * gXPCSend_MessageStr = NULL;
+
+static const char kXPCSendMessageSection_Name[] = "Message Argument";
+static const char kXPCSendMessageSection_Text[] =
+ "XPC messages are described as a string using the following syntax.\n"
+ "\n"
+ "With the exception of the top-most XPC message dictionary, dictionaries begin with a '{' and end with a '}'.\n"
+ "Key-value pairs are of the form <key>=<value>, where <key> is a string and <value> is a value of any of the\n"
+ "currently supported XPC types.\n"
+ "\n"
+ "Arrays begin with a '[' and end with a ']'.\n"
+ "\n"
+ "The following non-container XPC types are supported:\n"
+ "\n"
+ "Type Syntax Example\n"
+ "bool bool:<string> bool:true (or yes/y/on/1), bool:false (or no/n/off/0)\n"
+ "data data:<hex string> data:C0000201\n"
+ "int64 (signed 64-bit integer) int:<pos. or neg. integer> int:-1\n"
+ "string string:<string> string:hello\\ world\n"
+ "uint64 (unsigned 64-bit integer) uint:<pos. integer> uint:1024 or uint:0x400\n"
+ "UUID uuid:<UUID> uuid:dab10183-84b5-4859-9de6-4bee287cfea3\n"
+ "\n"
+ "Example 1: 'cmd=string:add make=string:Apple model=string:Macintosh aliases=[string:Mac string:Macintosh\\ 128K]'\n"
+ "Example 2: 'cmd=string:search features={portable=bool:yes solar=bool:no} priceMin=uint:100 priceMax=uint:200'\n";
+
+static CLIOption kXPCSendOpts[] =
+{
+ StringOption( 's', "service", &gXPCSend_ServiceName, "service name", "XPC service name.", true ),
+ StringOption( 'm', "message", &gXPCSend_MessageStr, "message", "XPC message as a string.", true ),
+
+ CLI_SECTION( kXPCSendMessageSection_Name, kXPCSendMessageSection_Text ),
+ CLI_OPTION_END()
+};
+#endif // TARGET_OS_DARWIN
+
+#if ( MDNSRESPONDER_PROJECT )
+//===========================================================================================================================
+// InterfaceMonitor
+//===========================================================================================================================
+
+static void InterfaceMonitorCmd( void );
+
+static CLIOption kInterfaceMonitorOpts[] =
+{
+ StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// DNSProxy
+//===========================================================================================================================
+
+static void DNSProxyCmd( void );
+
+static char ** gDNSProxy_InputInterfaces = NULL;
+static size_t gDNSProxy_InputInterfaceCount = 0;
+static const char * gDNSProxy_OutputInterface = NULL;
+
+static CLIOption kDNSProxyOpts[] =
+{
+ MultiStringOption( 'i', "inputInterface", &gDNSProxy_InputInterfaces, &gDNSProxy_InputInterfaceCount, "name or index", "Interface to accept queries on. Can be specified more than once.", true ),
+ StringOption( 'o', "outputInterface", &gDNSProxy_OutputInterface, "name or index", "Interface to forward queries over. Use '0' for primary interface. (default: 0)", false ),
+ CLI_OPTION_END()
+};
+#endif // MDNSRESPONDER_PROJECT
+
+//===========================================================================================================================
+// Command Table
+//===========================================================================================================================
+
+static OSStatus VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset );
+
+static void BrowseCmd( void );
+static void GetAddrInfoCmd( void );
+static void QueryRecordCmd( void );
+static void RegisterCmd( void );
+static void RegisterRecordCmd( void );
+static void ResolveCmd( void );
+static void ReconfirmCmd( void );
+static void GetAddrInfoPOSIXCmd( void );
+static void ReverseLookupCmd( void );
+static void PortMappingCmd( void );
+static void BrowseAllCmd( void );
+static void GetAddrInfoStressCmd( void );
+static void DNSQueryCmd( void );
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+static void DNSCryptCmd( void );
+#endif
+static void MDNSQueryCmd( void );
+static void PIDToUUIDCmd( void );
+static void DaemonVersionCmd( void );
+
+static CLIOption kGlobalOpts[] =
+{
+ CLI_OPTION_CALLBACK_EX( 'V', "version", VersionOptionCallback, NULL, NULL,
+ kCLIOptionFlags_NoArgument | kCLIOptionFlags_GlobalOnly, "Displays the version of this tool.", NULL ),
+ CLI_OPTION_HELP(),
+
+ // Common commands.
+
+ Command( "browse", BrowseCmd, kBrowseOpts, "Uses DNSServiceBrowse() to browse for one or more service types.", false ),
+ Command( "getAddrInfo", GetAddrInfoCmd, kGetAddrInfoOpts, "Uses DNSServiceGetAddrInfo() to resolve a hostname to IP addresses.", false ),
+ Command( "queryRecord", QueryRecordCmd, kQueryRecordOpts, "Uses DNSServiceQueryRecord() to query for an arbitrary DNS record.", false ),
+ Command( "register", RegisterCmd, kRegisterOpts, "Uses DNSServiceRegister() to register a service.", false ),
+ Command( "registerRecord", RegisterRecordCmd, kRegisterRecordOpts, "Uses DNSServiceRegisterRecord() to register a record.", false ),
+ Command( "resolve", ResolveCmd, kResolveOpts, "Uses DNSServiceResolve() to resolve a service.", false ),
+ Command( "reconfirm", ReconfirmCmd, kReconfirmOpts, "Uses DNSServiceReconfirmRecord() to reconfirm a record.", false ),
+ Command( "getaddrinfo-posix", GetAddrInfoPOSIXCmd, kGetAddrInfoPOSIXOpts, "Uses getaddrinfo() to resolve a hostname to IP addresses.", false ),
+ Command( "reverseLookup", ReverseLookupCmd, kReverseLookupOpts, "Uses DNSServiceQueryRecord() to perform a reverse IP address lookup.", false ),
+ Command( "portMapping", PortMappingCmd, kPortMappingOpts, "Uses DNSServiceNATPortMappingCreate() to create a port mapping.", false ),
+ Command( "browseAll", BrowseAllCmd, kBrowseAllOpts, "Browse and resolve all (or specific) services and, optionally, attempt connections.", false ),
+
+ // Uncommon commands.
+
+ Command( "getnameinfo", GetNameInfoCmd, kGetNameInfoOpts, "Calls getnameinfo() and prints results.", true ),
+ Command( "getAddrInfoStress", GetAddrInfoStressCmd, kGetAddrInfoStressOpts, "Runs DNSServiceGetAddrInfo() stress testing.", true ),
+ Command( "DNSQuery", DNSQueryCmd, kDNSQueryOpts, "Crafts and sends a DNS query.", true ),
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+ Command( "DNSCrypt", DNSCryptCmd, kDNSCryptOpts, "Crafts and sends a DNSCrypt query.", true ),
+#endif
+ Command( "mdnsquery", MDNSQueryCmd, kMDNSQueryOpts, "Crafts and sends an mDNS query over the specified interface.", true ),
+ Command( "mdnscollider", MDNSColliderCmd, kMDNSColliderOpts, "Creates record name collision scenarios.", true ),
+ Command( "pid2uuid", PIDToUUIDCmd, kPIDToUUIDOpts, "Prints the UUID of a process.", true ),
+ Command( "server", DNSServerCmd, kDNSServerOpts, "DNS server for testing.", true ),
+ Command( "mdnsreplier", MDNSReplierCmd, kMDNSReplierOpts, "Responds to mDNS queries for a set of authoritative resource records.", true ),
+ Command( "test", NULL, kTestOpts, "Commands for testing DNS-SD.", true ),
+ Command( "ssdp", NULL, kSSDPOpts, "Simple Service Discovery Protocol (SSDP).", true ),
+#if( TARGET_OS_DARWIN )
+ Command( "legacy", NULL, kLegacyOpts, "Legacy DNS API.", true ),
+ Command( "dnsconfig", NULL, kDNSConfigOpts, "Add/remove a supplemental resolver entry to/from the system's DNS configuration.", true ),
+ Command( "xpcsend", XPCSendCmd, kXPCSendOpts, "Sends a message to an XPC service.", true ),
+#endif
+#if ( MDNSRESPONDER_PROJECT )
+ Command( "interfaceMonitor", InterfaceMonitorCmd, kInterfaceMonitorOpts, "mDNSResponder's interface monitor.", true ),
+ Command( "dnsproxy", DNSProxyCmd, kDNSProxyOpts, "Enables mDNSResponder's DNS proxy.", true ),
+#endif
+ Command( "daemonVersion", DaemonVersionCmd, NULL, "Prints the version of the DNS-SD daemon.", true ),
+
+ CLI_COMMAND_HELP(),
+ CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+// Helper Prototypes
+//===========================================================================================================================
+
+#define kExitReason_OneShotDone "one-shot done"
+#define kExitReason_ReceivedResponse "received response"
+#define kExitReason_SIGINT "interrupt signal"
+#define kExitReason_Timeout "timeout"
+#define kExitReason_TimeLimit "time limit"
+
+static void Exit( void *inContext ) ATTRIBUTE_NORETURN;
+
+static DNSServiceFlags GetDNSSDFlagsFromOpts( void );
+
+typedef enum
+{
+ kConnectionType_None = 0,
+ kConnectionType_Normal = 1,
+ kConnectionType_DelegatePID = 2,
+ kConnectionType_DelegateUUID = 3
+
+} ConnectionType;
+
+typedef struct
+{
+ ConnectionType type;
+ union
+ {
+ int32_t pid;
+ uint8_t uuid[ 16 ];
+
+ } delegate;
+
+} ConnectionDesc;
+
+static OSStatus
+ CreateConnectionFromArgString(
+ const char * inString,
+ dispatch_queue_t inQueue,
+ DNSServiceRef * outSDRef,
+ ConnectionDesc * outDesc );
+static OSStatus InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex );
+static OSStatus RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen );
+static OSStatus RecordTypeFromArgString( const char *inString, uint16_t *outValue );
+static OSStatus RecordClassFromArgString( const char *inString, uint16_t *outValue );
+
+#define kInterfaceNameBufLen ( Max( IF_NAMESIZE, 16 ) + 1 )
+
+static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] );
+static const char * RecordTypeToString( unsigned int inValue );
+
+static OSStatus
+ DNSRecordDataToString(
+ const void * inRDataPtr,
+ size_t inRDataLen,
+ unsigned int inRDataType,
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ char ** outString );
+
+static OSStatus
+ DNSMessageToText(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ Boolean inIsMDNS,
+ Boolean inPrintRaw,
+ char ** outText );
+
+static OSStatus
+ WriteDNSQueryMessage(
+ uint8_t inMsg[ kDNSQueryMessageMaxLen ],
+ uint16_t inMsgID,
+ uint16_t inFlags,
+ const char * inQName,
+ uint16_t inQType,
+ uint16_t inQClass,
+ size_t * outMsgLen );
+
+// Dispatch helpers
+
+typedef void ( *DispatchHandler )( void *inContext );
+
+static OSStatus
+ DispatchSignalSourceCreate(
+ int inSignal,
+ DispatchHandler inEventHandler,
+ void * inContext,
+ dispatch_source_t * outSource );
+static OSStatus
+ DispatchSocketSourceCreate(
+ SocketRef inSock,
+ dispatch_source_type_t inType,
+ dispatch_queue_t inQueue,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outSource );
+
+#define DispatchReadSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
+ DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_READ, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
+
+#define DispatchWriteSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
+ DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_WRITE, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
+
+static OSStatus
+ DispatchTimerCreate(
+ dispatch_time_t inStart,
+ uint64_t inIntervalNs,
+ uint64_t inLeewayNs,
+ dispatch_queue_t inQueue,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outTimer );
+
+#define DispatchTimerOneShotCreate( IN_START, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, IN_CONTEXT, OUT_TIMER ) \
+ DispatchTimerCreate( IN_START, DISPATCH_TIME_FOREVER, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, NULL, IN_CONTEXT, OUT_TIMER )
+
+static OSStatus
+ DispatchProcessMonitorCreate(
+ pid_t inPID,
+ unsigned long inFlags,
+ dispatch_queue_t inQueue,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outMonitor );
+
+static const char * ServiceTypeDescription( const char *inName );
+
+typedef struct
+{
+ SocketRef sock; // Socket.
+ void * userContext; // User context.
+ int32_t refCount; // Reference count.
+
+} SocketContext;
+
+static OSStatus SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext );
+static SocketContext * SocketContextRetain( SocketContext *inContext );
+static void SocketContextRelease( SocketContext *inContext );
+static void SocketContextCancelHandler( void *inContext );
+
+#define ForgetSocketContext( X ) ForgetCustom( X, SocketContextRelease )
+
+static OSStatus StringToInt32( const char *inString, int32_t *outValue );
+static OSStatus StringToUInt32( const char *inString, uint32_t *outValue );
+#if( TARGET_OS_DARWIN )
+static int64_t _StringToInt64( const char *inString, OSStatus *outError );
+static uint64_t _StringToUInt64( const char *inString, OSStatus *outError );
+static pid_t _StringToPID( const char *inString, OSStatus *outError );
+static OSStatus
+ _ParseEscapedString(
+ const char * inSrc,
+ const char * inEnd,
+ const char * inDelimiters,
+ char * inBufPtr,
+ size_t inBufLen,
+ size_t * outCopiedLen,
+ size_t * outActualLen,
+ const char ** outPtr );
+#endif
+static OSStatus StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
+static OSStatus StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
+static OSStatus StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen );
+#if( TARGET_OS_DARWIN )
+static OSStatus GetDefaultDNSServer( sockaddr_ip *outAddr );
+#endif
+static OSStatus
+ _ServerSocketOpenEx2(
+ int inFamily,
+ int inType,
+ int inProtocol,
+ const void * inAddr,
+ int inPort,
+ int * outPort,
+ int inRcvBufSize,
+ Boolean inNoPortReuse,
+ SocketRef * outSock );
+
+static const struct sockaddr * GetMDNSMulticastAddrV4( void );
+static const struct sockaddr * GetMDNSMulticastAddrV6( void );
+
+static OSStatus
+ CreateMulticastSocket(
+ const struct sockaddr * inAddr,
+ int inPort,
+ const char * inIfName,
+ uint32_t inIfIndex,
+ Boolean inJoin,
+ int * outPort,
+ SocketRef * outSock );
+
+static OSStatus DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr );
+static OSStatus CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax );
+static OSStatus CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax );
+static OSStatus CheckRootUser( void );
+static OSStatus SpawnCommand( pid_t *outPID, const char *inFormat, ... );
+static OSStatus OutputFormatFromArgString( const char *inArgString, OutputFormatType *outFormat );
+static OSStatus OutputPropertyList( CFPropertyListRef inPList, OutputFormatType inType, const char *inOutputFilePath );
+static OSStatus CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen );
+static OSStatus CreateTXTRecordDataFromString( const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen );
+static OSStatus
+ CreateNSECRecordData(
+ const uint8_t * inNextDomainName,
+ uint8_t ** outPtr,
+ size_t * outLen,
+ unsigned int inTypeCount,
+ ... );
+static OSStatus
+ AppendSOARecord(
+ DataBuffer * inDB,
+ const uint8_t * inNamePtr,
+ size_t inNameLen,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ const uint8_t * inMName,
+ const uint8_t * inRName,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimumTTL,
+ size_t * outLen );
+static OSStatus
+ CreateSOARecordData(
+ const uint8_t * inMName,
+ const uint8_t * inRName,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimumTTL,
+ uint8_t ** outPtr,
+ size_t * outLen );
+static OSStatus
+ _DataBuffer_AppendDNSQuestion(
+ DataBuffer * inDB,
+ const uint8_t * inNamePtr,
+ size_t inNameLen,
+ uint16_t inType,
+ uint16_t inClass );
+static OSStatus
+ _DataBuffer_AppendDNSRecord(
+ DataBuffer * inDB,
+ const uint8_t * inNamePtr,
+ size_t inNameLen,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ const uint8_t * inRDataPtr,
+ size_t inRDataLen );
+static char * _NanoTime64ToTimestamp( NanoTime64 inTime, char *inBuf, size_t inMaxLen );
+
+typedef struct MDNSInterfaceItem MDNSInterfaceItem;
+struct MDNSInterfaceItem
+{
+ MDNSInterfaceItem * next;
+ char * ifName;
+ uint32_t ifIndex;
+ Boolean hasIPv4;
+ Boolean hasIPv6;
+ Boolean isAWDL;
+ Boolean isWiFi;
+};
+
+typedef enum
+{
+ kMDNSInterfaceSubset_All = 0, // All mDNS-capable interfaces.
+ kMDNSInterfaceSubset_AWDL = 1, // All mDNS-capable AWDL interfaces.
+ kMDNSInterfaceSubset_NonAWDL = 2 // All mDNS-capable non-AWDL iterfaces.
+
+} MDNSInterfaceSubset;
+
+static OSStatus _MDNSInterfaceListCreate( MDNSInterfaceSubset inSubset, size_t inItemSize, MDNSInterfaceItem **outList );
+static void _MDNSInterfaceListFree( MDNSInterfaceItem *inList );
+#define _MDNSInterfaceListForget( X ) ForgetCustom( X, _MDNSInterfaceListFree )
+static OSStatus _MDNSInterfaceGetAny( MDNSInterfaceSubset inSubset, char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex );
+
+static OSStatus _SetComputerName( CFStringRef inComputerName, CFStringEncoding inEncoding );
+static OSStatus _SetComputerNameWithUTF8CString( const char *inComputerName );
+static OSStatus _SetLocalHostName( CFStringRef inLocalHostName );
+static OSStatus _SetLocalHostNameWithUTF8CString( const char *inLocalHostName );
+
+static OSStatus _SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs );
+static OSStatus
+ _StringToIPv4Address(
+ const char * inStr,
+ StringToIPAddressFlags inFlags,
+ uint32_t * outIP,
+ int * outPort,
+ uint32_t * outSubnet,
+ uint32_t * outRouter,
+ const char ** outStr );
+static void _StringArray_Free( char **inArray, size_t inCount );
+static OSStatus
+ _StringToIPv6Address(
+ const char * inStr,
+ StringToIPAddressFlags inFlags,
+ uint8_t outIPv6[ 16 ],
+ uint32_t * outScope,
+ int * outPort,
+ int * outPrefix,
+ const char ** outStr );
+static Boolean
+ _ParseQuotedEscapedString(
+ const char * inSrc,
+ const char * inEnd,
+ const char * inDelimiters,
+ char * inBuf,
+ size_t inMaxLen,
+ size_t * outCopiedLen,
+ size_t * outTotalLen,
+ const char ** outSrc );
+static void * _memdup( const void *inPtr, size_t inLen );
+static int _memicmp( const void *inP1, const void *inP2, size_t inLen );
+static uint32_t _FNV1( const void *inData, size_t inSize );
+
+#define Unused( X ) (void)(X)
+
+//===========================================================================================================================
+// MDNSCollider
+//===========================================================================================================================
+
+typedef struct MDNSColliderPrivate * MDNSColliderRef;
+
+typedef uint32_t MDNSColliderProtocols;
+#define kMDNSColliderProtocol_None 0
+#define kMDNSColliderProtocol_IPv4 ( 1 << 0 )
+#define kMDNSColliderProtocol_IPv6 ( 1 << 1 )
+
+typedef void ( *MDNSColliderStopHandler_f )( void *inContext, OSStatus inError );
+
+static OSStatus MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider );
+static OSStatus MDNSColliderStart( MDNSColliderRef inCollider );
+static void MDNSColliderStop( MDNSColliderRef inCollider );
+static void MDNSColliderSetProtocols( MDNSColliderRef inCollider, MDNSColliderProtocols inProtocols );
+static void MDNSColliderSetInterfaceIndex( MDNSColliderRef inCollider, uint32_t inInterfaceIndex );
+static OSStatus MDNSColliderSetProgram( MDNSColliderRef inCollider, const char *inProgramStr );
+static void
+ MDNSColliderSetStopHandler(
+ MDNSColliderRef inCollider,
+ MDNSColliderStopHandler_f inStopHandler,
+ void * inStopContext );
+static OSStatus
+ MDNSColliderSetRecord(
+ MDNSColliderRef inCollider,
+ const uint8_t * inName,
+ uint16_t inType,
+ const void * inRDataPtr,
+ size_t inRDataLen );
+static CFTypeID MDNSColliderGetTypeID( void );
+
+//===========================================================================================================================
+// ServiceBrowser
+//===========================================================================================================================
+
+typedef struct ServiceBrowserPrivate * ServiceBrowserRef;
+typedef struct ServiceBrowserResults ServiceBrowserResults;
+typedef struct SBRDomain SBRDomain;
+typedef struct SBRServiceType SBRServiceType;
+typedef struct SBRServiceInstance SBRServiceInstance;
+typedef struct SBRIPAddress SBRIPAddress;
+
+typedef void ( *ServiceBrowserCallback_f )( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
+
+struct ServiceBrowserResults
+{
+ SBRDomain * domainList; // List of domains in which services were found.
+};
+
+struct SBRDomain
+{
+ SBRDomain * next; // Next domain in list.
+ char * name; // Name of domain represented by this object.
+ SBRServiceType * typeList; // List of service types in this domain.
+};
+
+struct SBRServiceType
+{
+ SBRServiceType * next; // Next service type in list.
+ char * name; // Name of service type represented by this object.
+ SBRServiceInstance * instanceList; // List of service instances of this service type.
+};
+
+struct SBRServiceInstance
+{
+ SBRServiceInstance * next; // Next service instance in list.
+ char * name; // Name of service instance represented by this object.
+ char * hostname; // Target from service instance's SRV record.
+ uint32_t ifIndex; // Index of interface over which this service instance was discovered.
+ uint16_t port; // Port from service instance's SRV record.
+ uint8_t * txtPtr; // Service instance's TXT record data.
+ size_t txtLen; // Service instance's TXT record data length.
+ SBRIPAddress * ipaddrList; // List of IP addresses that the hostname resolved to.
+ uint64_t discoverTimeUs; // Time it took to discover this service instance in microseconds.
+ uint64_t resolveTimeUs; // Time it took to resolve this service instance in microseconds.
+};
+
+struct SBRIPAddress
+{
+ SBRIPAddress * next; // Next IP address in list.
+ sockaddr_ip sip; // IPv4 or IPv6 address.
+ uint64_t resolveTimeUs; // Time it took to resolve this IP address in microseconds.
+};
+
+static CFTypeID ServiceBrowserGetTypeID( void );
+static OSStatus
+ ServiceBrowserCreate(
+ dispatch_queue_t inQueue,
+ uint32_t inInterfaceIndex,
+ const char * inDomain,
+ unsigned int inBrowseTimeSecs,
+ Boolean inIncludeAWDL,
+ ServiceBrowserRef * outBrowser );
+static void ServiceBrowserStart( ServiceBrowserRef inBrowser );
+static OSStatus ServiceBrowserAddServiceType( ServiceBrowserRef inBrowser, const char *inServiceType );
+static void
+ ServiceBrowserSetCallback(
+ ServiceBrowserRef inBrowser,
+ ServiceBrowserCallback_f inCallback,
+ void * inContext );
+static void ServiceBrowserResultsRetain( ServiceBrowserResults *inResults );
+static void ServiceBrowserResultsRelease( ServiceBrowserResults *inResults );
+
+#define ForgetServiceBrowserResults( X ) ForgetCustom( X, ServiceBrowserResultsRelease )
+
+//===========================================================================================================================
+// main
+//===========================================================================================================================
+
+#define _PRINTF_EXTENSION_HANDLER_DECLARE( NAME ) \
+ static int \
+ _PrintFExtension ## NAME ## Handler( \
+ PrintFContext * inContext, \
+ PrintFFormat * inFormat, \
+ PrintFVAList * inArgs, \
+ void * inUserContext )
+
+_PRINTF_EXTENSION_HANDLER_DECLARE( Timestamp );
+_PRINTF_EXTENSION_HANDLER_DECLARE( DNSMessage );
+_PRINTF_EXTENSION_HANDLER_DECLARE( CallbackFlags );
+_PRINTF_EXTENSION_HANDLER_DECLARE( DNSRecordData );
+
+int main( int argc, const char **argv )
+{
+ OSStatus err;
+
+ // Route DebugServices logging output to stderr.
+
+ dlog_control( "DebugServices:output=file;stderr" );
+
+ PrintFRegisterExtension( "du:time", _PrintFExtensionTimestampHandler, NULL );
+ PrintFRegisterExtension( "du:dnsmsg", _PrintFExtensionDNSMessageHandler, NULL );
+ PrintFRegisterExtension( "du:cbflags", _PrintFExtensionCallbackFlagsHandler, NULL );
+ PrintFRegisterExtension( "du:rdata", _PrintFExtensionDNSRecordDataHandler, NULL );
+ CLIInit( argc, argv );
+ err = CLIParse( kGlobalOpts, kCLIFlags_None );
+ if( err ) exit( 1 );
+
+ return( gExitCode );
+}
+
+//===========================================================================================================================
+// VersionOptionCallback
+//===========================================================================================================================
+
+static OSStatus VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset )
+{
+ const char * srcVers;
+#if( MDNSRESPONDER_PROJECT )
+ char srcStr[ 16 ];
+#endif
+
+ Unused( inOption );
+ Unused( inArg );
+ Unused( inUnset );
+
+#if( MDNSRESPONDER_PROJECT )
+ srcVers = SourceVersionToCString( _DNS_SD_H, srcStr );
+#else
+ srcVers = DNSSDUTIL_SOURCE_VERSION;
+#endif
+ FPrintF( stdout, "%s version %v (%s)\n", gProgramName, kDNSSDUtilNumVersion, srcVers );
+
+ return( kEndingErr );
+}
+
+//===========================================================================================================================
+// BrowseCmd
+//===========================================================================================================================
+
+typedef struct BrowseResolveOp BrowseResolveOp;
+
+struct BrowseResolveOp
+{
+ BrowseResolveOp * next; // Next resolve operation in list.
+ DNSServiceRef sdRef; // sdRef of the DNSServiceResolve or DNSServiceQueryRecord operation.
+ char * fullName; // Full name of the service to resolve.
+ uint32_t interfaceIndex; // Interface index of the DNSServiceResolve or DNSServiceQueryRecord operation.
+};
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef * opRefs; // Array of sdRefs for individual Browse operarions.
+ size_t opRefsCount; // Count of array of sdRefs for non-shared connections.
+ const char * domain; // Domain for DNSServiceBrowse operation(s).
+ DNSServiceFlags flags; // Flags for DNSServiceBrowse operation(s).
+ char ** serviceTypes; // Array of service types to browse for.
+ size_t serviceTypesCount; // Count of array of service types to browse for.
+ int timeLimitSecs; // Time limit of DNSServiceBrowse operation in seconds.
+ BrowseResolveOp * resolveList; // List of resolve and/or TXT record query operations.
+ uint32_t ifIndex; // Interface index of DNSServiceBrowse operation(s).
+ Boolean printedHeader; // True if results header has been printed.
+ Boolean doResolve; // True if service instances are to be resolved.
+ Boolean doResolveTXTOnly; // True if TXT records of service instances are to be queried.
+
+} BrowseContext;
+
+static void BrowsePrintPrologue( const BrowseContext *inContext );
+static void BrowseContextFree( BrowseContext *inContext );
+static OSStatus BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp );
+static void BrowseResolveOpFree( BrowseResolveOp *inOp );
+static void DNSSD_API
+ BrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext );
+static void DNSSD_API
+ BrowseResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext );
+static void DNSSD_API
+ BrowseQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void BrowseCmd( void )
+{
+ OSStatus err;
+ size_t i;
+ BrowseContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (BrowseContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->opRefs = (DNSServiceRef *) calloc( gBrowse_ServiceTypesCount, sizeof( DNSServiceRef ) );
+ require_action( context->opRefs, exit, err = kNoMemoryErr );
+ context->opRefsCount = gBrowse_ServiceTypesCount;
+
+ // Check command parameters.
+
+ if( gBrowse_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d seconds.\n", gBrowse_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ context->serviceTypes = gBrowse_ServiceTypes;
+ context->serviceTypesCount = gBrowse_ServiceTypesCount;
+ context->domain = gBrowse_Domain;
+ context->doResolve = gBrowse_DoResolve ? true : false;
+ context->timeLimitSecs = gBrowse_TimeLimitSecs;
+ context->doResolveTXTOnly = gBrowse_QueryTXT ? true : false;
+
+ // Print prologue.
+
+ BrowsePrintPrologue( context );
+
+ // Start operation(s).
+
+ for( i = 0; i < context->serviceTypesCount; ++i )
+ {
+ DNSServiceRef sdRef;
+
+ sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+ err = DNSServiceBrowse( &sdRef, context->flags, context->ifIndex, context->serviceTypes[ i ], context->domain,
+ BrowseCallback, context );
+ require_noerr( err, exit );
+
+ context->opRefs[ i ] = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRefs[ i ], dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) BrowseContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowsePrintPrologue
+//===========================================================================================================================
+
+static void BrowsePrintPrologue( const BrowseContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ const char * const * ptr = (const char **) inContext->serviceTypes;
+ const char * const * const end = (const char **) inContext->serviceTypes + inContext->serviceTypesCount;
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Service types: %s", *ptr++ );
+ while( ptr < end ) FPrintF( stdout, ", %s", *ptr++ );
+ FPrintF( stdout, "\n" );
+ FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// BrowseContextFree
+//===========================================================================================================================
+
+static void BrowseContextFree( BrowseContext *inContext )
+{
+ size_t i;
+
+ for( i = 0; i < inContext->opRefsCount; ++i )
+ {
+ DNSServiceForget( &inContext->opRefs[ i ] );
+ }
+ if( inContext->serviceTypes )
+ {
+ _StringArray_Free( inContext->serviceTypes, inContext->serviceTypesCount );
+ inContext->serviceTypes = NULL;
+ inContext->serviceTypesCount = 0;
+ }
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// BrowseResolveOpCreate
+//===========================================================================================================================
+
+static OSStatus BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp )
+{
+ OSStatus err;
+ BrowseResolveOp * resolveOp;
+
+ resolveOp = (BrowseResolveOp *) calloc( 1, sizeof( *resolveOp ) );
+ require_action( resolveOp, exit, err = kNoMemoryErr );
+
+ resolveOp->fullName = strdup( inFullName );
+ require_action( resolveOp->fullName, exit, err = kNoMemoryErr );
+
+ resolveOp->interfaceIndex = inInterfaceIndex;
+
+ *outOp = resolveOp;
+ resolveOp = NULL;
+ err = kNoErr;
+
+exit:
+ if( resolveOp ) BrowseResolveOpFree( resolveOp );
+ return( err );
+}
+
+//===========================================================================================================================
+// BrowseResolveOpFree
+//===========================================================================================================================
+
+static void BrowseResolveOpFree( BrowseResolveOp *inOp )
+{
+ DNSServiceForget( &inOp->sdRef );
+ ForgetMem( &inOp->fullName );
+ free( inOp );
+}
+
+//===========================================================================================================================
+// BrowseCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext )
+{
+ BrowseContext * const context = (BrowseContext *) inContext;
+ OSStatus err;
+ BrowseResolveOp * newOp = NULL;
+ BrowseResolveOp ** p;
+ char fullName[ kDNSServiceMaxDomainName ];
+ struct timeval now;
+
+ Unused( inSDRef );
+
+ gettimeofday( &now, NULL );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s %-16s IF %-20s %-20s Instance Name\n", "Timestamp", "Flags", "Domain", "Service Type" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%{du:time} %{du:cbflags} %2d %-20s %-20s %s\n",
+ &now, inFlags, (int32_t) inInterfaceIndex, inDomain, inRegType, inName );
+
+ if( !context->doResolve && !context->doResolveTXTOnly ) goto exit;
+
+ err = DNSServiceConstructFullName( fullName, inName, inRegType, inDomain );
+ require_noerr( err, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+
+ err = BrowseResolveOpCreate( fullName, inInterfaceIndex, &newOp );
+ require_noerr( err, exit );
+
+ if( context->mainRef )
+ {
+ sdRef = context->mainRef;
+ flags = kDNSServiceFlagsShareConnection;
+ }
+ else
+ {
+ flags = 0;
+ }
+ if( context->doResolve )
+ {
+ err = DNSServiceResolve( &sdRef, flags, inInterfaceIndex, inName, inRegType, inDomain, BrowseResolveCallback,
+ NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DNSServiceQueryRecord( &sdRef, flags, inInterfaceIndex, fullName, kDNSServiceType_TXT, kDNSServiceClass_IN,
+ BrowseQueryRecordCallback, NULL );
+ require_noerr( err, exit );
+ }
+
+ newOp->sdRef = sdRef;
+ if( !context->mainRef )
+ {
+ err = DNSServiceSetDispatchQueue( newOp->sdRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+ for( p = &context->resolveList; *p; p = &( *p )->next ) {}
+ *p = newOp;
+ newOp = NULL;
+ }
+ else
+ {
+ BrowseResolveOp * resolveOp;
+
+ for( p = &context->resolveList; ( resolveOp = *p ) != NULL; p = &resolveOp->next )
+ {
+ if( ( resolveOp->interfaceIndex == inInterfaceIndex ) && ( strcasecmp( resolveOp->fullName, fullName ) == 0 ) )
+ {
+ break;
+ }
+ }
+ if( resolveOp )
+ {
+ *p = resolveOp->next;
+ BrowseResolveOpFree( resolveOp );
+ }
+ }
+
+exit:
+ if( newOp ) BrowseResolveOpFree( newOp );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ struct timeval now;
+
+ Unused( inSDRef );
+ Unused( inClass );
+ Unused( inTTL );
+ Unused( inContext );
+
+ gettimeofday( &now, NULL );
+
+ err = inError;
+ require_noerr( err, exit );
+ require_action( inType == kDNSServiceType_TXT, exit, err = kTypeErr );
+
+ FPrintF( stdout, "%{du:time} %s %s TXT on interface %d\n TXT: %#{txt}\n",
+ &now, DNSServiceFlagsToAddRmvStr( inFlags ), inFullName, (int32_t) inInterfaceIndex, inRDataPtr,
+ (size_t) inRDataLen );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// BrowseResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ BrowseResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext )
+{
+ struct timeval now;
+ char errorStr[ 64 ];
+
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inContext );
+
+ gettimeofday( &now, NULL );
+
+ if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
+
+ FPrintF( stdout, "%{du:time} %s can be reached at %s:%u (interface %d)%?s\n",
+ &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
+ if( inTXTLen == 1 )
+ {
+ FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
+ }
+ else
+ {
+ FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
+ }
+}
+
+//===========================================================================================================================
+// GetAddrInfoCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef opRef; // sdRef for the DNSServiceGetAddrInfo operation.
+ const char * name; // Hostname to resolve.
+ DNSServiceFlags flags; // Flags argument for DNSServiceGetAddrInfo().
+ DNSServiceProtocol protocols; // Protocols argument for DNSServiceGetAddrInfo().
+ uint32_t ifIndex; // Interface index argument for DNSServiceGetAddrInfo().
+ int timeLimitSecs; // Time limit for the DNSServiceGetAddrInfo() operation in seconds.
+ Boolean printedHeader; // True if the results header has been printed.
+ Boolean oneShotMode; // True if command is done after the first set of results (one-shot mode).
+ Boolean needIPv4; // True if in one-shot mode and an IPv4 result is needed.
+ Boolean needIPv6; // True if in one-shot mode and an IPv6 result is needed.
+
+} GetAddrInfoContext;
+
+static void GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext );
+static void GetAddrInfoContextFree( GetAddrInfoContext *inContext );
+static void DNSSD_API
+ GetAddrInfoCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void GetAddrInfoCmd( void )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ GetAddrInfoContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Check command parameters.
+
+ if( gGetAddrInfo_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d s.\n", gGetAddrInfo_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (GetAddrInfoContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ context->name = gGetAddrInfo_Name;
+ context->timeLimitSecs = gGetAddrInfo_TimeLimitSecs;
+ if( gGetAddrInfo_ProtocolIPv4 ) context->protocols |= kDNSServiceProtocol_IPv4;
+ if( gGetAddrInfo_ProtocolIPv6 ) context->protocols |= kDNSServiceProtocol_IPv6;
+ if( gGetAddrInfo_OneShot )
+ {
+ context->oneShotMode = true;
+ context->needIPv4 = ( gGetAddrInfo_ProtocolIPv4 || !gGetAddrInfo_ProtocolIPv6 ) ? true : false;
+ context->needIPv6 = ( gGetAddrInfo_ProtocolIPv6 || !gGetAddrInfo_ProtocolIPv4 ) ? true : false;
+ }
+
+ // Print prologue.
+
+ GetAddrInfoPrintPrologue( context );
+
+ // Start operation.
+
+ sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+ err = DNSServiceGetAddrInfo( &sdRef, context->flags, context->ifIndex, context->protocols, context->name,
+ GetAddrInfoCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) GetAddrInfoContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GetAddrInfoPrintPrologue
+//===========================================================================================================================
+
+static void GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Protocols: %#{flags}\n", inContext->protocols, kDNSServiceProtocolDescriptors );
+ FPrintF( stdout, "Name: %s\n", inContext->name );
+ FPrintF( stdout, "Mode: %s\n", inContext->oneShotMode ? "one-shot" : "continuous" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// GetAddrInfoContextFree
+//===========================================================================================================================
+
+static void GetAddrInfoContextFree( GetAddrInfoContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// GetAddrInfoCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ GetAddrInfoCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ GetAddrInfoContext * const context = (GetAddrInfoContext *) inContext;
+ struct timeval now;
+ OSStatus err;
+ const char * addrStr;
+ char addrStrBuf[ kSockAddrStringMaxSize ];
+
+ Unused( inSDRef );
+
+ gettimeofday( &now, NULL );
+
+ switch( inError )
+ {
+ case kDNSServiceErr_NoError:
+ case kDNSServiceErr_NoSuchRecord:
+ err = kNoErr;
+ break;
+
+ case kDNSServiceErr_Timeout:
+ Exit( kExitReason_Timeout );
+
+ default:
+ err = inError;
+ goto exit;
+ }
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ err = kTypeErr;
+ goto exit;
+ }
+
+ if( !inError )
+ {
+ err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
+ require_noerr( err, exit );
+ addrStr = addrStrBuf;
+ }
+ else
+ {
+ addrStr = ( inSockAddr->sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr;
+ }
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s %-16s IF %-30s %-34s %6s\n", "Timestamp", "Flags", "Hostname", "Address", "TTL" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%{du:time} %{du:cbflags} %2d %-30s %-34s %6u\n",
+ &now, inFlags, (int32_t) inInterfaceIndex, inHostname, addrStr, inTTL );
+
+ if( context->oneShotMode )
+ {
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ if( inSockAddr->sa_family == AF_INET ) context->needIPv4 = false;
+ else context->needIPv6 = false;
+ }
+ if( !( inFlags & kDNSServiceFlagsMoreComing ) && !context->needIPv4 && !context->needIPv6 )
+ {
+ Exit( kExitReason_OneShotDone );
+ }
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// QueryRecordCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef opRef; // sdRef for the DNSServiceQueryRecord operation.
+ const char * recordName; // Resource record name argument for DNSServiceQueryRecord().
+ DNSServiceFlags flags; // Flags argument for DNSServiceQueryRecord().
+ uint32_t ifIndex; // Interface index argument for DNSServiceQueryRecord().
+ int timeLimitSecs; // Time limit for the DNSServiceQueryRecord() operation in seconds.
+ uint16_t recordType; // Resource record type argument for DNSServiceQueryRecord().
+ Boolean printedHeader; // True if the results header was printed.
+ Boolean oneShotMode; // True if command is done after the first set of results (one-shot mode).
+ Boolean gotRecord; // True if in one-shot mode and received at least one record of the desired type.
+ Boolean printRawRData; // True if RDATA results are not to be formatted when printed.
+
+} QueryRecordContext;
+
+static void QueryRecordPrintPrologue( const QueryRecordContext *inContext );
+static void QueryRecordContextFree( QueryRecordContext *inContext );
+static void DNSSD_API
+ QueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void QueryRecordCmd( void )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ QueryRecordContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( gQueryRecord_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d seconds.\n", gQueryRecord_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gQueryRecord_Type, &context->recordType );
+ require_noerr( err, exit );
+
+ // Set remaining parameters.
+
+ context->recordName = gQueryRecord_Name;
+ context->timeLimitSecs = gQueryRecord_TimeLimitSecs;
+ context->oneShotMode = gQueryRecord_OneShot ? true : false;
+ context->printRawRData = gQueryRecord_RawRData ? true : false;
+
+ // Print prologue.
+
+ QueryRecordPrintPrologue( context );
+
+ // Start operation.
+
+ sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+ err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
+ kDNSServiceClass_IN, QueryRecordCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_TimeLimit,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) QueryRecordContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// QueryRecordContextFree
+//===========================================================================================================================
+
+static void QueryRecordContextFree( QueryRecordContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// QueryRecordPrintPrologue
+//===========================================================================================================================
+
+static void QueryRecordPrintPrologue( const QueryRecordContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->recordName );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->recordType ), inContext->recordType );
+ FPrintF( stdout, "Mode: %s\n", inContext->oneShotMode ? "one-shot" : "continuous" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+}
+
+//===========================================================================================================================
+// QueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ QueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ QueryRecordContext * const context = (QueryRecordContext *) inContext;
+ struct timeval now;
+ OSStatus err;
+ char * rdataStr = NULL;
+
+ Unused( inSDRef );
+
+ gettimeofday( &now, NULL );
+
+ switch( inError )
+ {
+ case kDNSServiceErr_NoError:
+ case kDNSServiceErr_NoSuchRecord:
+ err = kNoErr;
+ break;
+
+ case kDNSServiceErr_Timeout:
+ Exit( kExitReason_Timeout );
+
+ default:
+ err = inError;
+ goto exit;
+ }
+
+ if( inError != kDNSServiceErr_NoSuchRecord )
+ {
+ if( !context->printRawRData ) DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
+ if( !rdataStr )
+ {
+ ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, INT_MAX );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ }
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s %-16s IF %-32s %-5s %-5s %6s RData\n",
+ "Timestamp", "Flags", "Name", "Type", "Class", "TTL" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%{du:time} %{du:cbflags} %2d %-32s %-5s %?-5s%?5u %6u %s\n",
+ &now, inFlags, (int32_t) inInterfaceIndex, inFullName, RecordTypeToString( inType ),
+ ( inClass == kDNSServiceClass_IN ), "IN", ( inClass != kDNSServiceClass_IN ), inClass, inTTL,
+ rdataStr ? rdataStr : kNoSuchRecordStr );
+
+ if( context->oneShotMode )
+ {
+ if( ( inFlags & kDNSServiceFlagsAdd ) &&
+ ( ( context->recordType == kDNSServiceType_ANY ) || ( context->recordType == inType ) ) )
+ {
+ context->gotRecord = true;
+ }
+ if( !( inFlags & kDNSServiceFlagsMoreComing ) && context->gotRecord ) Exit( kExitReason_OneShotDone );
+ }
+
+exit:
+ FreeNullSafe( rdataStr );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSRecordRef recordRef; // Reference returned by DNSServiceAddRecord().
+ uint8_t * dataPtr; // Record data.
+ size_t dataLen; // Record data length.
+ uint32_t ttl; // Record TTL value.
+ uint16_t type; // Record type.
+
+} ExtraRecord;
+
+typedef struct
+{
+ DNSServiceRef opRef; // sdRef for DNSServiceRegister operation.
+ const char * name; // Service name argument for DNSServiceRegister().
+ const char * type; // Service type argument for DNSServiceRegister().
+ const char * domain; // Domain in which advertise the service.
+ uint8_t * txtPtr; // Service TXT record data. (malloc'd)
+ size_t txtLen; // Service TXT record data len.
+ ExtraRecord * extraRecords; // Array of extra records to add to registered service.
+ size_t extraRecordsCount; // Number of extra records.
+ uint8_t * updateTXTPtr; // Pointer to record data for TXT record update. (malloc'd)
+ size_t updateTXTLen; // Length of record data for TXT record update.
+ uint32_t updateTTL; // TTL of updated TXT record.
+ int updateDelayMs; // Post-registration TXT record update delay in milliseconds.
+ DNSServiceFlags flags; // Flags argument for DNSServiceRegister().
+ uint32_t ifIndex; // Interface index argument for DNSServiceRegister().
+ int lifetimeMs; // Lifetime of the record registration in milliseconds.
+ uint16_t port; // Service instance's port number.
+ Boolean printedHeader; // True if results header was printed.
+ Boolean didRegister; // True if service was registered.
+
+} RegisterContext;
+
+static void RegisterPrintPrologue( const RegisterContext *inContext );
+static void RegisterContextFree( RegisterContext *inContext );
+static void DNSSD_API
+ RegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext );
+static void RegisterUpdate( void *inContext );
+
+static void RegisterCmd( void )
+{
+ OSStatus err;
+ RegisterContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (RegisterContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( ( gRegister_Port < 0 ) || ( gRegister_Port > UINT16_MAX ) )
+ {
+ FPrintF( stderr, "Port number %d is out-of-range.\n", gRegister_Port );
+ err = kParamErr;
+ goto exit;
+ }
+
+ if( ( gAddRecord_DataCount != gAddRecord_TypesCount ) || ( gAddRecord_TTLsCount != gAddRecord_TypesCount ) )
+ {
+ FPrintF( stderr, "There are missing additional record parameters.\n" );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get TXT record data.
+
+ if( gRegister_TXT )
+ {
+ err = RecordDataFromArgString( gRegister_TXT, &context->txtPtr, &context->txtLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // Set remaining parameters.
+
+ context->name = gRegister_Name;
+ context->type = gRegister_Type;
+ context->domain = gRegister_Domain;
+ context->port = (uint16_t) gRegister_Port;
+ context->lifetimeMs = gRegister_LifetimeMs;
+
+ if( gAddRecord_TypesCount > 0 )
+ {
+ size_t i;
+
+ context->extraRecords = (ExtraRecord *) calloc( gAddRecord_TypesCount, sizeof( ExtraRecord ) );
+ require_action( context, exit, err = kNoMemoryErr );
+ context->extraRecordsCount = gAddRecord_TypesCount;
+
+ for( i = 0; i < gAddRecord_TypesCount; ++i )
+ {
+ ExtraRecord * const extraRecord = &context->extraRecords[ i ];
+
+ err = RecordTypeFromArgString( gAddRecord_Types[ i ], &extraRecord->type );
+ require_noerr( err, exit );
+
+ err = StringToUInt32( gAddRecord_TTLs[ i ], &extraRecord->ttl );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid TTL value: %s\n", gAddRecord_TTLs[ i ] );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = RecordDataFromArgString( gAddRecord_Data[ i ], &extraRecord->dataPtr, &extraRecord->dataLen );
+ require_noerr_quiet( err, exit );
+ }
+ }
+
+ if( gUpdateRecord_Data )
+ {
+ err = RecordDataFromArgString( gUpdateRecord_Data, &context->updateTXTPtr, &context->updateTXTLen );
+ require_noerr_quiet( err, exit );
+
+ context->updateTTL = (uint32_t) gUpdateRecord_TTL;
+ context->updateDelayMs = gUpdateRecord_DelayMs;
+ }
+
+ // Print prologue.
+
+ RegisterPrintPrologue( context );
+
+ // Start operation.
+
+ err = DNSServiceRegister( &context->opRef, context->flags, context->ifIndex, context->name, context->type,
+ context->domain, NULL, htons( context->port ), (uint16_t) context->txtLen, context->txtPtr,
+ RegisterCallback, context );
+ ForgetMem( &context->txtPtr );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) RegisterContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterPrintPrologue
+//===========================================================================================================================
+
+static void RegisterPrintPrologue( const RegisterContext *inContext )
+{
+ size_t i;
+ int infinite;
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->name ? inContext->name : "<NULL>" );
+ FPrintF( stdout, "Type: %s\n", inContext->type );
+ FPrintF( stdout, "Domain: %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
+ FPrintF( stdout, "Port: %u\n", inContext->port );
+ FPrintF( stdout, "TXT data: %#{txt}\n", inContext->txtPtr, inContext->txtLen );
+ infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
+ FPrintF( stdout, "Lifetime: %?s%?d ms\n", infinite, "∞", !infinite, inContext->lifetimeMs );
+ if( inContext->updateTXTPtr )
+ {
+ FPrintF( stdout, "\nUpdate record:\n" );
+ FPrintF( stdout, " Delay: %d ms\n", ( inContext->updateDelayMs > 0 ) ? inContext->updateDelayMs : 0 );
+ FPrintF( stdout, " TTL: %u%?s\n",
+ inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
+ FPrintF( stdout, " TXT data: %#{txt}\n", inContext->updateTXTPtr, inContext->updateTXTLen );
+ }
+ if( inContext->extraRecordsCount > 0 ) FPrintF( stdout, "\n" );
+ for( i = 0; i < inContext->extraRecordsCount; ++i )
+ {
+ const ExtraRecord * record = &inContext->extraRecords[ i ];
+
+ FPrintF( stdout, "Extra record %zu:\n", i + 1 );
+ FPrintF( stdout, " Type: %s (%u)\n", RecordTypeToString( record->type ), record->type );
+ FPrintF( stdout, " TTL: %u%?s\n", record->ttl, record->ttl == 0, " (system will use a default value.)" );
+ FPrintF( stdout, " RData: %#H\n\n", record->dataPtr, (int) record->dataLen, INT_MAX );
+ }
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// RegisterContextFree
+//===========================================================================================================================
+
+static void RegisterContextFree( RegisterContext *inContext )
+{
+ ExtraRecord * record;
+ const ExtraRecord * const end = inContext->extraRecords + inContext->extraRecordsCount;
+
+ DNSServiceForget( &inContext->opRef );
+ ForgetMem( &inContext->txtPtr );
+ for( record = inContext->extraRecords; record < end; ++record )
+ {
+ check( !record->recordRef );
+ ForgetMem( &record->dataPtr );
+ }
+ ForgetMem( &inContext->extraRecords );
+ ForgetMem( &inContext->updateTXTPtr );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// RegisterCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ RegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext )
+{
+ RegisterContext * const context = (RegisterContext *) inContext;
+ OSStatus err;
+ struct timeval now;
+
+ Unused( inSDRef );
+
+ gettimeofday( &now, NULL );
+
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s %-16s Service\n", "Timestamp", "Flags" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%{du:time} %{du:cbflags} %s.%s%s %?#m\n", &now, inFlags, inName, inType, inDomain, inError, inError );
+
+ require_noerr_action_quiet( inError, exit, err = inError );
+
+ if( !context->didRegister && ( inFlags & kDNSServiceFlagsAdd ) )
+ {
+ context->didRegister = true;
+ if( context->updateTXTPtr )
+ {
+ if( context->updateDelayMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
+ context, RegisterUpdate );
+ }
+ else
+ {
+ RegisterUpdate( context );
+ }
+ }
+ if( context->extraRecordsCount > 0 )
+ {
+ ExtraRecord * record;
+ const ExtraRecord * const end = context->extraRecords + context->extraRecordsCount;
+
+ for( record = context->extraRecords; record < end; ++record )
+ {
+ err = DNSServiceAddRecord( context->opRef, &record->recordRef, 0, record->type,
+ (uint16_t) record->dataLen, record->dataPtr, record->ttl );
+ require_noerr( err, exit );
+ }
+ }
+ if( context->lifetimeMs == 0 )
+ {
+ Exit( kExitReason_TimeLimit );
+ }
+ else if( context->lifetimeMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterUpdate
+//===========================================================================================================================
+
+static void RegisterUpdate( void *inContext )
+{
+ OSStatus err;
+ RegisterContext * const context = (RegisterContext *) inContext;
+
+ err = DNSServiceUpdateRecord( context->opRef, NULL, 0, (uint16_t) context->updateTXTLen, context->updateTXTPtr,
+ context->updateTTL );
+ require_noerr( err, exit );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterRecordCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef conRef; // sdRef to be initialized by DNSServiceCreateConnection().
+ DNSRecordRef recordRef; // Registered record reference.
+ const char * recordName; // Name of resource record.
+ uint8_t * dataPtr; // Pointer to resource record data.
+ size_t dataLen; // Length of resource record data.
+ uint32_t ttl; // TTL value of resource record in seconds.
+ uint32_t ifIndex; // Interface index argument for DNSServiceRegisterRecord().
+ DNSServiceFlags flags; // Flags argument for DNSServiceRegisterRecord().
+ int lifetimeMs; // Lifetime of the record registration in milliseconds.
+ uint16_t recordType; // Resource record type.
+ uint8_t * updateDataPtr; // Pointer to data for record update. (malloc'd)
+ size_t updateDataLen; // Length of data for record update.
+ uint32_t updateTTL; // TTL for updated record.
+ int updateDelayMs; // Post-registration record update delay in milliseconds.
+ Boolean didRegister; // True if the record was registered.
+
+} RegisterRecordContext;
+
+static void RegisterRecordPrintPrologue( const RegisterRecordContext *inContext );
+static void RegisterRecordContextFree( RegisterRecordContext *inContext );
+static void DNSSD_API
+ RegisterRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSRecordRef inRecordRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ void * inContext );
+static void RegisterRecordUpdate( void *inContext );
+
+static void RegisterRecordCmd( void )
+{
+ OSStatus err;
+ RegisterRecordContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (RegisterRecordContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Create connection.
+
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->conRef, NULL );
+ require_noerr_quiet( err, exit );
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+
+ // Get interface.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gRegisterRecord_Type, &context->recordType );
+ require_noerr( err, exit );
+
+ // Get record data.
+
+ if( gRegisterRecord_Data )
+ {
+ err = RecordDataFromArgString( gRegisterRecord_Data, &context->dataPtr, &context->dataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // Set remaining parameters.
+
+ context->recordName = gRegisterRecord_Name;
+ context->ttl = (uint32_t) gRegisterRecord_TTL;
+ context->lifetimeMs = gRegisterRecord_LifetimeMs;
+
+ // Get update data.
+
+ if( gRegisterRecord_UpdateData )
+ {
+ err = RecordDataFromArgString( gRegisterRecord_UpdateData, &context->updateDataPtr, &context->updateDataLen );
+ require_noerr_quiet( err, exit );
+
+ context->updateTTL = (uint32_t) gRegisterRecord_UpdateTTL;
+ context->updateDelayMs = gRegisterRecord_UpdateDelayMs;
+ }
+
+ // Print prologue.
+
+ RegisterRecordPrintPrologue( context );
+
+ // Start operation.
+
+ err = DNSServiceRegisterRecord( context->conRef, &context->recordRef, context->flags, context->ifIndex,
+ context->recordName, context->recordType, kDNSServiceClass_IN, (uint16_t) context->dataLen, context->dataPtr,
+ context->ttl, RegisterRecordCallback, context );
+ if( err )
+ {
+ FPrintF( stderr, "DNSServiceRegisterRecord() returned %#m\n", err );
+ goto exit;
+ }
+
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) RegisterRecordContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// RegisterRecordPrintPrologue
+//===========================================================================================================================
+
+static void RegisterRecordPrintPrologue( const RegisterRecordContext *inContext )
+{
+ int infinite;
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->recordName );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->recordType ), inContext->recordType );
+ FPrintF( stdout, "TTL: %u\n", inContext->ttl );
+ FPrintF( stdout, "Data: %#H\n", inContext->dataPtr, (int) inContext->dataLen, INT_MAX );
+ infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
+ FPrintF( stdout, "Lifetime: %?s%?d ms\n", infinite, "∞", !infinite, inContext->lifetimeMs );
+ if( inContext->updateDataPtr )
+ {
+ FPrintF( stdout, "\nUpdate record:\n" );
+ FPrintF( stdout, " Delay: %d ms\n", ( inContext->updateDelayMs >= 0 ) ? inContext->updateDelayMs : 0 );
+ FPrintF( stdout, " TTL: %u%?s\n",
+ inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
+ FPrintF( stdout, " RData: %#H\n", inContext->updateDataPtr, (int) inContext->updateDataLen, INT_MAX );
+ }
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// RegisterRecordContextFree
+//===========================================================================================================================
+
+static void RegisterRecordContextFree( RegisterRecordContext *inContext )
+{
+ DNSServiceForget( &inContext->conRef );
+ ForgetMem( &inContext->dataPtr );
+ ForgetMem( &inContext->updateDataPtr );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// RegisterRecordCallback
+//===========================================================================================================================
+
+static void
+ RegisterRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSRecordRef inRecordRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ void * inContext )
+{
+ RegisterRecordContext * context = (RegisterRecordContext *) inContext;
+ struct timeval now;
+
+ Unused( inSDRef );
+ Unused( inRecordRef );
+ Unused( inFlags );
+ Unused( context );
+
+ gettimeofday( &now, NULL );
+ FPrintF( stdout, "%{du:time} Record registration result (error %#m)\n", &now, inError );
+
+ if( !context->didRegister && !inError )
+ {
+ context->didRegister = true;
+ if( context->updateDataPtr )
+ {
+ if( context->updateDelayMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
+ context, RegisterRecordUpdate );
+ }
+ else
+ {
+ RegisterRecordUpdate( context );
+ }
+ }
+ if( context->lifetimeMs == 0 )
+ {
+ Exit( kExitReason_TimeLimit );
+ }
+ else if( context->lifetimeMs > 0 )
+ {
+ dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ }
+}
+
+//===========================================================================================================================
+// RegisterRecordUpdate
+//===========================================================================================================================
+
+static void RegisterRecordUpdate( void *inContext )
+{
+ OSStatus err;
+ RegisterRecordContext * const context = (RegisterRecordContext *) inContext;
+
+ err = DNSServiceUpdateRecord( context->conRef, context->recordRef, 0, (uint16_t) context->updateDataLen,
+ context->updateDataPtr, context->updateTTL );
+ require_noerr( err, exit );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ResolveCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connections.
+ DNSServiceRef opRef; // sdRef for the DNSServiceResolve operation.
+ DNSServiceFlags flags; // Flags argument for DNSServiceResolve().
+ const char * name; // Service name argument for DNSServiceResolve().
+ const char * type; // Service type argument for DNSServiceResolve().
+ const char * domain; // Domain argument for DNSServiceResolve().
+ uint32_t ifIndex; // Interface index argument for DNSServiceResolve().
+ int timeLimitSecs; // Time limit for the DNSServiceResolve operation in seconds.
+
+} ResolveContext;
+
+static void ResolvePrintPrologue( const ResolveContext *inContext );
+static void ResolveContextFree( ResolveContext *inContext );
+static void DNSSD_API
+ ResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext );
+
+static void ResolveCmd( void )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ ResolveContext * context = NULL;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (ResolveContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( gResolve_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d seconds.\n", gResolve_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ context->name = gResolve_Name;
+ context->type = gResolve_Type;
+ context->domain = gResolve_Domain;
+ context->timeLimitSecs = gResolve_TimeLimitSecs;
+
+ // Print prologue.
+
+ ResolvePrintPrologue( context );
+
+ // Start operation.
+
+ sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+ err = DNSServiceResolve( &sdRef, context->flags, context->ifIndex, context->name, context->type, context->domain,
+ ResolveCallback, NULL );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) ResolveContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ReconfirmCmd
+//===========================================================================================================================
+
+static void ReconfirmCmd( void )
+{
+ OSStatus err;
+ uint8_t * rdataPtr = NULL;
+ size_t rdataLen = 0;
+ DNSServiceFlags flags;
+ uint32_t ifIndex;
+ uint16_t type, class;
+ char ifName[ kInterfaceNameBufLen ];
+
+ // Get flags.
+
+ flags = GetDNSSDFlagsFromOpts();
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gReconfirmRecord_Type, &type );
+ require_noerr( err, exit );
+
+ // Get record data.
+
+ if( gReconfirmRecord_Data )
+ {
+ err = RecordDataFromArgString( gReconfirmRecord_Data, &rdataPtr, &rdataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // Get record class.
+
+ if( gReconfirmRecord_Class )
+ {
+ err = RecordClassFromArgString( gReconfirmRecord_Class, &class );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ class = kDNSServiceClass_IN;
+ }
+
+ // Print prologue.
+
+ FPrintF( stdout, "Flags: %#{flags}\n", flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+ FPrintF( stdout, "Name: %s\n", gReconfirmRecord_Name );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
+ FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+ FPrintF( stdout, "Data: %#H\n", rdataPtr, (int) rdataLen, INT_MAX );
+ FPrintF( stdout, "---\n" );
+
+ err = DNSServiceReconfirmRecord( flags, ifIndex, gReconfirmRecord_Name, type, class, (uint16_t) rdataLen, rdataPtr );
+ FPrintF( stdout, "Error: %#m\n", err );
+
+exit:
+ FreeNullSafe( rdataPtr );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ResolvePrintPrologue
+//===========================================================================================================================
+
+static void ResolvePrintPrologue( const ResolveContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->name );
+ FPrintF( stdout, "Type: %s\n", inContext->type );
+ FPrintF( stdout, "Domain: %s\n", inContext->domain );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// ResolveContextFree
+//===========================================================================================================================
+
+static void ResolveContextFree( ResolveContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// ResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ ResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext )
+{
+ struct timeval now;
+ char errorStr[ 64 ];
+
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inContext );
+
+ gettimeofday( &now, NULL );
+
+ if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
+
+ FPrintF( stdout, "%{du:time}: %s can be reached at %s:%u (interface %d)%?s\n",
+ &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
+ if( inTXTLen == 1 )
+ {
+ FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
+ }
+ else
+ {
+ FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
+ }
+}
+
+//===========================================================================================================================
+// GetAddrInfoPOSIXCmd
+//===========================================================================================================================
+
+#define AddressFamilyStr( X ) ( \
+ ( (X) == AF_INET ) ? "inet" : \
+ ( (X) == AF_INET6 ) ? "inet6" : \
+ ( (X) == AF_UNSPEC ) ? "unspec" : \
+ "???" )
+
+typedef struct
+{
+ unsigned int flag;
+ const char * str;
+
+} FlagStringPair;
+
+#define CaseFlagStringify( X ) { (X), # X }
+
+const FlagStringPair kGAIPOSIXFlagStringPairs[] =
+{
+#if( defined( AI_UNUSABLE ) )
+ CaseFlagStringify( AI_UNUSABLE ),
+#endif
+ CaseFlagStringify( AI_NUMERICSERV ),
+ CaseFlagStringify( AI_V4MAPPED ),
+ CaseFlagStringify( AI_ADDRCONFIG ),
+#if( defined( AI_V4MAPPED_CFG ) )
+ CaseFlagStringify( AI_V4MAPPED_CFG ),
+#endif
+ CaseFlagStringify( AI_ALL ),
+ CaseFlagStringify( AI_NUMERICHOST ),
+ CaseFlagStringify( AI_CANONNAME ),
+ CaseFlagStringify( AI_PASSIVE ),
+ { 0, NULL }
+};
+
+static void GetAddrInfoPOSIXCmd( void )
+{
+ OSStatus err;
+ struct addrinfo hints;
+ struct timeval now;
+ const struct addrinfo * addrInfo;
+ struct addrinfo * addrInfoList = NULL;
+ const FlagStringPair * pair;
+
+ memset( &hints, 0, sizeof( hints ) );
+ hints.ai_socktype = SOCK_STREAM;
+
+ // Set hints address family.
+
+ if( !gGAIPOSIX_Family ) hints.ai_family = AF_UNSPEC;
+ else if( strcasecmp( gGAIPOSIX_Family, "inet" ) == 0 ) hints.ai_family = AF_INET;
+ else if( strcasecmp( gGAIPOSIX_Family, "inet6" ) == 0 ) hints.ai_family = AF_INET6;
+ else if( strcasecmp( gGAIPOSIX_Family, "unspec" ) == 0 ) hints.ai_family = AF_UNSPEC;
+ else
+ {
+ FPrintF( stderr, "Invalid address family: %s.\n", gGAIPOSIX_Family );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Set hints flags.
+
+ if( gGAIPOSIXFlag_AddrConfig ) hints.ai_flags |= AI_ADDRCONFIG;
+ if( gGAIPOSIXFlag_All ) hints.ai_flags |= AI_ALL;
+ if( gGAIPOSIXFlag_CanonName ) hints.ai_flags |= AI_CANONNAME;
+ if( gGAIPOSIXFlag_NumericHost ) hints.ai_flags |= AI_NUMERICHOST;
+ if( gGAIPOSIXFlag_NumericServ ) hints.ai_flags |= AI_NUMERICSERV;
+ if( gGAIPOSIXFlag_Passive ) hints.ai_flags |= AI_PASSIVE;
+ if( gGAIPOSIXFlag_V4Mapped ) hints.ai_flags |= AI_V4MAPPED;
+#if( defined( AI_V4MAPPED_CFG ) )
+ if( gGAIPOSIXFlag_V4MappedCFG ) hints.ai_flags |= AI_V4MAPPED_CFG;
+#endif
+#if( defined( AI_DEFAULT ) )
+ if( gGAIPOSIXFlag_Default ) hints.ai_flags |= AI_DEFAULT;
+#endif
+#if( defined( AI_UNUSABLE ) )
+ if( gGAIPOSIXFlag_Unusable ) hints.ai_flags |= AI_UNUSABLE;
+#endif
+
+ // Print prologue.
+
+ FPrintF( stdout, "Hostname: %s\n", gGAIPOSIX_HostName );
+ FPrintF( stdout, "Servname: %s\n", gGAIPOSIX_ServName );
+ FPrintF( stdout, "Address family: %s\n", AddressFamilyStr( hints.ai_family ) );
+ FPrintF( stdout, "Flags: 0x%X < ", hints.ai_flags );
+ for( pair = kGAIPOSIXFlagStringPairs; pair->str != NULL; ++pair )
+ {
+ if( ( (unsigned int) hints.ai_flags ) & pair->flag ) FPrintF( stdout, "%s ", pair->str );
+ }
+ FPrintF( stdout, ">\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ // Call getaddrinfo().
+
+ err = getaddrinfo( gGAIPOSIX_HostName, gGAIPOSIX_ServName, &hints, &addrInfoList );
+ gettimeofday( &now, NULL );
+ if( err )
+ {
+ FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
+ }
+ else
+ {
+ int addrCount = 0;
+
+ for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next ) { ++addrCount; }
+
+ FPrintF( stdout, "Addresses (%d total):\n", addrCount );
+ for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next )
+ {
+ FPrintF( stdout, "%##a\n", addrInfo->ai_addr );
+ }
+ }
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %{du:time}\n", &now );
+
+exit:
+ if( addrInfoList ) freeaddrinfo( addrInfoList );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ReverseLookupCmd
+//===========================================================================================================================
+
+#define kIP6ARPADomainStr "ip6.arpa."
+
+static void ReverseLookupCmd( void )
+{
+ OSStatus err;
+ QueryRecordContext * context = NULL;
+ DNSServiceRef sdRef;
+ dispatch_source_t signalSource = NULL;
+ uint32_t ipv4Addr;
+ uint8_t ipv6Addr[ 16 ];
+ char recordName[ ( 16 * 4 ) + sizeof( kIP6ARPADomainStr ) ];
+ int useMainConnection;
+ const char * endPtr;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( gReverseLookup_TimeLimitSecs < 0 )
+ {
+ FPrintF( stderr, "Invalid time limit: %d s.\n", gReverseLookup_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Create reverse lookup record name.
+
+ err = _StringToIPv4Address( gReverseLookup_IPAddr, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix,
+ &ipv4Addr, NULL, NULL, NULL, &endPtr );
+ if( err || ( *endPtr != '\0' ) )
+ {
+ char * dst;
+ int i;
+
+ err = _StringToIPv6Address( gReverseLookup_IPAddr,
+ kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
+ ipv6Addr, NULL, NULL, NULL, &endPtr );
+ if( err || ( *endPtr != '\0' ) )
+ {
+ FPrintF( stderr, "Invalid IP address: \"%s\".\n", gReverseLookup_IPAddr );
+ err = kParamErr;
+ goto exit;
+ }
+ dst = recordName;
+ for( i = 15; i >= 0; --i )
+ {
+ *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] & 0x0F ];
+ *dst++ = '.';
+ *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] >> 4 ];
+ *dst++ = '.';
+ }
+ strcpy_literal( dst, kIP6ARPADomainStr );
+ check( ( strlen( recordName ) + 1 ) <= sizeof( recordName ) );
+ }
+ else
+ {
+ SNPrintF( recordName, sizeof( recordName ), "%u.%u.%u.%u.in-addr.arpa.",
+ ipv4Addr & 0xFF,
+ ( ipv4Addr >> 8 ) & 0xFF,
+ ( ipv4Addr >> 16 ) & 0xFF,
+ ( ipv4Addr >> 24 ) & 0xFF );
+ }
+
+ // Set remaining parameters.
+
+ context->recordName = recordName;
+ context->recordType = kDNSServiceType_PTR;
+ context->timeLimitSecs = gReverseLookup_TimeLimitSecs;
+ context->oneShotMode = gReverseLookup_OneShot ? true : false;
+
+ // Print prologue.
+
+ QueryRecordPrintPrologue( context );
+
+ // Start operation.
+
+ sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+ err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
+ kDNSServiceClass_IN, QueryRecordCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ // Set time limit.
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+ kExitReason_TimeLimit, Exit );
+ }
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) QueryRecordContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// PortMappingCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef; // Main sdRef for shared connection.
+ DNSServiceRef opRef; // sdRef for the DNSServiceNATPortMappingCreate operation.
+ DNSServiceFlags flags; // Flags for DNSServiceNATPortMappingCreate operation.
+ uint32_t ifIndex; // Interface index argument for DNSServiceNATPortMappingCreate operation.
+ DNSServiceProtocol protocols; // Protocols argument for DNSServiceNATPortMappingCreate operation.
+ uint32_t ttl; // TTL argument for DNSServiceNATPortMappingCreate operation.
+ uint16_t internalPort; // Internal port argument for DNSServiceNATPortMappingCreate operation.
+ uint16_t externalPort; // External port argument for DNSServiceNATPortMappingCreate operation.
+ Boolean printedHeader; // True if results header was printed.
+
+} PortMappingContext;
+
+static void PortMappingPrintPrologue( const PortMappingContext *inContext );
+static void PortMappingContextFree( PortMappingContext *inContext );
+static void DNSSD_API
+ PortMappingCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ uint32_t inExternalIPv4Address,
+ DNSServiceProtocol inProtocol,
+ uint16_t inInternalPort,
+ uint16_t inExternalPort,
+ uint32_t inTTL,
+ void * inContext );
+
+static void PortMappingCmd( void )
+{
+ OSStatus err;
+ PortMappingContext * context = NULL;
+ DNSServiceRef sdRef;
+ dispatch_source_t signalSource = NULL;
+ int useMainConnection;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Create context.
+
+ context = (PortMappingContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // Check command parameters.
+
+ if( ( gPortMapping_InternalPort < 0 ) || ( gPortMapping_InternalPort > UINT16_MAX ) )
+ {
+ FPrintF( stderr, "Internal port number %d is out-of-range.\n", gPortMapping_InternalPort );
+ err = kParamErr;
+ goto exit;
+ }
+
+ if( ( gPortMapping_ExternalPort < 0 ) || ( gPortMapping_ExternalPort > UINT16_MAX ) )
+ {
+ FPrintF( stderr, "External port number %d is out-of-range.\n", gPortMapping_ExternalPort );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create main connection.
+
+ if( gConnectionOpt )
+ {
+ err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+ require_noerr_quiet( err, exit );
+ useMainConnection = true;
+ }
+ else
+ {
+ useMainConnection = false;
+ }
+
+ // Get flags.
+
+ context->flags = GetDNSSDFlagsFromOpts();
+ if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Set remaining parameters.
+
+ if( gPortMapping_ProtocolTCP ) context->protocols |= kDNSServiceProtocol_TCP;
+ if( gPortMapping_ProtocolUDP ) context->protocols |= kDNSServiceProtocol_UDP;
+ context->ttl = (uint32_t) gPortMapping_TTL;
+ context->internalPort = (uint16_t) gPortMapping_InternalPort;
+ context->externalPort = (uint16_t) gPortMapping_ExternalPort;
+
+ // Print prologue.
+
+ PortMappingPrintPrologue( context );
+
+ // Start operation.
+
+ sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+ err = DNSServiceNATPortMappingCreate( &sdRef, context->flags, context->ifIndex, context->protocols,
+ htons( context->internalPort ), htons( context->externalPort ), context->ttl, PortMappingCallback, context );
+ require_noerr( err, exit );
+
+ context->opRef = sdRef;
+ if( !useMainConnection )
+ {
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+ }
+
+ dispatch_main();
+
+exit:
+ dispatch_source_forget( &signalSource );
+ if( context ) PortMappingContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// PortMappingPrintPrologue
+//===========================================================================================================================
+
+static void PortMappingPrintPrologue( const PortMappingContext *inContext )
+{
+ char ifName[ kInterfaceNameBufLen ];
+
+ InterfaceIndexToName( inContext->ifIndex, ifName );
+
+ FPrintF( stdout, "Flags: %#{flags}\n", inContext->flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, ifName );
+ FPrintF( stdout, "Protocols: %#{flags}\n", inContext->protocols, kDNSServiceProtocolDescriptors );
+ FPrintF( stdout, "Internal Port: %u\n", inContext->internalPort );
+ FPrintF( stdout, "External Port: %u\n", inContext->externalPort );
+ FPrintF( stdout, "TTL: %u%?s\n", inContext->ttl, !inContext->ttl,
+ " (system will use a default value.)" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+}
+
+//===========================================================================================================================
+// PortMappingContextFree
+//===========================================================================================================================
+
+static void PortMappingContextFree( PortMappingContext *inContext )
+{
+ DNSServiceForget( &inContext->opRef );
+ DNSServiceForget( &inContext->mainRef );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// PortMappingCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ PortMappingCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ uint32_t inExternalIPv4Address,
+ DNSServiceProtocol inProtocol,
+ uint16_t inInternalPort,
+ uint16_t inExternalPort,
+ uint32_t inTTL,
+ void * inContext )
+{
+ PortMappingContext * const context = (PortMappingContext *) inContext;
+ struct timeval now;
+ char errorStr[ 128 ];
+
+ Unused( inSDRef );
+ Unused( inFlags );
+
+ gettimeofday( &now, NULL );
+
+ if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " (error: %#m)", inError );
+ if( !context->printedHeader )
+ {
+ FPrintF( stdout, "%-26s IF %7s %15s %7s %6s Protocol\n", "Timestamp", "IntPort", "ExtAddr", "ExtPort", "TTL" );
+ context->printedHeader = true;
+ }
+ FPrintF( stdout, "%{du:time} %2u %7u %15.4a %7u %6u %#{flags}%?s\n",
+ &now, inInterfaceIndex, ntohs( inInternalPort), &inExternalIPv4Address, ntohs( inExternalPort ), inTTL,
+ inProtocol, kDNSServiceProtocolDescriptors, inError, errorStr );
+}
+
+//===========================================================================================================================
+// BrowseAllCmd
+//===========================================================================================================================
+
+typedef struct BrowseAllConnection BrowseAllConnection;
+
+typedef struct
+{
+ ServiceBrowserRef browser; // Service browser.
+ ServiceBrowserResults * results; // Results from the service browser.
+ BrowseAllConnection * connectionList; // List of connections.
+ dispatch_source_t connectionTimer; // Timer for connection timeout.
+ int connectionPendingCount; // Number of pending connections.
+ int connectionTimeoutSecs; // Timeout value for connections in seconds.
+
+} BrowseAllContext;
+
+struct BrowseAllConnection
+{
+ BrowseAllConnection * next; // Next connection object in list.
+ sockaddr_ip sip; // IPv4 or IPv6 address to connect to.
+ uint16_t port; // TCP port to connect to.
+ AsyncConnectionRef asyncCnx; // AsyncConnection object to handle the actual connection.
+ OSStatus status; // Status of connection. NoErr means connection succeeded.
+ CFTimeInterval connectTimeSecs; // Time it took to connect in seconds.
+ int32_t refCount; // This object's reference count.
+ BrowseAllContext * context; // Back pointer to parent context.
+};
+
+static void _BrowseAllContextFree( BrowseAllContext *inContext );
+static void _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
+static OSStatus
+ _BrowseAllConnectionCreate(
+ const struct sockaddr * inSockAddr,
+ uint16_t inPort,
+ BrowseAllContext * inContext,
+ BrowseAllConnection ** outConnection );
+static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection );
+static void _BrowseAllConnectionRelease( BrowseAllConnection *inConnection );
+static void _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg );
+static void _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg );
+static void _BrowseAllExit( void *inContext );
+
+static Boolean _IsServiceTypeTCP( const char *inServiceType );
+
+static void BrowseAllCmd( void )
+{
+ OSStatus err;
+ BrowseAllContext * context = NULL;
+ size_t i;
+ uint32_t ifIndex;
+ char ifName[ kInterfaceNameBufLen ];
+
+ // Check parameters.
+
+ if( gBrowseAll_BrowseTimeSecs <= 0 )
+ {
+ FPrintF( stdout, "Invalid browse time: %d seconds.\n", gBrowseAll_BrowseTimeSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ context = (BrowseAllContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->connectionTimeoutSecs = gBrowseAll_ConnectTimeout;
+#if( TARGET_OS_POSIX )
+ // Increase the open file descriptor limit for connection sockets.
+
+ if( context->connectionTimeoutSecs > 0 )
+ {
+ struct rlimit fdLimits;
+
+ err = getrlimit( RLIMIT_NOFILE, &fdLimits );
+ err = map_global_noerr_errno( err );
+ require_noerr( err, exit );
+
+ if( fdLimits.rlim_cur < 4096 )
+ {
+ fdLimits.rlim_cur = 4096;
+ err = setrlimit( RLIMIT_NOFILE, &fdLimits );
+ err = map_global_noerr_errno( err );
+ require_noerr( err, exit );
+ }
+ }
+#endif
+
+ // Get interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ // Print prologue.
+
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+ FPrintF( stdout, "Service types: ");
+ if( gBrowseAll_ServiceTypesCount > 0 )
+ {
+ FPrintF( stdout, "%s", gBrowseAll_ServiceTypes[ 0 ] );
+ for( i = 1; i < gBrowseAll_ServiceTypesCount; ++i )
+ {
+ FPrintF( stdout, ", %s", gBrowseAll_ServiceTypes[ i ] );
+ }
+ FPrintF( stdout, "\n" );
+ }
+ else
+ {
+ FPrintF( stdout, "all services\n" );
+ }
+ FPrintF( stdout, "Domain: %s\n", gBrowseAll_Domain ? gBrowseAll_Domain : "default domains" );
+ FPrintF( stdout, "Browse time: %d second%?c\n", gBrowseAll_BrowseTimeSecs, gBrowseAll_BrowseTimeSecs != 1, 's' );
+ FPrintF( stdout, "Connect timeout: %d second%?c\n",
+ context->connectionTimeoutSecs, context->connectionTimeoutSecs != 1, 's' );
+ FPrintF( stdout, "IncludeAWDL: %s\n", gDNSSDFlag_IncludeAWDL ? "yes" : "no" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ err = ServiceBrowserCreate( dispatch_get_main_queue(), ifIndex, gBrowseAll_Domain,
+ (unsigned int) gBrowseAll_BrowseTimeSecs, gDNSSDFlag_IncludeAWDL ? true : false, &context->browser );
+ require_noerr( err, exit );
+
+ for( i = 0; i < gBrowseAll_ServiceTypesCount; ++i )
+ {
+ err = ServiceBrowserAddServiceType( context->browser, gBrowseAll_ServiceTypes[ i ] );
+ require_noerr( err, exit );
+ }
+ ServiceBrowserSetCallback( context->browser, _BrowseAllServiceBrowserCallback, context );
+ ServiceBrowserStart( context->browser );
+ dispatch_main();
+
+exit:
+ if( context ) _BrowseAllContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// _BrowseAllContextFree
+//===========================================================================================================================
+
+static void _BrowseAllContextFree( BrowseAllContext *inContext )
+{
+ check( !inContext->browser );
+ check( !inContext->connectionTimer );
+ check( !inContext->connectionList );
+ ForgetServiceBrowserResults( &inContext->results );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// _BrowseAllServiceBrowserCallback
+//===========================================================================================================================
+
+#define kDiscardProtocolPort 9
+
+static void _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
+{
+ OSStatus err;
+ BrowseAllContext * const context = (BrowseAllContext *) inContext;
+ SBRDomain * domain;
+ SBRServiceType * type;
+ SBRServiceInstance * instance;
+ SBRIPAddress * ipaddr;
+
+ Unused( inError );
+
+ require_action( inResults, exit, err = kUnexpectedErr );
+
+ check( !context->results );
+ context->results = inResults;
+ ServiceBrowserResultsRetain( context->results );
+
+ check( context->connectionPendingCount == 0 );
+ if( context->connectionTimeoutSecs > 0 )
+ {
+ BrowseAllConnection * connection;
+ BrowseAllConnection ** connectionPtr = &context->connectionList;
+ char destination[ kSockAddrStringMaxSize ];
+
+ for( domain = context->results->domainList; domain; domain = domain->next )
+ {
+ for( type = domain->typeList; type; type = type->next )
+ {
+ if( !_IsServiceTypeTCP( type->name ) ) continue;
+ for( instance = type->instanceList; instance; instance = instance->next )
+ {
+ if( instance->port == kDiscardProtocolPort ) continue;
+ for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
+ {
+ err = _BrowseAllConnectionCreate( &ipaddr->sip.sa, instance->port, context, &connection );
+ require_noerr( err, exit );
+
+ *connectionPtr = connection;
+ connectionPtr = &connection->next;
+
+ err = SockAddrToString( &ipaddr->sip, kSockAddrStringFlagsNoPort, destination );
+ check_noerr( err );
+ if( !err )
+ {
+ err = AsyncConnection_Connect( &connection->asyncCnx, destination, -instance->port,
+ kAsyncConnectionFlag_P2P, kAsyncConnectionNoTimeout,
+ kSocketBufferSize_DontSet, kSocketBufferSize_DontSet,
+ _BrowseAllConnectionProgress, connection, _BrowseAllConnectionHandler, connection,
+ dispatch_get_main_queue() );
+ check_noerr( err );
+ }
+ if( !err )
+ {
+ _BrowseAllConnectionRetain( connection );
+ connection->status = kInProgressErr;
+ ++context->connectionPendingCount;
+ }
+ else
+ {
+ connection->status = err;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( context->connectionPendingCount > 0 )
+ {
+ check( !context->connectionTimer );
+ err = DispatchTimerCreate( dispatch_time_seconds( context->connectionTimeoutSecs ), DISPATCH_TIME_FOREVER,
+ 100 * kNanosecondsPerMillisecond, NULL, _BrowseAllExit, NULL, context, &context->connectionTimer );
+ require_noerr( err, exit );
+ dispatch_resume( context->connectionTimer );
+ }
+ else
+ {
+ dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
+ }
+ err = kNoErr;
+
+exit:
+ ForgetCF( &context->browser );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// _BrowseAllConnectionCreate
+//===========================================================================================================================
+
+static OSStatus
+ _BrowseAllConnectionCreate(
+ const struct sockaddr * inSockAddr,
+ uint16_t inPort,
+ BrowseAllContext * inContext,
+ BrowseAllConnection ** outConnection )
+{
+ OSStatus err;
+ BrowseAllConnection * obj;
+
+ obj = (BrowseAllConnection *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->refCount = 1;
+ SockAddrCopy( inSockAddr, &obj->sip );
+ obj->port = inPort;
+ obj->context = inContext;
+
+ *outConnection = obj;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _BrowseAllConnectionRetain
+//===========================================================================================================================
+
+static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection )
+{
+ ++inConnection->refCount;
+}
+
+//===========================================================================================================================
+// _BrowseAllConnectionRelease
+//===========================================================================================================================
+
+static void _BrowseAllConnectionRelease( BrowseAllConnection *inConnection )
+{
+ if( --inConnection->refCount == 0 ) free( inConnection );
+}
+
+//===========================================================================================================================
+// _BrowseAllConnectionProgress
+//===========================================================================================================================
+
+static void _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg )
+{
+ BrowseAllConnection * const connection = (BrowseAllConnection *) inArg;
+
+ if( inPhase == kAsyncConnectionPhase_Connected )
+ {
+ const AsyncConnectedInfo * const info = (AsyncConnectedInfo *) inDetails;
+
+ connection->connectTimeSecs = info->connectSecs;
+ }
+}
+
+//===========================================================================================================================
+// _BrowseAllConnectionHandler
+//===========================================================================================================================
+
+static void _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg )
+{
+ BrowseAllConnection * const connection = (BrowseAllConnection *) inArg;
+ BrowseAllContext * const context = connection->context;
+
+ connection->status = inError;
+ ForgetSocket( &inSock );
+ if( context )
+ {
+ check( context->connectionPendingCount > 0 );
+ if( ( --context->connectionPendingCount == 0 ) && context->connectionTimer )
+ {
+ dispatch_source_forget( &context->connectionTimer );
+ dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
+ }
+ }
+ _BrowseAllConnectionRelease( connection );
+}
+
+//===========================================================================================================================
+// _BrowseAllExit
+//===========================================================================================================================
+
+#define Indent( X ) ( (X) * 4 ), ""
+
+static void _BrowseAllExit( void *inContext )
+{
+ BrowseAllContext * const context = (BrowseAllContext *) inContext;
+ SBRDomain * domain;
+ SBRServiceType * type;
+ SBRServiceInstance * instance;
+ SBRIPAddress * ipaddr;
+ char textBuf[ 512 ];
+#if( TARGET_OS_POSIX )
+ const Boolean useColor = isatty( STDOUT_FILENO ) ? true : false;
+#endif
+
+ dispatch_source_forget( &context->connectionTimer );
+
+ for( domain = context->results->domainList; domain; domain = domain->next )
+ {
+ FPrintF( stdout, "%s\n\n", domain->name );
+
+ for( type = domain->typeList; type; type = type->next )
+ {
+ const char * description;
+ const Boolean serviceTypeIsTCP = _IsServiceTypeTCP( type->name );
+
+ description = ServiceTypeDescription( type->name );
+ if( description ) FPrintF( stdout, "%*s" "%s (%s)\n\n", Indent( 1 ), description, type->name );
+ else FPrintF( stdout, "%*s" "%s\n\n", Indent( 1 ), type->name );
+
+ for( instance = type->instanceList; instance; instance = instance->next )
+ {
+ char * dst = textBuf;
+ char * const lim = &textBuf[ countof( textBuf ) ];
+ char ifname[ IF_NAMESIZE + 1 ];
+
+ SNPrintF_Add( &dst, lim, "%s via ", instance->name );
+ if( instance->ifIndex == 0 )
+ {
+ SNPrintF_Add( &dst, lim, "the Internet" );
+ }
+ else if( if_indextoname( instance->ifIndex, ifname ) )
+ {
+ NetTransportType netType;
+
+ SocketGetInterfaceInfo( kInvalidSocketRef, ifname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &netType );
+ SNPrintF_Add( &dst, lim, "%s (%s)",
+ ( netType == kNetTransportType_Ethernet ) ? "Ethernet" : NetTransportTypeToString( netType ),
+ ifname );
+ }
+ else
+ {
+ SNPrintF_Add( &dst, lim, "interface index %u", instance->ifIndex );
+ }
+ FPrintF( stdout, "%*s" "%-55s %4llu.%03llu ms\n\n",
+ Indent( 2 ), textBuf, instance->discoverTimeUs / 1000, instance->discoverTimeUs % 1000 );
+
+ if( instance->hostname )
+ {
+ SNPrintF( textBuf, sizeof( textBuf ), "%s:%u", instance->hostname, instance->port );
+ FPrintF( stdout, "%*s" "%-51s %4llu.%03llu ms\n",
+ Indent( 3 ), textBuf, instance->resolveTimeUs / 1000, instance->resolveTimeUs % 1000 );
+ }
+ else
+ {
+ FPrintF( stdout, "%*s" "%s:%u\n", Indent( 3 ), instance->hostname, instance->port );
+ }
+
+ for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
+ {
+ BrowseAllConnection * conn;
+ BrowseAllConnection ** connPtr;
+
+ FPrintF( stdout, "%*s" "%-##47a %4llu.%03llu ms",
+ Indent( 4 ), &ipaddr->sip.sa, ipaddr->resolveTimeUs / 1000, ipaddr->resolveTimeUs % 1000 );
+
+ conn = NULL;
+ if( serviceTypeIsTCP && ( instance->port != kDiscardProtocolPort ) )
+ {
+ for( connPtr = &context->connectionList; ( conn = *connPtr ) != NULL; connPtr = &conn->next )
+ {
+ if( ( conn->port == instance->port ) &&
+ ( SockAddrCompareAddr( &conn->sip, &ipaddr->sip ) == 0 ) ) break;
+ }
+ if( conn )
+ {
+ if( conn->status == kInProgressErr ) conn->status = kTimeoutErr;
+ *connPtr = conn->next;
+ conn->context = NULL;
+ AsyncConnection_Forget( &conn->asyncCnx );
+ }
+ }
+
+ if( conn )
+ {
+ if( conn->status == kNoErr )
+ {
+ FPrintF( stdout, " (%sconnected%s in %.3f ms)\n",
+ useColor ? kANSIGreen : "", useColor ? kANSINormal : "", conn->connectTimeSecs * 1000 );
+ }
+ else
+ {
+ FPrintF( stdout, " (%scould not connect%s: %m)\n",
+ useColor ? kANSIRed : "", useColor ? kANSINormal : "", conn->status );
+ }
+ _BrowseAllConnectionRelease( conn );
+ }
+ else
+ {
+ FPrintF( stdout, " (no connection attempted)\n" );
+ }
+ }
+
+ FPrintF( stdout, "\n" );
+ if( instance->txtLen == 0 ) continue;
+
+ FPrintF( stdout, "%*s" "TXT record (%zu byte%?c):\n",
+ Indent( 3 ), instance->txtLen, instance->txtLen != 1, 's' );
+ if( instance->txtLen > 1 )
+ {
+ FPrintF( stdout, "%3{txt}", instance->txtPtr, instance->txtLen );
+ }
+ else
+ {
+ FPrintF( stdout, "%*s" "%#H\n", Indent( 3 ), instance->txtPtr, (int) instance->txtLen, INT_MAX );
+ }
+ FPrintF( stdout, "\n" );
+ }
+ FPrintF( stdout, "\n" );
+ }
+ }
+
+ _BrowseAllContextFree( context );
+ Exit( NULL );
+}
+
+//===========================================================================================================================
+// _IsServiceTypeTCP
+//===========================================================================================================================
+
+static Boolean _IsServiceTypeTCP( const char *inServiceType )
+{
+ OSStatus err;
+ const uint8_t * secondLabel;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = DomainNameFromString( name, inServiceType, NULL );
+ if( !err )
+ {
+ secondLabel = DomainNameGetNextLabel( name );
+ if( secondLabel && DomainNameEqual( secondLabel, (const uint8_t *) "\x04" "_tcp" ) ) return( true );
+ }
+ return( false );
+}
+
+//===========================================================================================================================
+// GetNameInfoCmd
+//===========================================================================================================================
+
+const FlagStringPair kGetNameInfoFlagStringPairs[] =
+{
+ CaseFlagStringify( NI_NUMERICSCOPE ),
+ CaseFlagStringify( NI_DGRAM ),
+ CaseFlagStringify( NI_NUMERICSERV ),
+ CaseFlagStringify( NI_NAMEREQD ),
+ CaseFlagStringify( NI_NUMERICHOST ),
+ CaseFlagStringify( NI_NOFQDN ),
+ { 0, NULL }
+};
+
+static void GetNameInfoCmd( void )
+{
+ OSStatus err;
+ sockaddr_ip sip;
+ size_t sockAddrLen;
+ unsigned int flags;
+ const FlagStringPair * pair;
+ struct timeval now;
+ char host[ NI_MAXHOST ];
+ char serv[ NI_MAXSERV ];
+
+ err = StringToSockAddr( gGetNameInfo_IPAddress, &sip, sizeof( sip ), &sockAddrLen );
+ check_noerr( err );
+ if( err )
+ {
+ FPrintF( stderr, "Failed to convert \"%s\" to a sockaddr.\n", gGetNameInfo_IPAddress );
+ goto exit;
+ }
+
+ flags = 0;
+ if( gGetNameInfoFlag_DGram ) flags |= NI_DGRAM;
+ if( gGetNameInfoFlag_NameReqd ) flags |= NI_NAMEREQD;
+ if( gGetNameInfoFlag_NoFQDN ) flags |= NI_NOFQDN;
+ if( gGetNameInfoFlag_NumericHost ) flags |= NI_NUMERICHOST;
+ if( gGetNameInfoFlag_NumericScope ) flags |= NI_NUMERICSCOPE;
+ if( gGetNameInfoFlag_NumericServ ) flags |= NI_NUMERICSERV;
+
+ // Print prologue.
+
+ FPrintF( stdout, "SockAddr: %##a\n", &sip.sa );
+ FPrintF( stdout, "Flags: 0x%X < ", flags );
+ for( pair = kGetNameInfoFlagStringPairs; pair->str != NULL; ++pair )
+ {
+ if( flags & pair->flag ) FPrintF( stdout, "%s ", pair->str );
+ }
+ FPrintF( stdout, ">\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ // Call getnameinfo().
+
+ err = getnameinfo( &sip.sa, (socklen_t) sockAddrLen, host, (socklen_t) sizeof( host ), serv, (socklen_t) sizeof( serv ),
+ (int) flags );
+ gettimeofday( &now, NULL );
+ if( err )
+ {
+ FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
+ }
+ else
+ {
+ FPrintF( stdout, "host: %s\n", host );
+ FPrintF( stdout, "serv: %s\n", serv );
+ }
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %{du:time}\n", &now );
+
+exit:
+ gExitCode = err ? 1 : 0;
+}
+
+//===========================================================================================================================
+// GetAddrInfoStressCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServiceRef mainRef;
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+ unsigned int interfaceIndex;
+ unsigned int connectionNumber;
+ unsigned int requestCount;
+ unsigned int requestCountMax;
+ unsigned int requestCountLimit;
+ unsigned int durationMinMs;
+ unsigned int durationMaxMs;
+
+} GAIStressContext;
+
+static void GetAddrInfoStressEvent( void *inContext );
+static void DNSSD_API
+ GetAddrInfoStressCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void GetAddrInfoStressCmd( void )
+{
+ OSStatus err;
+ GAIStressContext * context = NULL;
+ int i;
+ DNSServiceFlags flags;
+ uint32_t ifIndex;
+ char ifName[ kInterfaceNameBufLen ];
+
+ if( gGAIStress_TestDurationSecs < 0 )
+ {
+ FPrintF( stdout, "Invalid test duration: %d s.\n", gGAIStress_TestDurationSecs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_ConnectionCount <= 0 )
+ {
+ FPrintF( stdout, "Invalid simultaneous connection count: %d.\n", gGAIStress_ConnectionCount );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_DurationMinMs <= 0 )
+ {
+ FPrintF( stdout, "Invalid minimum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMinMs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_DurationMaxMs <= 0 )
+ {
+ FPrintF( stdout, "Invalid maximum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMaxMs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_DurationMinMs > gGAIStress_DurationMaxMs )
+ {
+ FPrintF( stdout, "Invalid minimum and maximum DNSServiceGetAddrInfo() durations: %d ms and %d ms.\n",
+ gGAIStress_DurationMinMs, gGAIStress_DurationMaxMs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( gGAIStress_RequestCountMax <= 0 )
+ {
+ FPrintF( stdout, "Invalid maximum request count: %d.\n", gGAIStress_RequestCountMax );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Set flags.
+
+ flags = GetDNSSDFlagsFromOpts();
+
+ // Set interface index.
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ for( i = 0; i < gGAIStress_ConnectionCount; ++i )
+ {
+ context = (GAIStressContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->flags = flags;
+ context->interfaceIndex = ifIndex;
+ context->connectionNumber = (unsigned int)( i + 1 );
+ context->requestCountMax = (unsigned int) gGAIStress_RequestCountMax;
+ context->durationMinMs = (unsigned int) gGAIStress_DurationMinMs;
+ context->durationMaxMs = (unsigned int) gGAIStress_DurationMaxMs;
+
+ dispatch_async_f( dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
+ context = NULL;
+ }
+
+ if( gGAIStress_TestDurationSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( gGAIStress_TestDurationSecs ), dispatch_get_main_queue(), NULL, Exit );
+ }
+
+ FPrintF( stdout, "Flags: %#{flags}\n", flags, kDNSServiceFlagsDescriptors );
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+ FPrintF( stdout, "Test duration: " );
+ if( gGAIStress_TestDurationSecs == 0 )
+ {
+ FPrintF( stdout, "∞\n" );
+ }
+ else
+ {
+ FPrintF( stdout, "%d s\n", gGAIStress_TestDurationSecs );
+ }
+ FPrintF( stdout, "Connection count: %d\n", gGAIStress_ConnectionCount );
+ FPrintF( stdout, "Request duration min: %d ms\n", gGAIStress_DurationMinMs );
+ FPrintF( stdout, "Request duration max: %d ms\n", gGAIStress_DurationMaxMs );
+ FPrintF( stdout, "Request count max: %d\n", gGAIStress_RequestCountMax );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL);
+ FPrintF( stdout, "---\n" );
+
+ dispatch_main();
+
+exit:
+ FreeNullSafe( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GetAddrInfoStressEvent
+//===========================================================================================================================
+
+#define kStressRandStrLen 5
+
+#define kLowercaseAlphaCharSet "abcdefghijklmnopqrstuvwxyz"
+
+static void GetAddrInfoStressEvent( void *inContext )
+{
+ GAIStressContext * const context = (GAIStressContext *) inContext;
+ OSStatus err;
+ DNSServiceRef sdRef;
+ unsigned int nextMs;
+ char randomStr[ kStressRandStrLen + 1 ];
+ char hostname[ kStressRandStrLen + 4 + 1 ];
+ Boolean isConnectionNew = false;
+ static Boolean printedHeader = false;
+
+ if( !context->mainRef || ( context->requestCount >= context->requestCountLimit ) )
+ {
+ DNSServiceForget( &context->mainRef );
+ context->sdRef = NULL;
+ context->requestCount = 0;
+ context->requestCountLimit = RandomRange( 1, context->requestCountMax );
+
+ err = DNSServiceCreateConnection( &context->mainRef );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->mainRef, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ isConnectionNew = true;
+ }
+
+ RandomString( kLowercaseAlphaCharSet, sizeof_string( kLowercaseAlphaCharSet ), 2, kStressRandStrLen, randomStr );
+ SNPrintF( hostname, sizeof( hostname ), "%s.com", randomStr );
+
+ nextMs = RandomRange( context->durationMinMs, context->durationMaxMs );
+
+ if( !printedHeader )
+ {
+ FPrintF( stdout, "%-26s Conn Hostname Dur (ms)\n", "Timestamp" );
+ printedHeader = true;
+ }
+ FPrintF( stdout, "%{du:time} %3u%c %9s %8u\n",
+ NULL, context->connectionNumber, isConnectionNew ? '*': ' ', hostname, nextMs );
+
+ DNSServiceForget( &context->sdRef );
+ sdRef = context->mainRef;
+ err = DNSServiceGetAddrInfo( &sdRef, context->flags | kDNSServiceFlagsShareConnection, context->interfaceIndex,
+ kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, hostname, GetAddrInfoStressCallback, NULL );
+ require_noerr( err, exit );
+ context->sdRef = sdRef;
+
+ context->requestCount++;
+
+ dispatch_after_f( dispatch_time_milliseconds( nextMs ), dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GetAddrInfoStressCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ GetAddrInfoStressCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ Unused( inSDRef );
+ Unused( inFlags );
+ Unused( inInterfaceIndex );
+ Unused( inError );
+ Unused( inHostname );
+ Unused( inSockAddr );
+ Unused( inTTL );
+ Unused( inContext );
+}
+
+//===========================================================================================================================
+// DNSQueryCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ sockaddr_ip serverAddr;
+ uint64_t sendTicks;
+ uint8_t * msgPtr;
+ size_t msgLen;
+ size_t msgOffset;
+ const char * name;
+ dispatch_source_t readSource;
+ SocketRef sock;
+ int timeLimitSecs;
+ uint16_t queryID;
+ uint16_t type;
+ Boolean haveTCPLen;
+ Boolean useTCP;
+ Boolean printRawRData; // True if RDATA results are not to be formatted.
+ uint8_t msgBuf[ 512 ];
+
+} DNSQueryContext;
+
+static void DNSQueryPrintPrologue( const DNSQueryContext *inContext );
+static void DNSQueryReadHandler( void *inContext );
+static void DNSQueryCancelHandler( void *inContext );
+
+static void DNSQueryCmd( void )
+{
+ OSStatus err;
+ DNSQueryContext * context = NULL;
+ uint8_t * msgPtr;
+ size_t msgLen, sendLen;
+
+ // Check command parameters.
+
+ if( gDNSQuery_TimeLimitSecs < -1 )
+ {
+ FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSQuery_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+ if( ( gDNSQuery_Flags < INT16_MIN ) || ( gDNSQuery_Flags > UINT16_MAX ) )
+ {
+ FPrintF( stdout, "DNS flags-and-codes value is out of the unsigned 16-bit range: 0x%08X.\n", gDNSQuery_Flags );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (DNSQueryContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->name = gDNSQuery_Name;
+ context->sock = kInvalidSocketRef;
+ context->timeLimitSecs = gDNSQuery_TimeLimitSecs;
+ context->queryID = (uint16_t) Random32();
+ context->useTCP = gDNSQuery_UseTCP ? true : false;
+ context->printRawRData = gDNSQuery_RawRData ? true : false;
+
+#if( TARGET_OS_DARWIN )
+ if( gDNSQuery_Server )
+#endif
+ {
+ err = StringToSockAddr( gDNSQuery_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
+ require_noerr( err, exit );
+ }
+#if( TARGET_OS_DARWIN )
+ else
+ {
+ err = GetDefaultDNSServer( &context->serverAddr );
+ require_noerr( err, exit );
+ }
+#endif
+ if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSPort );
+
+ err = RecordTypeFromArgString( gDNSQuery_Type, &context->type );
+ require_noerr( err, exit );
+
+ // Write query message.
+
+ check_compile_time_code( sizeof( context->msgBuf ) >= ( kDNSQueryMessageMaxLen + 2 ) );
+
+ msgPtr = context->useTCP ? &context->msgBuf[ 2 ] : context->msgBuf;
+ err = WriteDNSQueryMessage( msgPtr, context->queryID, (uint16_t) gDNSQuery_Flags, context->name, context->type,
+ kDNSServiceClass_IN, &msgLen );
+ require_noerr( err, exit );
+ check( msgLen <= UINT16_MAX );
+
+ if( context->useTCP )
+ {
+ WriteBig16( context->msgBuf, msgLen );
+ sendLen = 2 + msgLen;
+ }
+ else
+ {
+ sendLen = msgLen;
+ }
+
+ DNSQueryPrintPrologue( context );
+
+ if( gDNSQuery_Verbose )
+ {
+ FPrintF( stdout, "DNS message to send:\n\n%{du:dnsmsg}", msgPtr, msgLen );
+ FPrintF( stdout, "---\n" );
+ }
+
+ if( context->useTCP )
+ {
+ // Create TCP socket.
+
+ context->sock = socket( context->serverAddr.sa.sa_family, SOCK_STREAM, IPPROTO_TCP );
+ err = map_socket_creation_errno( context->sock );
+ require_noerr( err, exit );
+
+ err = SocketConnect( context->sock, &context->serverAddr, 5 );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ // Create UDP socket.
+
+ err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &context->sock );
+ require_noerr( err, exit );
+ }
+
+ context->sendTicks = UpTicks();
+ err = _SocketWriteAll( context->sock, context->msgBuf, sendLen, 5 );
+ require_noerr( err, exit );
+
+ if( context->timeLimitSecs == 0 ) goto exit;
+
+ err = DispatchReadSourceCreate( context->sock, NULL, DNSQueryReadHandler, DNSQueryCancelHandler, context,
+ &context->readSource );
+ require_noerr( err, exit );
+ dispatch_resume( context->readSource );
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ if( context )
+ {
+ dispatch_source_forget( &context->readSource );
+ ForgetSocket( &context->sock );
+ free( context );
+ }
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DNSQueryPrintPrologue
+//===========================================================================================================================
+
+static void DNSQueryPrintPrologue( const DNSQueryContext *inContext )
+{
+ const int timeLimitSecs = inContext->timeLimitSecs;
+
+ FPrintF( stdout, "Name: %s\n", inContext->name );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->type ), inContext->type );
+ FPrintF( stdout, "Server: %##a\n", &inContext->serverAddr );
+ FPrintF( stdout, "Transport: %s\n", inContext->useTCP ? "TCP" : "UDP" );
+ FPrintF( stdout, "Time limit: " );
+ if( timeLimitSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+// DNSQueryReadHandler
+//===========================================================================================================================
+
+static void DNSQueryReadHandler( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ const uint64_t nowTicks = UpTicks();
+ DNSQueryContext * const context = (DNSQueryContext *) inContext;
+
+ gettimeofday( &now, NULL );
+
+ if( context->useTCP )
+ {
+ if( !context->haveTCPLen )
+ {
+ err = SocketReadData( context->sock, &context->msgBuf, 2, &context->msgOffset );
+ if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
+ require_noerr( err, exit );
+
+ context->msgOffset = 0;
+ context->msgLen = ReadBig16( context->msgBuf );
+ context->haveTCPLen = true;
+ if( context->msgLen <= sizeof( context->msgBuf ) )
+ {
+ context->msgPtr = context->msgBuf;
+ }
+ else
+ {
+ context->msgPtr = (uint8_t *) malloc( context->msgLen );
+ require_action( context->msgPtr, exit, err = kNoMemoryErr );
+ }
+ }
+
+ err = SocketReadData( context->sock, context->msgPtr, context->msgLen, &context->msgOffset );
+ if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
+ require_noerr( err, exit );
+ context->msgOffset = 0;
+ context->haveTCPLen = false;
+ }
+ else
+ {
+ sockaddr_ip fromAddr;
+
+ context->msgPtr = context->msgBuf;
+ err = SocketRecvFrom( context->sock, context->msgPtr, sizeof( context->msgBuf ), &context->msgLen, &fromAddr,
+ sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+ }
+
+ FPrintF( stdout, "Receive time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
+ FPrintF( stdout, "Message size: %zu\n", context->msgLen );
+ FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+ FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgPtr, context->msgLen );
+
+ if( ( context->msgLen >= kDNSHeaderLength ) && ( DNSHeaderGetID( (DNSHeader *) context->msgPtr ) == context->queryID ) )
+ {
+ Exit( kExitReason_ReceivedResponse );
+ }
+
+exit:
+ if( err ) dispatch_source_forget( &context->readSource );
+}
+
+//===========================================================================================================================
+// DNSQueryCancelHandler
+//===========================================================================================================================
+
+static void DNSQueryCancelHandler( void *inContext )
+{
+ DNSQueryContext * const context = (DNSQueryContext *) inContext;
+
+ check( !context->readSource );
+ ForgetSocket( &context->sock );
+ if( context->msgPtr != context->msgBuf ) ForgetMem( &context->msgPtr );
+ free( context );
+ dispatch_async_f( dispatch_get_main_queue(), NULL, Exit );
+}
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+//===========================================================================================================================
+// DNSCryptCmd
+//===========================================================================================================================
+
+#define kDNSCryptPort 443
+
+#define kDNSCryptMinPadLength 8
+#define kDNSCryptMaxPadLength 256
+#define kDNSCryptBlockSize 64
+#define kDNSCryptCertMinimumLength 124
+#define kDNSCryptClientMagicLength 8
+#define kDNSCryptResolverMagicLength 8
+#define kDNSCryptHalfNonceLength 12
+#define kDNSCryptCertMagicLength 4
+
+check_compile_time( ( kDNSCryptHalfNonceLength * 2 ) == crypto_box_NONCEBYTES );
+
+static const uint8_t kDNSCryptCertMagic[ kDNSCryptCertMagicLength ] = { 'D', 'N', 'S', 'C' };
+static const uint8_t kDNSCryptResolverMagic[ kDNSCryptResolverMagicLength ] =
+{
+ 0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38
+};
+
+typedef struct
+{
+ uint8_t certMagic[ kDNSCryptCertMagicLength ];
+ uint8_t esVersion[ 2 ];
+ uint8_t minorVersion[ 2 ];
+ uint8_t signature[ crypto_sign_BYTES ];
+ uint8_t publicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientMagic[ kDNSCryptClientMagicLength ];
+ uint8_t serial[ 4 ];
+ uint8_t startTime[ 4 ];
+ uint8_t endTime[ 4 ];
+ uint8_t extensions[ 1 ]; // Variably-sized extension data.
+
+} DNSCryptCert;
+
+check_compile_time( offsetof( DNSCryptCert, extensions ) == kDNSCryptCertMinimumLength );
+
+typedef struct
+{
+ uint8_t clientMagic[ kDNSCryptClientMagicLength ];
+ uint8_t clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t poly1305MAC[ 16 ];
+
+} DNSCryptQueryHeader;
+
+check_compile_time( sizeof( DNSCryptQueryHeader ) == 68 );
+check_compile_time( sizeof( DNSCryptQueryHeader ) >= crypto_box_ZEROBYTES );
+check_compile_time( ( sizeof( DNSCryptQueryHeader ) - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES ) ==
+ offsetof( DNSCryptQueryHeader, poly1305MAC ) );
+
+typedef struct
+{
+ uint8_t resolverMagic[ kDNSCryptResolverMagicLength ];
+ uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t resolverNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t poly1305MAC[ 16 ];
+
+} DNSCryptResponseHeader;
+
+check_compile_time( sizeof( DNSCryptResponseHeader ) == 48 );
+check_compile_time( offsetof( DNSCryptResponseHeader, poly1305MAC ) >= crypto_box_BOXZEROBYTES );
+check_compile_time( ( offsetof( DNSCryptResponseHeader, poly1305MAC ) - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES ) ==
+ sizeof( DNSCryptResponseHeader ) );
+
+typedef struct
+{
+ sockaddr_ip serverAddr;
+ uint64_t sendTicks;
+ const char * providerName;
+ const char * qname;
+ const uint8_t * certPtr;
+ size_t certLen;
+ dispatch_source_t readSource;
+ size_t msgLen;
+ int timeLimitSecs;
+ uint16_t queryID;
+ uint16_t qtype;
+ Boolean printRawRData;
+ uint8_t serverPublicSignKey[ crypto_sign_PUBLICKEYBYTES ];
+ uint8_t serverPublicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
+ uint8_t clientSecretKey[ crypto_box_SECRETKEYBYTES ];
+ uint8_t clientMagic[ kDNSCryptClientMagicLength ];
+ uint8_t clientNonce[ kDNSCryptHalfNonceLength ];
+ uint8_t nmKey[ crypto_box_BEFORENMBYTES ];
+ uint8_t msgBuf[ 512 ];
+
+} DNSCryptContext;
+
+static void DNSCryptReceiveCertHandler( void *inContext );
+static void DNSCryptReceiveResponseHandler( void *inContext );
+static void DNSCryptProceed( void *inContext );
+static OSStatus DNSCryptProcessCert( DNSCryptContext *inContext );
+static OSStatus DNSCryptBuildQuery( DNSCryptContext *inContext );
+static OSStatus DNSCryptSendQuery( DNSCryptContext *inContext );
+static void DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen );
+
+static void DNSCryptCmd( void )
+{
+ OSStatus err;
+ DNSCryptContext * context = NULL;
+ size_t writtenBytes;
+ size_t totalBytes;
+ SocketContext * sockCtx;
+ SocketRef sock = kInvalidSocketRef;
+ const char * ptr;
+
+ // Check command parameters.
+
+ if( gDNSCrypt_TimeLimitSecs < -1 )
+ {
+ FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSCrypt_TimeLimitSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (DNSCryptContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->providerName = gDNSCrypt_ProviderName;
+ context->qname = gDNSCrypt_Name;
+ context->timeLimitSecs = gDNSCrypt_TimeLimitSecs;
+ context->printRawRData = gDNSCrypt_RawRData ? true : false;
+
+ err = crypto_box_keypair( context->clientPublicKey, context->clientSecretKey );
+ require_noerr( err, exit );
+
+ err = HexToData( gDNSCrypt_ProviderKey, kSizeCString, kHexToData_DefaultFlags,
+ context->serverPublicSignKey, sizeof( context->serverPublicSignKey ), &writtenBytes, &totalBytes, &ptr );
+ if( err || ( *ptr != '\0' ) )
+ {
+ FPrintF( stderr, "Failed to parse public signing key hex string (%s).\n", gDNSCrypt_ProviderKey );
+ goto exit;
+ }
+ else if( totalBytes != sizeof( context->serverPublicSignKey ) )
+ {
+ FPrintF( stderr, "Public signing key contains incorrect number of hex bytes (%zu != %zu)\n",
+ totalBytes, sizeof( context->serverPublicSignKey ) );
+ err = kSizeErr;
+ goto exit;
+ }
+ check( writtenBytes == totalBytes );
+
+ err = StringToSockAddr( gDNSCrypt_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
+ require_noerr( err, exit );
+ if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSCryptPort );
+
+ err = RecordTypeFromArgString( gDNSCrypt_Type, &context->qtype );
+ require_noerr( err, exit );
+
+ // Write query message.
+
+ context->queryID = (uint16_t) Random32();
+ err = WriteDNSQueryMessage( context->msgBuf, context->queryID, kDNSHeaderFlag_RecursionDesired, context->providerName,
+ kDNSServiceType_TXT, kDNSServiceClass_IN, &context->msgLen );
+ require_noerr( err, exit );
+
+ // Create UDP socket.
+
+ err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &sock );
+ require_noerr( err, exit );
+
+ // Send DNS query.
+
+ context->sendTicks = UpTicks();
+ err = _SocketWriteAll( sock, context->msgBuf, context->msgLen, 5 );
+ require_noerr( err, exit );
+
+ err = SocketContextCreate( sock, context, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveCertHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSource );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSource );
+
+ if( context->timeLimitSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ if( context ) free( context );
+ ForgetSocket( &sock );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DNSCryptReceiveCertHandler
+//===========================================================================================================================
+
+static void DNSCryptReceiveCertHandler( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ const uint64_t nowTicks = UpTicks();
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ DNSCryptContext * const context = (DNSCryptContext *) sockCtx->userContext;
+ const DNSHeader * hdr;
+ sockaddr_ip fromAddr;
+ const uint8_t * ptr;
+ const uint8_t * txtPtr;
+ size_t txtLen;
+ unsigned int answerCount, i;
+ uint8_t targetName[ kDomainNameLengthMax ];
+
+ gettimeofday( &now, NULL );
+
+ dispatch_source_forget( &context->readSource );
+
+ err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
+ &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+ check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+
+ FPrintF( stdout, "Receive time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
+ FPrintF( stdout, "Message size: %zu\n", context->msgLen );
+ FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+ FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgBuf, context->msgLen );
+
+ require_action_quiet( context->msgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+
+ hdr = (DNSHeader *) context->msgBuf;
+ require_action_quiet( DNSHeaderGetID( hdr ) == context->queryID, exit, err = kMismatchErr );
+
+ err = DNSMessageGetAnswerSection( context->msgBuf, context->msgLen, &ptr );
+ require_noerr( err, exit );
+
+ err = DomainNameFromString( targetName, context->providerName, NULL );
+ require_noerr( err, exit );
+
+ answerCount = DNSHeaderGetAnswerCount( hdr );
+ for( i = 0; i < answerCount; ++i )
+ {
+ uint16_t type;
+ uint16_t class;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractRecord( context->msgBuf, context->msgLen, ptr, name, &type, &class, NULL, &txtPtr, &txtLen,
+ &ptr );
+ require_noerr( err, exit );
+
+ if( ( type == kDNSServiceType_TXT ) && ( class == kDNSServiceClass_IN ) && DomainNameEqual( name, targetName ) )
+ {
+ break;
+ }
+ }
+
+ if( txtLen < ( 1 + kDNSCryptCertMinimumLength ) )
+ {
+ FPrintF( stderr, "TXT record length is too short (%u < %u)\n", txtLen, kDNSCryptCertMinimumLength + 1 );
+ err = kSizeErr;
+ goto exit;
+ }
+ if( txtPtr[ 0 ] < kDNSCryptCertMinimumLength )
+ {
+ FPrintF( stderr, "TXT record value length is too short (%u < %u)\n", txtPtr[ 0 ], kDNSCryptCertMinimumLength );
+ err = kSizeErr;
+ goto exit;
+ }
+
+ context->certLen = txtPtr[ 0 ];
+ context->certPtr = &txtPtr[ 1 ];
+
+ dispatch_async_f( dispatch_get_main_queue(), context, DNSCryptProceed );
+
+exit:
+ if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+// DNSCryptReceiveResponseHandler
+//===========================================================================================================================
+
+static void DNSCryptReceiveResponseHandler( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ const uint64_t nowTicks = UpTicks();
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ DNSCryptContext * const context = (DNSCryptContext *) sockCtx->userContext;
+ sockaddr_ip fromAddr;
+ DNSCryptResponseHeader * hdr;
+ const uint8_t * end;
+ uint8_t * ciphertext;
+ uint8_t * plaintext;
+ const uint8_t * response;
+ uint8_t nonce[ crypto_box_NONCEBYTES ];
+
+ gettimeofday( &now, NULL );
+
+ dispatch_source_forget( &context->readSource );
+
+ err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
+ &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+ check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+
+ FPrintF( stdout, "Receive time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source: %##a\n", &context->serverAddr );
+ FPrintF( stdout, "Message size: %zu\n", context->msgLen );
+ FPrintF( stdout, "RTT: %llu ms\n\n", UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+
+ if( context->msgLen < sizeof( DNSCryptResponseHeader ) )
+ {
+ FPrintF( stderr, "DNSCrypt response is too short.\n" );
+ err = kSizeErr;
+ goto exit;
+ }
+
+ hdr = (DNSCryptResponseHeader *) context->msgBuf;
+
+ if( memcmp( hdr->resolverMagic, kDNSCryptResolverMagic, kDNSCryptResolverMagicLength ) != 0 )
+ {
+ FPrintF( stderr, "DNSCrypt response resolver magic %#H != %#H\n",
+ hdr->resolverMagic, kDNSCryptResolverMagicLength, INT_MAX,
+ kDNSCryptResolverMagic, kDNSCryptResolverMagicLength, INT_MAX );
+ err = kValueErr;
+ goto exit;
+ }
+
+ if( memcmp( hdr->clientNonce, context->clientNonce, kDNSCryptHalfNonceLength ) != 0 )
+ {
+ FPrintF( stderr, "DNSCrypt response client nonce mismatch.\n" );
+ err = kValueErr;
+ goto exit;
+ }
+
+ memcpy( nonce, hdr->clientNonce, crypto_box_NONCEBYTES );
+
+ ciphertext = hdr->poly1305MAC - crypto_box_BOXZEROBYTES;
+ memset( ciphertext, 0, crypto_box_BOXZEROBYTES );
+
+ plaintext = (uint8_t *)( hdr + 1 ) - crypto_box_ZEROBYTES;
+ check( plaintext == ciphertext );
+
+ end = context->msgBuf + context->msgLen;
+
+ err = crypto_box_open_afternm( plaintext, ciphertext, (size_t)( end - ciphertext ), nonce, context->nmKey );
+ require_noerr( err, exit );
+
+ response = plaintext + crypto_box_ZEROBYTES;
+ FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, response, (size_t)( end - response ) );
+ Exit( kExitReason_ReceivedResponse );
+
+exit:
+ if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+// DNSCryptProceed
+//===========================================================================================================================
+
+static void DNSCryptProceed( void *inContext )
+{
+ OSStatus err;
+ DNSCryptContext * const context = (DNSCryptContext *) inContext;
+
+ err = DNSCryptProcessCert( context );
+ require_noerr_quiet( err, exit );
+
+ err = DNSCryptBuildQuery( context );
+ require_noerr_quiet( err, exit );
+
+ err = DNSCryptSendQuery( context );
+ require_noerr_quiet( err, exit );
+
+exit:
+ if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+// DNSCryptProcessCert
+//===========================================================================================================================
+
+static OSStatus DNSCryptProcessCert( DNSCryptContext *inContext )
+{
+ OSStatus err;
+ const DNSCryptCert * const cert = (DNSCryptCert *) inContext->certPtr;
+ const uint8_t * const certEnd = inContext->certPtr + inContext->certLen;
+ struct timeval now;
+ time_t startTimeSecs, endTimeSecs;
+ size_t signedLen;
+ uint8_t * tempBuf;
+ unsigned long long tempLen;
+
+ DNSCryptPrintCertificate( cert, inContext->certLen );
+
+ if( memcmp( cert->certMagic, kDNSCryptCertMagic, kDNSCryptCertMagicLength ) != 0 )
+ {
+ FPrintF( stderr, "DNSCrypt certificate magic %#H != %#H\n",
+ cert->certMagic, kDNSCryptCertMagicLength, INT_MAX,
+ kDNSCryptCertMagic, kDNSCryptCertMagicLength, INT_MAX );
+ err = kValueErr;
+ goto exit;
+ }
+
+ startTimeSecs = (time_t) ReadBig32( cert->startTime );
+ endTimeSecs = (time_t) ReadBig32( cert->endTime );
+
+ gettimeofday( &now, NULL );
+ if( now.tv_sec < startTimeSecs )
+ {
+ FPrintF( stderr, "DNSCrypt certificate start time is in the future.\n" );
+ err = kDateErr;
+ goto exit;
+ }
+ if( now.tv_sec >= endTimeSecs )
+ {
+ FPrintF( stderr, "DNSCrypt certificate has expired.\n" );
+ err = kDateErr;
+ goto exit;
+ }
+
+ signedLen = (size_t)( certEnd - cert->signature );
+ tempBuf = (uint8_t *) malloc( signedLen );
+ require_action( tempBuf, exit, err = kNoMemoryErr );
+ err = crypto_sign_open( tempBuf, &tempLen, cert->signature, signedLen, inContext->serverPublicSignKey );
+ free( tempBuf );
+ if( err )
+ {
+ FPrintF( stderr, "DNSCrypt certificate failed verification.\n" );
+ err = kAuthenticationErr;
+ goto exit;
+ }
+
+ memcpy( inContext->serverPublicKey, cert->publicKey, crypto_box_PUBLICKEYBYTES );
+ memcpy( inContext->clientMagic, cert->clientMagic, kDNSCryptClientMagicLength );
+
+ err = crypto_box_beforenm( inContext->nmKey, inContext->serverPublicKey, inContext->clientSecretKey );
+ require_noerr( err, exit );
+
+ inContext->certPtr = NULL;
+ inContext->certLen = 0;
+ inContext->msgLen = 0;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSCryptBuildQuery
+//===========================================================================================================================
+
+static OSStatus DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen );
+
+static OSStatus DNSCryptBuildQuery( DNSCryptContext *inContext )
+{
+ OSStatus err;
+ DNSCryptQueryHeader * const hdr = (DNSCryptQueryHeader *) inContext->msgBuf;
+ uint8_t * const queryPtr = (uint8_t *)( hdr + 1 );
+ size_t queryLen;
+ size_t paddedQueryLen;
+ const uint8_t * const msgLimit = inContext->msgBuf + sizeof( inContext->msgBuf );
+ const uint8_t * padLimit;
+ uint8_t nonce[ crypto_box_NONCEBYTES ];
+
+ check_compile_time_code( sizeof( inContext->msgBuf ) >= ( sizeof( DNSCryptQueryHeader ) + kDNSQueryMessageMaxLen ) );
+
+ inContext->queryID = (uint16_t) Random32();
+ err = WriteDNSQueryMessage( queryPtr, inContext->queryID, kDNSHeaderFlag_RecursionDesired, inContext->qname,
+ inContext->qtype, kDNSServiceClass_IN, &queryLen );
+ require_noerr( err, exit );
+
+ padLimit = &queryPtr[ queryLen + kDNSCryptMaxPadLength ];
+ if( padLimit > msgLimit ) padLimit = msgLimit;
+
+ err = DNSCryptPadQuery( queryPtr, queryLen, (size_t)( padLimit - queryPtr ), &paddedQueryLen );
+ require_noerr( err, exit );
+
+ memset( queryPtr - crypto_box_ZEROBYTES, 0, crypto_box_ZEROBYTES );
+ RandomBytes( inContext->clientNonce, kDNSCryptHalfNonceLength );
+ memcpy( nonce, inContext->clientNonce, kDNSCryptHalfNonceLength );
+ memset( &nonce[ kDNSCryptHalfNonceLength ], 0, kDNSCryptHalfNonceLength );
+
+ err = crypto_box_afternm( queryPtr - crypto_box_ZEROBYTES, queryPtr - crypto_box_ZEROBYTES,
+ paddedQueryLen + crypto_box_ZEROBYTES, nonce, inContext->nmKey );
+ require_noerr( err, exit );
+
+ memcpy( hdr->clientMagic, inContext->clientMagic, kDNSCryptClientMagicLength );
+ memcpy( hdr->clientPublicKey, inContext->clientPublicKey, crypto_box_PUBLICKEYBYTES );
+ memcpy( hdr->clientNonce, nonce, kDNSCryptHalfNonceLength );
+
+ inContext->msgLen = (size_t)( &queryPtr[ paddedQueryLen ] - inContext->msgBuf );
+
+exit:
+ return( err );
+}
+
+static OSStatus DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen )
+{
+ OSStatus err;
+ size_t paddedLen;
+
+ require_action_quiet( ( inMsgLen + kDNSCryptMinPadLength ) <= inMaxLen, exit, err = kSizeErr );
+
+ paddedLen = inMsgLen + kDNSCryptMinPadLength +
+ arc4random_uniform( (uint32_t)( inMaxLen - ( inMsgLen + kDNSCryptMinPadLength ) + 1 ) );
+ paddedLen += ( kDNSCryptBlockSize - ( paddedLen % kDNSCryptBlockSize ) );
+ if( paddedLen > inMaxLen ) paddedLen = inMaxLen;
+
+ inMsgPtr[ inMsgLen ] = 0x80;
+ memset( &inMsgPtr[ inMsgLen + 1 ], 0, paddedLen - ( inMsgLen + 1 ) );
+
+ if( outPaddedLen ) *outPaddedLen = paddedLen;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSCryptSendQuery
+//===========================================================================================================================
+
+static OSStatus DNSCryptSendQuery( DNSCryptContext *inContext )
+{
+ OSStatus err;
+ SocketContext * sockCtx;
+ SocketRef sock = kInvalidSocketRef;
+
+ check( inContext->msgLen > 0 );
+ check( !inContext->readSource );
+
+ err = UDPClientSocketOpen( AF_UNSPEC, &inContext->serverAddr, 0, -1, NULL, &sock );
+ require_noerr( err, exit );
+
+ inContext->sendTicks = UpTicks();
+ err = _SocketWriteAll( sock, inContext->msgBuf, inContext->msgLen, 5 );
+ require_noerr( err, exit );
+
+ err = SocketContextCreate( sock, inContext, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveResponseHandler, SocketContextCancelHandler, sockCtx,
+ &inContext->readSource );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( inContext->readSource );
+
+exit:
+ ForgetSocket( &sock );
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSCryptPrintCertificate
+//===========================================================================================================================
+
+#define kCertTimeStrBufLen 32
+
+static char * CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] );
+
+static void DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen )
+{
+ time_t startTime, endTime;
+ int extLen;
+ char timeBuf[ kCertTimeStrBufLen ];
+
+ check( inLen >= kDNSCryptCertMinimumLength );
+
+ startTime = (time_t) ReadBig32( inCert->startTime );
+ endTime = (time_t) ReadBig32( inCert->endTime );
+
+ FPrintF( stdout, "DNSCrypt certificate (%zu bytes):\n", inLen );
+ FPrintF( stdout, "Cert Magic: %#H\n", inCert->certMagic, kDNSCryptCertMagicLength, INT_MAX );
+ FPrintF( stdout, "ES Version: %u\n", ReadBig16( inCert->esVersion ) );
+ FPrintF( stdout, "Minor Version: %u\n", ReadBig16( inCert->minorVersion ) );
+ FPrintF( stdout, "Signature: %H\n", inCert->signature, crypto_sign_BYTES / 2, INT_MAX );
+ FPrintF( stdout, " %H\n", &inCert->signature[ crypto_sign_BYTES / 2 ], crypto_sign_BYTES / 2, INT_MAX );
+ FPrintF( stdout, "Public Key: %H\n", inCert->publicKey, sizeof( inCert->publicKey ), INT_MAX );
+ FPrintF( stdout, "Client Magic: %H\n", inCert->clientMagic, kDNSCryptClientMagicLength, INT_MAX );
+ FPrintF( stdout, "Serial: %u\n", ReadBig32( inCert->serial ) );
+ FPrintF( stdout, "Start Time: %u (%s)\n", (uint32_t) startTime, CertTimeStr( startTime, timeBuf ) );
+ FPrintF( stdout, "End Time: %u (%s)\n", (uint32_t) endTime, CertTimeStr( endTime, timeBuf ) );
+
+ if( inLen > kDNSCryptCertMinimumLength )
+ {
+ extLen = (int)( inLen - kDNSCryptCertMinimumLength );
+ FPrintF( stdout, "Extensions: %.1H\n", inCert->extensions, extLen, extLen );
+ }
+ FPrintF( stdout, "\n" );
+}
+
+static char * CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] )
+{
+ struct tm * tm;
+
+ tm = localtime( &inTime );
+ if( !tm )
+ {
+ dlogassert( "localtime() returned a NULL pointer.\n" );
+ *inBuffer = '\0';
+ }
+ else
+ {
+ strftime( inBuffer, kCertTimeStrBufLen, "%a %b %d %H:%M:%S %Z %Y", tm );
+ }
+
+ return( inBuffer );
+}
+
+#endif // DNSSDUTIL_INCLUDE_DNSCRYPT
+
+//===========================================================================================================================
+// MDNSQueryCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ const char * qnameStr; // Name (QNAME) of the record being queried as a C string.
+ dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
+ dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
+ int localPort; // The port number to which the sockets are bound.
+ int receiveSecs; // After send, the amount of time to spend receiving.
+ uint32_t ifIndex; // Index of the interface over which to send the query.
+ uint16_t qtype; // The type (QTYPE) of the record being queried.
+ Boolean isQU; // True if the query is QU, i.e., requests unicast responses.
+ Boolean allResponses; // True if all mDNS messages received should be printed.
+ Boolean printRawRData; // True if RDATA should be printed as hexdumps.
+ Boolean useIPv4; // True if the query should be sent via IPv4 multicast.
+ Boolean useIPv6; // True if the query should be sent via IPv6 multicast.
+ char ifName[ IF_NAMESIZE + 1 ]; // Name of the interface over which to send the query.
+ uint8_t qname[ kDomainNameLengthMax ]; // Buffer to hold the QNAME in DNS label format.
+ uint8_t msgBuf[ kMDNSMessageSizeMax ]; // mDNS message buffer.
+
+} MDNSQueryContext;
+
+static void MDNSQueryPrintPrologue( const MDNSQueryContext *inContext );
+static void MDNSQueryReadHandler( void *inContext );
+
+static void MDNSQueryCmd( void )
+{
+ OSStatus err;
+ MDNSQueryContext * context;
+ SocketRef sockV4 = kInvalidSocketRef;
+ SocketRef sockV6 = kInvalidSocketRef;
+ ssize_t n;
+ const char * ifname;
+ size_t msgLen;
+ unsigned int sendCount;
+
+ // Check command parameters.
+
+ if( gMDNSQuery_ReceiveSecs < -1 )
+ {
+ FPrintF( stdout, "Invalid receive time value: %d seconds.\n", gMDNSQuery_ReceiveSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ context = (MDNSQueryContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->qnameStr = gMDNSQuery_Name;
+ context->receiveSecs = gMDNSQuery_ReceiveSecs;
+ context->isQU = gMDNSQuery_IsQU ? true : false;
+ context->allResponses = gMDNSQuery_AllResponses ? true : false;
+ context->printRawRData = gMDNSQuery_RawRData ? true : false;
+ context->useIPv4 = ( gMDNSQuery_UseIPv4 || !gMDNSQuery_UseIPv6 ) ? true : false;
+ context->useIPv6 = ( gMDNSQuery_UseIPv6 || !gMDNSQuery_UseIPv4 ) ? true : false;
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ ifname = if_indextoname( context->ifIndex, context->ifName );
+ require_action( ifname, exit, err = kNameErr );
+
+ err = RecordTypeFromArgString( gMDNSQuery_Type, &context->qtype );
+ require_noerr( err, exit );
+
+ // Set up IPv4 socket.
+
+ if( context->useIPv4 )
+ {
+ err = CreateMulticastSocket( GetMDNSMulticastAddrV4(),
+ gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
+ ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV4 );
+ require_noerr( err, exit );
+ }
+
+ // Set up IPv6 socket.
+
+ if( context->useIPv6 )
+ {
+ err = CreateMulticastSocket( GetMDNSMulticastAddrV6(),
+ gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
+ ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV6 );
+ require_noerr( err, exit );
+ }
+
+ // Craft mDNS query message.
+
+ check_compile_time_code( sizeof( context->msgBuf ) >= kDNSQueryMessageMaxLen );
+ err = WriteDNSQueryMessage( context->msgBuf, kDefaultMDNSMessageID, kDefaultMDNSQueryFlags, context->qnameStr,
+ context->qtype, context->isQU ? ( kDNSServiceClass_IN | kQClassUnicastResponseBit ) : kDNSServiceClass_IN, &msgLen );
+ require_noerr( err, exit );
+
+ // Print prologue.
+
+ MDNSQueryPrintPrologue( context );
+
+ // Send mDNS query message.
+
+ sendCount = 0;
+ if( IsValidSocket( sockV4 ) )
+ {
+ const struct sockaddr * const mcastAddr4 = GetMDNSMulticastAddrV4();
+
+ n = sendto( sockV4, context->msgBuf, msgLen, 0, mcastAddr4, SockAddrGetSize( mcastAddr4 ) );
+ err = map_socket_value_errno( sockV4, n == (ssize_t) msgLen, n );
+ if( err )
+ {
+ FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
+ ForgetSocket( &sockV4 );
+ }
+ else
+ {
+ ++sendCount;
+ }
+ }
+ if( IsValidSocket( sockV6 ) )
+ {
+ const struct sockaddr * const mcastAddr6 = GetMDNSMulticastAddrV6();
+
+ n = sendto( sockV6, context->msgBuf, msgLen, 0, mcastAddr6, SockAddrGetSize( mcastAddr6 ) );
+ err = map_socket_value_errno( sockV6, n == (ssize_t) msgLen, n );
+ if( err )
+ {
+ FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
+ ForgetSocket( &sockV6 );
+ }
+ else
+ {
+ ++sendCount;
+ }
+ }
+ require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
+
+ // If there's no wait period after the send, then exit.
+
+ if( context->receiveSecs == 0 ) goto exit;
+
+ // Create dispatch read sources for socket(s).
+
+ if( IsValidSocket( sockV4 ) )
+ {
+ SocketContext * sockCtx;
+
+ err = SocketContextCreate( sockV4, context, &sockCtx );
+ require_noerr( err, exit );
+ sockV4 = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSourceV4 );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSourceV4 );
+ }
+
+ if( IsValidSocket( sockV6 ) )
+ {
+ SocketContext * sockCtx;
+
+ err = SocketContextCreate( sockV6, context, &sockCtx );
+ require_noerr( err, exit );
+ sockV6 = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSourceV6 );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSourceV6 );
+ }
+
+ if( context->receiveSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ ForgetSocket( &sockV4 );
+ ForgetSocket( &sockV6 );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// MDNSColliderCmd
+//===========================================================================================================================
+
+static void _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError );
+
+static void MDNSColliderCmd( void )
+{
+ OSStatus err;
+ MDNSColliderRef collider = NULL;
+ uint8_t * rdataPtr = NULL;
+ size_t rdataLen = 0;
+ const char * ifname;
+ uint32_t ifIndex;
+ MDNSColliderProtocols protocols;
+ uint16_t type;
+ char ifName[ IF_NAMESIZE + 1 ];
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ ifname = if_indextoname( ifIndex, ifName );
+ if( !ifname )
+ {
+ FPrintF( stderr, "error: Invalid interface name or index: %s\n", gInterface );
+ err = kNameErr;
+ goto exit;
+ }
+
+ err = DomainNameFromString( name, gMDNSCollider_Name, NULL );
+ if( err )
+ {
+ FPrintF( stderr, "error: Invalid record name: %s\n", gMDNSCollider_Name );
+ goto exit;
+ }
+
+ err = RecordTypeFromArgString( gMDNSCollider_Type, &type );
+ require_noerr_quiet( err, exit );
+
+ if( gMDNSCollider_RecordData )
+ {
+ err = RecordDataFromArgString( gMDNSCollider_RecordData, &rdataPtr, &rdataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ err = MDNSColliderCreate( dispatch_get_main_queue(), &collider );
+ require_noerr( err, exit );
+
+ err = MDNSColliderSetProgram( collider, gMDNSCollider_Program );
+ if( err )
+ {
+ FPrintF( stderr, "error: Failed to set program string: '%s'\n", gMDNSCollider_Program );
+ goto exit;
+ }
+
+ err = MDNSColliderSetRecord( collider, name, type, rdataPtr, rdataLen );
+ require_noerr( err, exit );
+ ForgetMem( &rdataPtr );
+
+ protocols = kMDNSColliderProtocol_None;
+ if( gMDNSCollider_UseIPv4 || !gMDNSCollider_UseIPv6 ) protocols |= kMDNSColliderProtocol_IPv4;
+ if( gMDNSCollider_UseIPv6 || !gMDNSCollider_UseIPv4 ) protocols |= kMDNSColliderProtocol_IPv6;
+ MDNSColliderSetProtocols( collider, protocols );
+ MDNSColliderSetInterfaceIndex( collider, ifIndex );
+ MDNSColliderSetStopHandler( collider, _MDNSColliderCmdStopHandler, collider );
+
+ err = MDNSColliderStart( collider );
+ require_noerr( err, exit );
+
+ dispatch_main();
+
+exit:
+ FreeNullSafe( rdataPtr );
+ CFReleaseNullSafe( collider );
+ if( err ) exit( 1 );
+}
+
+static void _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError )
+{
+ MDNSColliderRef const collider = (MDNSColliderRef) inContext;
+
+ CFRelease( collider );
+ exit( inError ? 1 : 0 );
+}
+
+//===========================================================================================================================
+// MDNSQueryPrintPrologue
+//===========================================================================================================================
+
+static void MDNSQueryPrintPrologue( const MDNSQueryContext *inContext )
+{
+ const int receiveSecs = inContext->receiveSecs;
+
+ FPrintF( stdout, "Interface: %d (%s)\n", (int32_t) inContext->ifIndex, inContext->ifName );
+ FPrintF( stdout, "Name: %s\n", inContext->qnameStr );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( inContext->qtype ), inContext->qtype );
+ FPrintF( stdout, "Class: IN (%s)\n", inContext->isQU ? "QU" : "QM" );
+ FPrintF( stdout, "Local port: %d\n", inContext->localPort );
+ FPrintF( stdout, "IP protocols: %?s%?s%?s\n",
+ inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
+ FPrintF( stdout, "Receive duration: " );
+ if( receiveSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+}
+
+//===========================================================================================================================
+// MDNSQueryReadHandler
+//===========================================================================================================================
+
+static void MDNSQueryReadHandler( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ MDNSQueryContext * const context = (MDNSQueryContext *) sockCtx->userContext;
+ size_t msgLen;
+ sockaddr_ip fromAddr;
+ Boolean foundAnswer = false;
+
+ gettimeofday( &now, NULL );
+
+ err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &fromAddr,
+ sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ if( !context->allResponses && ( msgLen >= kDNSHeaderLength ) )
+ {
+ const uint8_t * ptr;
+ const DNSHeader * const hdr = (DNSHeader *) context->msgBuf;
+ unsigned int rrCount, i;
+ uint16_t type, class;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = DNSMessageGetAnswerSection( context->msgBuf, msgLen, &ptr );
+ require_noerr( err, exit );
+
+ if( context->qname[ 0 ] == 0 )
+ {
+ err = DomainNameAppendString( context->qname, context->qnameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ rrCount = DNSHeaderGetAnswerCount( hdr ) + DNSHeaderGetAuthorityCount( hdr ) + DNSHeaderGetAdditionalCount( hdr );
+ for( i = 0; i < rrCount; ++i )
+ {
+ err = DNSMessageExtractRecord( context->msgBuf, msgLen, ptr, name, &type, &class, NULL, NULL, NULL, &ptr );
+ require_noerr( err, exit );
+
+ if( ( ( context->qtype == kDNSServiceType_ANY ) || ( type == context->qtype ) ) &&
+ DomainNameEqual( name, context->qname ) )
+ {
+ foundAnswer = true;
+ break;
+ }
+ }
+ }
+ if( context->allResponses || foundAnswer )
+ {
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "Receive time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source: %##a\n", &fromAddr );
+ FPrintF( stdout, "Message size: %zu\n\n%#.*{du:dnsmsg}",
+ msgLen, context->printRawRData ? 1 : 0, context->msgBuf, msgLen );
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// PIDToUUIDCmd
+//===========================================================================================================================
+
+static void PIDToUUIDCmd( void )
+{
+ OSStatus err;
+ int n;
+ struct proc_uniqidentifierinfo info;
+
+ n = proc_pidinfo( gPIDToUUID_PID, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof( info ) );
+ require_action_quiet( n == (int) sizeof( info ), exit, err = kUnknownErr );
+
+ FPrintF( stdout, "%#U\n", info.p_uuid );
+ err = kNoErr;
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DNSServerCmd
+//===========================================================================================================================
+
+typedef struct DNSServerPrivate * DNSServerRef;
+
+typedef struct
+{
+ DNSServerRef server; // Reference to the DNS server.
+ dispatch_source_t sigIntSource; // Dispatch SIGINT source.
+ dispatch_source_t sigTermSource; // Dispatch SIGTERM source.
+ const char * domainOverride; // If non-NULL, the server is to use this domain instead of "d.test.".
+#if( TARGET_OS_DARWIN )
+ dispatch_source_t processMonitor; // Process monitor source for process being followed, if any.
+ pid_t followPID; // PID of process being followed, if any. (If it exits, we exit).
+ Boolean addedResolver; // True if system DNS settings contains a resolver entry for server.
+#endif
+ Boolean loopbackOnly; // True if the server should be bound to the loopback interface.
+
+} DNSServerCmdContext;
+
+typedef enum
+{
+ kDNSServerEvent_Started = 1,
+ kDNSServerEvent_Stopped = 2
+
+} DNSServerEventType;
+
+typedef void ( *DNSServerEventHandler_f )( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
+
+CFTypeID DNSServerGetTypeID( void );
+static OSStatus
+ DNSServerCreate(
+ dispatch_queue_t inQueue,
+ DNSServerEventHandler_f inEventHandler,
+ void * inEventContext,
+ unsigned int inResponseDelayMs,
+ uint32_t inDefaultTTL,
+ int inPort,
+ Boolean inLoopbackOnly,
+ const char * inDomain,
+ Boolean inBadUDPMode,
+ DNSServerRef * outServer );
+static void DNSServerStart( DNSServerRef inServer );
+static void DNSServerStop( DNSServerRef inServer );
+
+#define ForgetDNSServer( X ) ForgetCustomEx( X, DNSServerStop, CFRelease )
+
+static void DNSServerCmdContextFree( DNSServerCmdContext *inContext );
+static void DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
+static void DNSServerCmdSigIntHandler( void *inContext );
+static void DNSServerCmdSigTermHandler( void *inContext );
+#if( TARGET_OS_DARWIN )
+static void DNSServerCmdFollowedProcessHandler( void *inContext );
+#endif
+
+ulog_define_ex( kDNSSDUtilIdentifier, DNSServer, kLogLevelInfo, kLogFlags_None, "DNSServer", NULL );
+#define ds_ulog( LEVEL, ... ) ulog( &log_category_from_name( DNSServer ), (LEVEL), __VA_ARGS__ )
+
+static void DNSServerCmd( void )
+{
+ OSStatus err;
+ DNSServerCmdContext * context = NULL;
+
+ if( gDNSServer_Foreground )
+ {
+ LogControl( "DNSServer:output=file;stdout,DNSServer:flags=time;prefix" );
+ }
+
+ err = CheckIntegerArgument( gDNSServer_ResponseDelayMs, "response delay (ms)", 0, INT_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gDNSServer_DefaultTTL, "default TTL", 0, INT32_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gDNSServer_Port, "port number", -UINT16_MAX, UINT16_MAX );
+ require_noerr_quiet( err, exit );
+
+ context = (DNSServerCmdContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->domainOverride = gDNSServer_DomainOverride;
+ context->loopbackOnly = gDNSServer_LoopbackOnly ? true : false;
+
+#if( TARGET_OS_DARWIN )
+ if( gDNSServer_FollowPID )
+ {
+ context->followPID = _StringToPID( gDNSServer_FollowPID, &err );
+ if( err || ( context->followPID < 0 ) )
+ {
+ FPrintF( stderr, "error: Invalid follow PID: %s\n", gDNSServer_FollowPID );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
+ DNSServerCmdFollowedProcessHandler, NULL, context, &context->processMonitor );
+ require_noerr( err, exit );
+ dispatch_resume( context->processMonitor );
+ }
+ else
+ {
+ context->followPID = -1;
+ }
+#endif
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, DNSServerCmdSigIntHandler, context, &context->sigIntSource );
+ require_noerr( err, exit );
+ dispatch_resume( context->sigIntSource );
+
+ signal( SIGTERM, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGTERM, DNSServerCmdSigTermHandler, context, &context->sigTermSource );
+ require_noerr( err, exit );
+ dispatch_resume( context->sigTermSource );
+
+ err = DNSServerCreate( dispatch_get_main_queue(), DNSServerCmdEventHandler, context,
+ (unsigned int) gDNSServer_ResponseDelayMs, (uint32_t) gDNSServer_DefaultTTL, gDNSServer_Port, context->loopbackOnly,
+ context->domainOverride, gDNSServer_BadUDPMode ? true : false, &context->server );
+ require_noerr( err, exit );
+
+ DNSServerStart( context->server );
+ dispatch_main();
+
+exit:
+ FPrintF( stderr, "Failed to start DNS server: %#m\n", err );
+ if( context ) DNSServerCmdContextFree( context );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// DNSServerCmdContextFree
+//===========================================================================================================================
+
+static void DNSServerCmdContextFree( DNSServerCmdContext *inContext )
+{
+ ForgetCF( &inContext->server );
+ dispatch_source_forget( &inContext->sigIntSource );
+ dispatch_source_forget( &inContext->sigTermSource );
+#if( TARGET_OS_DARWIN )
+ dispatch_source_forget( &inContext->processMonitor );
+#endif
+ free( inContext );
+}
+
+//===========================================================================================================================
+// DNSServerCmdEventHandler
+//===========================================================================================================================
+
+#if( TARGET_OS_DARWIN )
+static OSStatus _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort );
+static OSStatus _DNSServerCmdLoopbackResolverRemove( void );
+#endif
+
+static void DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext )
+{
+ OSStatus err;
+ DNSServerCmdContext * const context = (DNSServerCmdContext *) inContext;
+
+ if( inType == kDNSServerEvent_Started )
+ {
+ #if( TARGET_OS_DARWIN )
+ const int port = (int) inEventData;
+
+ err = _DNSServerCmdLoopbackResolverAdd( context->domainOverride ? context->domainOverride : "d.test.", port );
+ if( err )
+ {
+ ds_ulog( kLogLevelError, "Failed to add loopback resolver to DNS configuration for \"d.test.\" domain: %#m\n",
+ err );
+ if( context->loopbackOnly ) ForgetDNSServer( &context->server );
+ }
+ else
+ {
+ context->addedResolver = true;
+ }
+ #endif
+ }
+ else if( inType == kDNSServerEvent_Stopped )
+ {
+ const OSStatus stopError = (OSStatus) inEventData;
+
+ if( stopError ) ds_ulog( kLogLevelError, "The server stopped unexpectedly with error: %#m.\n", stopError );
+
+ err = kNoErr;
+ #if( TARGET_OS_DARWIN )
+ if( context->addedResolver )
+ {
+ err = _DNSServerCmdLoopbackResolverRemove();
+ if( err )
+ {
+ ds_ulog( kLogLevelError, "Failed to remove loopback resolver from DNS configuration: %#m\n", err );
+ }
+ else
+ {
+ context->addedResolver = false;
+ }
+ }
+ else if( context->loopbackOnly )
+ {
+ err = kUnknownErr;
+ }
+ #endif
+ DNSServerCmdContextFree( context );
+ exit( ( stopError || err ) ? 1 : 0 );
+ }
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// _DNSServerCmdLoopbackResolverAdd
+//===========================================================================================================================
+
+static OSStatus _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort )
+{
+ OSStatus err;
+ SCDynamicStoreRef store;
+ CFPropertyListRef plist = NULL;
+ CFStringRef key = NULL;
+ const uint32_t loopbackV4 = htonl( INADDR_LOOPBACK );
+ Boolean success;
+
+ store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+ err = map_scerror( store );
+ require_noerr( err, exit );
+
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO="
+ "["
+ "%s"
+ "]"
+ "%kO="
+ "["
+ "%.4a"
+ "%.16a"
+ "]"
+ "%kO=%i"
+ "%kO=%O"
+ "%kO=%O"
+ "}",
+ kSCPropNetDNSSupplementalMatchDomains, inDomain,
+ kSCPropNetDNSServerAddresses, &loopbackV4, in6addr_loopback.s6_addr,
+ kSCPropNetDNSServerPort, inPort,
+ kSCPropInterfaceName, CFSTR( "lo0" ),
+ kSCPropNetDNSConfirmedServiceID, CFSTR( "com.apple.dnssdutil.server" ) );
+ require_noerr( err, exit );
+
+ key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
+ CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
+ require_action( key, exit, err = kUnknownErr );
+
+ success = SCDynamicStoreSetValue( store, key, plist );
+ require_action( success, exit, err = kUnknownErr );
+
+exit:
+ CFReleaseNullSafe( store );
+ CFReleaseNullSafe( plist );
+ CFReleaseNullSafe( key );
+ return( err );
+}
+
+//===========================================================================================================================
+// _DNSServerCmdLoopbackResolverRemove
+//===========================================================================================================================
+
+static OSStatus _DNSServerCmdLoopbackResolverRemove( void )
+{
+ OSStatus err;
+ SCDynamicStoreRef store;
+ CFStringRef key = NULL;
+ Boolean success;
+
+ store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+ err = map_scerror( store );
+ require_noerr( err, exit );
+
+ key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
+ CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
+ require_action( key, exit, err = kUnknownErr );
+
+ success = SCDynamicStoreRemoveValue( store, key );
+ require_action( success, exit, err = kUnknownErr );
+
+exit:
+ CFReleaseNullSafe( store );
+ CFReleaseNullSafe( key );
+ return( err );
+}
+#endif
+
+//===========================================================================================================================
+// DNSServerCmdSigIntHandler
+//===========================================================================================================================
+
+static void _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal );
+
+static void DNSServerCmdSigIntHandler( void *inContext )
+{
+ _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGINT );
+}
+
+//===========================================================================================================================
+// DNSServerCmdSigTermHandler
+//===========================================================================================================================
+
+static void DNSServerCmdSigTermHandler( void *inContext )
+{
+ _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGTERM );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// DNSServerCmdFollowedProcessHandler
+//===========================================================================================================================
+
+static void DNSServerCmdFollowedProcessHandler( void *inContext )
+{
+ DNSServerCmdContext * const context = (DNSServerCmdContext *) inContext;
+
+ if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT ) _DNSServerCmdShutdown( context, 0 );
+}
+#endif
+
+//===========================================================================================================================
+// _DNSServerCmdExternalExit
+//===========================================================================================================================
+
+#define SignalNumberToString( X ) ( \
+ ( (X) == SIGINT ) ? "SIGINT" : \
+ ( (X) == SIGTERM ) ? "SIGTERM" : \
+ "???" )
+
+static void _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal )
+{
+ dispatch_source_forget( &inContext->sigIntSource );
+ dispatch_source_forget( &inContext->sigTermSource );
+#if( TARGET_OS_DARWIN )
+ dispatch_source_forget( &inContext->processMonitor );
+
+ if( inSignal == 0 )
+ {
+ ds_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited\n", (int64_t) inContext->followPID );
+ }
+ else
+#endif
+ {
+ ds_ulog( kLogLevelNotice, "Exiting: received signal %d (%s)\n", inSignal, SignalNumberToString( inSignal ) );
+ }
+
+ ForgetDNSServer( &inContext->server );
+}
+
+//===========================================================================================================================
+// DNSServerCreate
+//===========================================================================================================================
+
+#define kDDotTestDomainName (const uint8_t *) "\x01" "d" "\x04" "test"
+
+typedef struct DNSDelayedResponse DNSDelayedResponse;
+struct DNSDelayedResponse
+{
+ DNSDelayedResponse * next;
+ sockaddr_ip destAddr;
+ uint64_t targetTicks;
+ uint8_t * msgPtr;
+ size_t msgLen;
+};
+
+struct DNSServerPrivate
+{
+ CFRuntimeBase base; // CF object base.
+ uint8_t * domain; // Parent domain of server's resource records.
+ dispatch_queue_t queue; // Queue for DNS server's events.
+ dispatch_source_t readSourceUDPv4; // Read source for IPv4 UDP socket.
+ dispatch_source_t readSourceUDPv6; // Read source for IPv6 UDP socket.
+ dispatch_source_t readSourceTCPv4; // Read source for IPv4 TCP socket.
+ dispatch_source_t readSourceTCPv6; // Read source for IPv6 TCP socket.
+ SocketRef sockUDPv4;
+ SocketRef sockUDPv6;
+ DNSServerEventHandler_f eventHandler;
+ void * eventContext;
+ DNSDelayedResponse * responseList;
+ dispatch_source_t responseTimer;
+ unsigned int responseDelayMs;
+ uint32_t defaultTTL;
+ uint32_t serial; // Serial number for SOA record.
+ int port; // Port to use for receiving and sending DNS messages.
+ OSStatus stopError;
+ Boolean stopped;
+ Boolean loopbackOnly;
+ Boolean badUDPMode; // True if the server runs in Bad UDP mode.
+};
+
+static void _DNSServerUDPReadHandler( void *inContext );
+static void _DNSServerTCPReadHandler( void *inContext );
+static void _DNSDelayedResponseFree( DNSDelayedResponse *inResponse );
+static void _DNSDelayedResponseFreeList( DNSDelayedResponse *inList );
+
+CF_CLASS_DEFINE( DNSServer );
+
+static OSStatus
+ DNSServerCreate(
+ dispatch_queue_t inQueue,
+ DNSServerEventHandler_f inEventHandler,
+ void * inEventContext,
+ unsigned int inResponseDelayMs,
+ uint32_t inDefaultTTL,
+ int inPort,
+ Boolean inLoopbackOnly,
+ const char * inDomain,
+ Boolean inBadUDPMode,
+ DNSServerRef * outServer )
+{
+ OSStatus err;
+ DNSServerRef obj = NULL;
+
+ require_action_quiet( inDefaultTTL <= INT32_MAX, exit, err = kRangeErr );
+
+ CF_OBJECT_CREATE( DNSServer, obj, err, exit );
+
+ ReplaceDispatchQueue( &obj->queue, inQueue );
+ obj->eventHandler = inEventHandler;
+ obj->eventContext = inEventContext;
+ obj->responseDelayMs = inResponseDelayMs;
+ obj->defaultTTL = inDefaultTTL;
+ obj->port = inPort;
+ obj->loopbackOnly = inLoopbackOnly;
+ obj->badUDPMode = inBadUDPMode;
+
+ if( inDomain )
+ {
+ err = StringToDomainName( inDomain, &obj->domain, NULL );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ err = DomainNameDup( kDDotTestDomainName, &obj->domain, NULL );
+ require_noerr_quiet( err, exit );
+ }
+
+ *outServer = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ CFReleaseNullSafe( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _DNSServerFinalize
+//===========================================================================================================================
+
+static void _DNSServerFinalize( CFTypeRef inObj )
+{
+ DNSServerRef const me = (DNSServerRef) inObj;
+
+ check( !me->readSourceUDPv4 );
+ check( !me->readSourceUDPv6 );
+ check( !me->readSourceTCPv4 );
+ check( !me->readSourceTCPv6 );
+ check( !me->responseTimer );
+ ForgetMem( &me->domain );
+ dispatch_forget( &me->queue );
+}
+
+//===========================================================================================================================
+// DNSServerStart
+//===========================================================================================================================
+
+static void _DNSServerStart( void *inContext );
+static void _DNSServerStop( void *inContext, OSStatus inError );
+
+static void DNSServerStart( DNSServerRef me )
+{
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _DNSServerStart );
+}
+
+static void _DNSServerStart( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ DNSServerRef const me = (DNSServerRef) inContext;
+ SocketRef sock = kInvalidSocketRef;
+ SocketContext * sockCtx = NULL;
+ const uint32_t loopbackV4 = htonl( INADDR_LOOPBACK );
+ int year, month, day;
+
+ // Create IPv4 UDP socket.
+ // Initially, me->port is the port requested by the user. If it's 0, then the user wants any available ephemeral port.
+ // If it's negative, then the user would like a port number equal to its absolute value, but will settle for any
+ // available ephemeral port, if it's not available. The actual port number that was used will be stored in me->port and
+ // used for the remaining sockets.
+
+ err = _ServerSocketOpenEx2( AF_INET, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &loopbackV4 : NULL,
+ me->port, &me->port, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
+ require_noerr( err, exit );
+ check( me->port > 0 );
+
+ // Create read source for IPv4 UDP socket.
+
+ err = SocketContextCreate( sock, me, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
+ &me->readSourceUDPv4 );
+ require_noerr( err, exit );
+ dispatch_resume( me->readSourceUDPv4 );
+ me->sockUDPv4 = sockCtx->sock;
+ sockCtx = NULL;
+
+ // Create IPv6 UDP socket.
+
+ err = _ServerSocketOpenEx2( AF_INET6, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &in6addr_loopback : NULL,
+ me->port, NULL, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
+ require_noerr( err, exit );
+
+ // Create read source for IPv6 UDP socket.
+
+ err = SocketContextCreate( sock, me, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
+ &me->readSourceUDPv6 );
+ require_noerr( err, exit );
+ dispatch_resume( me->readSourceUDPv6 );
+ me->sockUDPv6 = sockCtx->sock;
+ sockCtx = NULL;
+
+ // Create IPv4 TCP socket.
+
+ err = _ServerSocketOpenEx2( AF_INET, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &loopbackV4 : NULL,
+ me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
+ require_noerr( err, exit );
+
+ // Create read source for IPv4 TCP socket.
+
+ err = SocketContextCreate( sock, me, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
+ &me->readSourceTCPv4 );
+ require_noerr( err, exit );
+ dispatch_resume( me->readSourceTCPv4 );
+ sockCtx = NULL;
+
+ // Create IPv6 TCP socket.
+
+ err = _ServerSocketOpenEx2( AF_INET6, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &in6addr_loopback : NULL,
+ me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
+ require_noerr( err, exit );
+
+ // Create read source for IPv6 TCP socket.
+
+ err = SocketContextCreate( sock, me, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
+ &me->readSourceTCPv6 );
+ require_noerr( err, exit );
+ dispatch_resume( me->readSourceTCPv6 );
+ sockCtx = NULL;
+
+ ds_ulog( kLogLevelInfo, "Server is using port %d.\n", me->port );
+ if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Started, (uintptr_t) me->port, me->eventContext );
+
+ // Create the serial number for the server's SOA record in the YYYMMDDnn convention recommended by
+ // <https://tools.ietf.org/html/rfc1912#section-2.2> using the current time.
+
+ gettimeofday( &now, NULL );
+ SecondsToYMD_HMS( ( INT64_C_safe( kDaysToUnixEpoch ) * kSecondsPerDay ) + now.tv_sec, &year, &month, &day,
+ NULL, NULL, NULL );
+ me->serial = (uint32_t)( ( year * 1000000 ) + ( month * 10000 ) + ( day * 100 ) + 1 );
+
+exit:
+ ForgetSocket( &sock );
+ if( sockCtx ) SocketContextRelease( sockCtx );
+ if( err ) _DNSServerStop( me, err );
+}
+
+//===========================================================================================================================
+// DNSServerStop
+//===========================================================================================================================
+
+static void _DNSServerUserStop( void *inContext );
+static void _DNSServerStop2( void *inContext );
+
+static void DNSServerStop( DNSServerRef me )
+{
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _DNSServerUserStop );
+}
+
+static void _DNSServerUserStop( void *inContext )
+{
+ DNSServerRef const me = (DNSServerRef) inContext;
+
+ _DNSServerStop( me, kNoErr );
+ CFRelease( me );
+}
+
+static void _DNSServerStop( void *inContext, OSStatus inError )
+{
+ DNSServerRef const me = (DNSServerRef) inContext;
+
+ me->stopError = inError;
+ dispatch_source_forget( &me->readSourceUDPv4 );
+ dispatch_source_forget( &me->readSourceUDPv6 );
+ dispatch_source_forget( &me->readSourceTCPv4 );
+ dispatch_source_forget( &me->readSourceTCPv6 );
+ dispatch_source_forget( &me->responseTimer );
+ me->sockUDPv4 = kInvalidSocketRef;
+ me->sockUDPv6 = kInvalidSocketRef;
+
+ if( me->responseList )
+ {
+ _DNSDelayedResponseFreeList( me->responseList );
+ me->responseList = NULL;
+ }
+ dispatch_async_f( me->queue, me, _DNSServerStop2 );
+}
+
+static void _DNSServerStop2( void *inContext )
+{
+ DNSServerRef const me = (DNSServerRef) inContext;
+
+ if( !me->stopped )
+ {
+ me->stopped = true;
+ if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Stopped, (uintptr_t) me->stopError, me->eventContext );
+ CFRelease( me );
+ }
+ CFRelease( me );
+}
+
+//===========================================================================================================================
+// _DNSDelayedResponseFree
+//===========================================================================================================================
+
+static void _DNSDelayedResponseFree( DNSDelayedResponse *inResponse )
+{
+ ForgetMem( &inResponse->msgPtr );
+ free( inResponse );
+}
+
+//===========================================================================================================================
+// _DNSDelayedResponseFreeList
+//===========================================================================================================================
+
+static void _DNSDelayedResponseFreeList( DNSDelayedResponse *inList )
+{
+ DNSDelayedResponse * response;
+
+ while( ( response = inList ) != NULL )
+ {
+ inList = response->next;
+ _DNSDelayedResponseFree( response );
+ }
+}
+
+//===========================================================================================================================
+// _DNSServerUDPReadHandler
+//===========================================================================================================================
+
+static OSStatus
+ _DNSServerAnswerQuery(
+ DNSServerRef inServer,
+ const uint8_t * inQueryPtr,
+ size_t inQueryLen,
+ Boolean inForTCP,
+ uint8_t ** outResponsePtr,
+ size_t * outResponseLen );
+
+#define _DNSServerAnswerQueryForUDP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
+ _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, false, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
+
+#define _DNSServerAnswerQueryForTCP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
+ _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, true, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
+
+static OSStatus
+ _DNSServerScheduleDelayedResponse(
+ DNSServerRef inServer,
+ const struct sockaddr * inDestAddr,
+ uint8_t * inMsgPtr,
+ size_t inMsgLen );
+static void _DNSServerUDPDelayedSend( void *inContext );
+
+static void _DNSServerUDPReadHandler( void *inContext )
+{
+ OSStatus err;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ DNSServerRef const me = (DNSServerRef) sockCtx->userContext;
+ struct timeval now;
+ ssize_t n;
+ sockaddr_ip clientAddr;
+ socklen_t clientAddrLen;
+ uint8_t * responsePtr = NULL; // malloc'd
+ size_t responseLen;
+ uint8_t msg[ 512 ];
+
+ gettimeofday( &now, NULL );
+
+ // Receive message.
+
+ clientAddrLen = (socklen_t) sizeof( clientAddr );
+ n = recvfrom( sockCtx->sock, (char *) msg, sizeof( msg ), 0, &clientAddr.sa, &clientAddrLen );
+ err = map_socket_value_errno( sockCtx->sock, n >= 0, n );
+ require_noerr( err, exit );
+
+ ds_ulog( kLogLevelInfo, "UDP server received %zd bytes from %##a at %{du:time}.\n", n, &clientAddr, &now );
+
+ if( n < kDNSHeaderLength )
+ {
+ ds_ulog( kLogLevelInfo, "UDP DNS message is too small (%zd < %d).\n", n, kDNSHeaderLength );
+ goto exit;
+ }
+
+ ds_ulog( kLogLevelInfo, "UDP received message:\n\n%1{du:dnsmsg}", msg, (size_t) n );
+
+ // Create response.
+
+ err = _DNSServerAnswerQueryForUDP( me, msg, (size_t) n, &responsePtr, &responseLen );
+ require_noerr_quiet( err, exit );
+
+ // Schedule response.
+
+ if( me->responseDelayMs > 0 )
+ {
+ err = _DNSServerScheduleDelayedResponse( me, &clientAddr.sa, responsePtr, responseLen );
+ require_noerr( err, exit );
+ responsePtr = NULL;
+ }
+ else
+ {
+ ds_ulog( kLogLevelInfo, "UDP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
+
+ n = sendto( sockCtx->sock, (char *) responsePtr, responseLen, 0, &clientAddr.sa, clientAddrLen );
+ err = map_socket_value_errno( sockCtx->sock, n == (ssize_t) responseLen, n );
+ require_noerr( err, exit );
+ }
+
+exit:
+ FreeNullSafe( responsePtr );
+ return;
+}
+
+static OSStatus
+ _DNSServerScheduleDelayedResponse(
+ DNSServerRef me,
+ const struct sockaddr * inDestAddr,
+ uint8_t * inMsgPtr,
+ size_t inMsgLen )
+{
+ OSStatus err;
+ DNSDelayedResponse * response;
+ DNSDelayedResponse ** responsePtr;
+ DNSDelayedResponse * newResponse;
+ uint64_t targetTicks;
+
+ targetTicks = UpTicks() + MillisecondsToUpTicks( me->responseDelayMs );
+
+ newResponse = (DNSDelayedResponse *) calloc( 1, sizeof( *newResponse ) );
+ require_action( newResponse, exit, err = kNoMemoryErr );
+
+ if( !me->responseList || ( targetTicks < me->responseList->targetTicks ) )
+ {
+ dispatch_source_forget( &me->responseTimer );
+
+ err = DispatchTimerCreate( dispatch_time_milliseconds( me->responseDelayMs ), DISPATCH_TIME_FOREVER,
+ ( (uint64_t) me->responseDelayMs ) * kNanosecondsPerMillisecond / 10, me->queue, _DNSServerUDPDelayedSend,
+ NULL, me, &me->responseTimer );
+ require_noerr( err, exit );
+ dispatch_resume( me->responseTimer );
+ }
+
+ SockAddrCopy( inDestAddr, &newResponse->destAddr );
+ newResponse->targetTicks = targetTicks;
+ newResponse->msgPtr = inMsgPtr;
+ newResponse->msgLen = inMsgLen;
+
+ for( responsePtr = &me->responseList; ( response = *responsePtr ) != NULL; responsePtr = &response->next )
+ {
+ if( newResponse->targetTicks < response->targetTicks ) break;
+ }
+ newResponse->next = response;
+ *responsePtr = newResponse;
+ newResponse = NULL;
+ err = kNoErr;
+
+exit:
+ if( newResponse ) _DNSDelayedResponseFree( newResponse );
+ return( err );
+}
+
+static void _DNSServerUDPDelayedSend( void *inContext )
+{
+ OSStatus err;
+ DNSServerRef const me = (DNSServerRef) inContext;
+ DNSDelayedResponse * response;
+ SocketRef sock;
+ ssize_t n;
+ uint64_t nowTicks;
+ uint64_t remainingNs;
+ DNSDelayedResponse * freeList = NULL;
+
+ dispatch_source_forget( &me->responseTimer );
+
+ nowTicks = UpTicks();
+ while( ( ( response = me->responseList ) != NULL ) && ( response->targetTicks <= nowTicks ) )
+ {
+ me->responseList = response->next;
+
+ ds_ulog( kLogLevelInfo, "UDP sending %zu byte response (delayed):\n\n%1{du:dnsmsg}",
+ response->msgLen, response->msgPtr, response->msgLen );
+
+ sock = ( response->destAddr.sa.sa_family == AF_INET ) ? me->sockUDPv4 : me->sockUDPv6;
+ n = sendto( sock, (char *) response->msgPtr, response->msgLen, 0, &response->destAddr.sa,
+ SockAddrGetSize( &response->destAddr ) );
+ err = map_socket_value_errno( sock, n == (ssize_t) response->msgLen, n );
+ check_noerr( err );
+
+ response->next = freeList;
+ freeList = response;
+ nowTicks = UpTicks();
+ }
+
+ if( response )
+ {
+ check( response->targetTicks > nowTicks );
+ remainingNs = UpTicksToNanoseconds( response->targetTicks - nowTicks );
+ if( remainingNs > INT64_MAX ) remainingNs = INT64_MAX;
+
+ err = DispatchTimerCreate( dispatch_time( DISPATCH_TIME_NOW, (int64_t) remainingNs ), DISPATCH_TIME_FOREVER, 0,
+ me->queue, _DNSServerUDPDelayedSend, NULL, me, &me->responseTimer );
+ require_noerr( err, exit );
+ dispatch_resume( me->responseTimer );
+ }
+
+exit:
+ if( freeList ) _DNSDelayedResponseFreeList( freeList );
+}
+
+//===========================================================================================================================
+// _DNSServerAnswerQuery
+//===========================================================================================================================
+
+#define kLabelPrefix_Alias "alias"
+#define kLabelPrefix_AliasTTL "alias-ttl"
+#define kLabelPrefix_Count "count-"
+#define kLabelPrefix_Tag "tag-"
+#define kLabelPrefix_TTL "ttl-"
+#define kLabel_IPv4 "ipv4"
+#define kLabel_IPv6 "ipv6"
+#define kLabelPrefix_SRV "srv-"
+
+#define kMaxAliasTTLCount ( ( kDomainLabelLengthMax - sizeof_string( kLabelPrefix_AliasTTL ) ) / 2 )
+#define kMaxParsedSRVCount ( kDomainNameLengthMax / ( 1 + sizeof_string( kLabelPrefix_SRV ) + 5 ) )
+
+typedef struct
+{
+ uint16_t priority; // Priority from SRV label.
+ uint16_t weight; // Weight from SRV label.
+ uint16_t port; // Port number from SRV label.
+ uint16_t targetLen; // Total length of the target hostname labels that follow an SRV label.
+ const uint8_t * targetPtr; // Pointer to the target hostname embedded in a domain name.
+
+} ParsedSRV;
+
+static OSStatus
+ _DNSServerInitializeResponseMessage(
+ DataBuffer * inDB,
+ unsigned int inID,
+ unsigned int inFlags,
+ const uint8_t * inQName,
+ unsigned int inQType,
+ unsigned int inQClass );
+static OSStatus
+ _DNSServerAnswerQueryDynamically(
+ DNSServerRef inServer,
+ const uint8_t * inQName,
+ unsigned int inQType,
+ unsigned int inQClass,
+ Boolean inForTCP,
+ DataBuffer * inDB );
+static Boolean
+ _DNSServerNameIsSRVName(
+ DNSServerRef inServer,
+ const uint8_t * inName,
+ const uint8_t ** outDomainPtr,
+ size_t * outDomainLen,
+ ParsedSRV inSRVArray[ kMaxParsedSRVCount ],
+ size_t * outSRVCount );
+static Boolean
+ _DNSServerNameIsHostname(
+ DNSServerRef inServer,
+ const uint8_t * inName,
+ uint32_t * outAliasCount,
+ uint32_t inAliasTTLs[ kMaxAliasTTLCount ],
+ size_t * outAliasTTLCount,
+ unsigned int * outCount,
+ unsigned int * outRandCount,
+ uint32_t * outTTL,
+ Boolean * outHasA,
+ Boolean * outHasAAAA,
+ Boolean * outHasSOA );
+
+static OSStatus
+ _DNSServerAnswerQuery(
+ DNSServerRef me,
+ const uint8_t * const inQueryPtr,
+ const size_t inQueryLen,
+ Boolean inForTCP,
+ uint8_t ** outResponsePtr,
+ size_t * outResponseLen )
+{
+ OSStatus err;
+ DataBuffer dataBuf;
+ const uint8_t * ptr;
+ const uint8_t * const queryEnd = &inQueryPtr[ inQueryLen ];
+ const DNSHeader * qhdr;
+ const dns_fixed_fields_question * fields;
+ unsigned int msgID, qflags, qtype, qclass, rflags;
+ uint8_t qname[ kDomainNameLengthMax ];
+
+ DataBuffer_Init( &dataBuf, NULL, 0, kDNSMaxTCPMessageSize );
+
+ require_action_quiet( inQueryLen >= kDNSHeaderLength, exit, err = kUnderrunErr );
+
+ qhdr = (const DNSHeader *) inQueryPtr;
+ msgID = DNSHeaderGetID( qhdr );
+ qflags = DNSHeaderGetFlags( qhdr );
+
+ // Minimal checking of the query message's header.
+
+ if( ( qflags & kDNSHeaderFlag_Response ) || // The message must be a query, not a response.
+ ( DNSFlagsGetOpCode( qflags ) != kDNSOpCode_Query ) || // OPCODE must be QUERY (standard query).
+ ( DNSHeaderGetQuestionCount( qhdr ) != 1 ) ) // There should be a single question.
+ {
+ err = kRequestErr;
+ goto exit;
+ }
+
+ // Get QNAME.
+
+ ptr = (const uint8_t *) &qhdr[ 1 ];
+ err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, ptr, qname, &ptr );
+ require_noerr( err, exit );
+
+ // Get QTYPE and QCLASS.
+
+ require_action_quiet( ( (size_t)( queryEnd - ptr ) ) >= sizeof( *fields ), exit, err = kUnderrunErr );
+ fields = (const dns_fixed_fields_question *) ptr;
+ qtype = dns_fixed_fields_question_get_type( fields );
+ qclass = dns_fixed_fields_question_get_class( fields );
+
+ // Create a tentative response message.
+
+ rflags = kDNSHeaderFlag_Response;
+ if( qflags & kDNSHeaderFlag_RecursionDesired ) rflags |= kDNSHeaderFlag_RecursionDesired;
+ DNSFlagsSetOpCode( rflags, kDNSOpCode_Query );
+
+ if( me->badUDPMode && !inForTCP ) msgID = (uint16_t)( msgID + 1 );
+ err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
+ require_noerr( err, exit );
+
+ err = _DNSServerAnswerQueryDynamically( me, qname, qtype, qclass, inForTCP, &dataBuf );
+ if( err )
+ {
+ DNSFlagsSetRCode( rflags, kDNSRCode_ServerFailure );
+ err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
+ require_noerr( err, exit );
+ }
+
+ err = DataBuffer_Detach( &dataBuf, outResponsePtr, outResponseLen );
+ require_noerr( err, exit );
+
+exit:
+ DataBuffer_Free( &dataBuf );
+ return( err );
+}
+
+static OSStatus
+ _DNSServerInitializeResponseMessage(
+ DataBuffer * inDB,
+ unsigned int inID,
+ unsigned int inFlags,
+ const uint8_t * inQName,
+ unsigned int inQType,
+ unsigned int inQClass )
+{
+ OSStatus err;
+ DNSHeader header;
+
+ DataBuffer_Reset( inDB );
+
+ memset( &header, 0, sizeof( header ) );
+ DNSHeaderSetID( &header, inID );
+ DNSHeaderSetFlags( &header, inFlags );
+ DNSHeaderSetQuestionCount( &header, 1 );
+
+ err = DataBuffer_Append( inDB, &header, sizeof( header ) );
+ require_noerr( err, exit );
+
+ err = _DataBuffer_AppendDNSQuestion( inDB, inQName, DomainNameLength( inQName ), (uint16_t) inQType,
+ (uint16_t) inQClass );
+ require_noerr( err, exit );
+
+exit:
+ return( err );
+}
+
+static OSStatus
+ _DNSServerAnswerQueryDynamically(
+ DNSServerRef me,
+ const uint8_t * const inQName,
+ const unsigned int inQType,
+ const unsigned int inQClass,
+ const Boolean inForTCP,
+ DataBuffer * const inDB )
+{
+ OSStatus err;
+ DNSHeader * hdr;
+ unsigned int flags, rcode;
+ uint32_t aliasCount, i;
+ uint32_t aliasTTLs[ kMaxAliasTTLCount ];
+ size_t aliasTTLCount;
+ unsigned int addrCount, randCount;
+ uint32_t ttl;
+ ParsedSRV srvArray[ kMaxParsedSRVCount ];
+ size_t srvCount;
+ const uint8_t * srvDomainPtr;
+ size_t srvDomainLen;
+ unsigned int answerCount;
+ Boolean notImplemented, truncated;
+ Boolean useAliasTTLs, nameExists, nameHasA, nameHasAAAA, nameHasSRV, nameHasSOA;
+ uint8_t namePtr[ 2 ];
+ dns_fixed_fields_record fields;
+
+ answerCount = 0;
+ truncated = false;
+ nameExists = false;
+ require_action_quiet( inQClass == kDNSServiceClass_IN, done, notImplemented = true );
+
+ notImplemented = false;
+ aliasCount = 0;
+ nameHasA = false;
+ nameHasAAAA = false;
+ nameHasSOA = false;
+ useAliasTTLs = false;
+ nameHasSRV = false;
+ srvDomainLen = 0;
+ srvCount = 0;
+
+ if( _DNSServerNameIsHostname( me, inQName, &aliasCount, aliasTTLs, &aliasTTLCount, &addrCount, &randCount, &ttl,
+ &nameHasA, &nameHasAAAA, &nameHasSOA ) )
+ {
+ check( !( ( aliasCount > 0 ) && ( aliasTTLCount > 0 ) ) );
+ check( ( addrCount >= 1 ) && ( addrCount <= 255 ) );
+ check( ( randCount == 0 ) || ( ( randCount >= addrCount ) && ( randCount <= 255 ) ) );
+ check( nameHasA || nameHasAAAA );
+
+ if( aliasTTLCount > 0 )
+ {
+ aliasCount = (uint32_t) aliasTTLCount;
+ useAliasTTLs = true;
+ }
+ nameExists = true;
+ }
+ else if( _DNSServerNameIsSRVName( me, inQName, &srvDomainPtr, &srvDomainLen, srvArray, &srvCount ) )
+ {
+ nameHasSRV = true;
+ nameExists = true;
+ }
+ require_quiet( nameExists, done );
+
+ if( aliasCount > 0 )
+ {
+ size_t nameOffset;
+ uint8_t rdataLabel[ 1 + kDomainLabelLengthMax + 1 ];
+
+ // If aliasCount is non-zero, then the first label of QNAME is either "alias" or "alias-<N>". superPtr is a name
+ // compression pointer to the second label of QNAME, i.e., the immediate superdomain name of QNAME. It's used for
+ // the RDATA of CNAME records whose canonical name ends with the superdomain name. It may also be used to construct
+ // CNAME record names, when the offset to the previous CNAME's RDATA doesn't fit in a compression pointer.
+
+ const uint8_t superPtr[ 2 ] = { 0xC0, (uint8_t)( kDNSHeaderLength + 1 + inQName[ 0 ] ) };
+
+ // The name of the first CNAME record is equal to QNAME, so nameOffset is set to offset of QNAME.
+
+ nameOffset = kDNSHeaderLength;
+
+ for( i = aliasCount; i >= 1; --i )
+ {
+ size_t nameLen;
+ size_t rdataLen;
+ uint32_t j;
+ uint32_t aliasTTL;
+ uint8_t nameLabel[ 1 + kDomainLabelLengthMax ];
+
+ if( nameOffset <= kDNSCompressionOffsetMax )
+ {
+ DNSMessageWriteLabelPointer( namePtr, nameOffset );
+ nameLen = sizeof( namePtr );
+ }
+ else
+ {
+ memcpy( nameLabel, rdataLabel, 1 + rdataLabel[ 0 ] );
+ nameLen = 1 + nameLabel[ 0 ] + sizeof( superPtr );
+ }
+
+ if( i >= 2 )
+ {
+ char * dst = (char *) &rdataLabel[ 1 ];
+ char * const lim = (char *) &rdataLabel[ countof( rdataLabel ) ];
+
+ if( useAliasTTLs )
+ {
+ err = SNPrintF_Add( &dst, lim, kLabelPrefix_AliasTTL );
+ require_noerr( err, exit );
+
+ for( j = aliasCount - ( i - 1 ); j < aliasCount; ++j )
+ {
+ err = SNPrintF_Add( &dst, lim, "-%u", aliasTTLs[ j ] );
+ require_noerr( err, exit );
+ }
+ }
+ else
+ {
+ err = SNPrintF_Add( &dst, lim, kLabelPrefix_Alias "%?{end}-%u", i == 2, i - 1 );
+ require_noerr( err, exit );
+ }
+ rdataLabel[ 0 ] = (uint8_t)( dst - (char *) &rdataLabel[ 1 ] );
+ rdataLen = 1 + rdataLabel[ 0 ] + sizeof( superPtr );
+ }
+ else
+ {
+ rdataLen = sizeof( superPtr );
+ }
+
+ if( !inForTCP )
+ {
+ size_t recordLen = nameLen + sizeof( fields ) + rdataLen;
+
+ if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
+ {
+ truncated = true;
+ goto done;
+ }
+ }
+ ++answerCount;
+
+ // Set CNAME record's NAME.
+
+ if( nameOffset <= kDNSCompressionOffsetMax )
+ {
+ err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DataBuffer_Append( inDB, nameLabel, 1 + nameLabel[ 0 ] );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
+ require_noerr( err, exit );
+ }
+
+ // Set CNAME record's TYPE, CLASS, TTL, and RDLENGTH.
+
+ aliasTTL = useAliasTTLs ? aliasTTLs[ aliasCount - i ] : me->defaultTTL;
+ dns_fixed_fields_record_init( &fields, kDNSServiceType_CNAME, kDNSServiceClass_IN, aliasTTL,
+ (uint16_t) rdataLen );
+ err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+
+ // Save offset of CNAME record's RDATA, which may be used for the name of the next CNAME record.
+
+ nameOffset = DataBuffer_GetLen( inDB );
+
+ // Set CNAME record's RDATA.
+
+ if( i >= 2 )
+ {
+ err = DataBuffer_Append( inDB, rdataLabel, 1 + rdataLabel[ 0 ] );
+ require_noerr( err, exit );
+ }
+ err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
+ require_noerr( err, exit );
+ }
+
+ namePtr[ 0 ] = superPtr[ 0 ];
+ namePtr[ 1 ] = superPtr[ 1 ];
+ }
+ else
+ {
+ // There are no aliases, so initialize the name compression pointer to point to QNAME.
+
+ DNSMessageWriteLabelPointer( namePtr, kDNSHeaderLength );
+ }
+
+ if( ( inQType == kDNSServiceType_A ) || ( inQType == kDNSServiceType_AAAA ) )
+ {
+ uint8_t * lsb; // Pointer to the least significant byte of record data.
+ size_t recordLen; // Length of the entire record.
+ size_t rdataLen; // Length of record's RDATA.
+ uint8_t rdata[ 16 ]; // A buffer that's big enough for either A or AAAA RDATA.
+ uint8_t randIntegers[ 255 ]; // Array for random integers in [1, 255].
+ const int useBadAddrs = ( me->badUDPMode && !inForTCP ) ? true : false;
+
+ if( inQType == kDNSServiceType_A )
+ {
+ const uint32_t baseAddrV4 = useBadAddrs ? kDNSServerBadBaseAddrV4 : kDNSServerBaseAddrV4;
+
+ require_quiet( nameHasA, done );
+
+ rdataLen = 4;
+ WriteBig32( rdata, baseAddrV4 );
+ lsb = &rdata[ 3 ];
+ }
+ else
+ {
+ const uint8_t * const baseAddrV6 = useBadAddrs ? kDNSServerBadBaseAddrV6 : kDNSServerBaseAddrV6;
+
+ require_quiet( nameHasAAAA, done );
+
+ rdataLen = 16;
+ memcpy( rdata, baseAddrV6, 16 );
+ lsb = &rdata[ 15 ];
+ }
+
+ if( randCount > 0 )
+ {
+ // Populate the array with all integers between 1 and <randCount>, inclusive.
+
+ for( i = 0; i < randCount; ++i ) randIntegers[ i ] = (uint8_t)( i + 1 );
+
+ // Prevent dubious static analyzer warning.
+ // Note: _DNSServerNameIsHostname() already enforces randCount >= addrCount. Also, this require_fatal() check
+ // needs to be placed right before the next for-loop. Any earlier, and the static analyzer warning will persist
+ // for some reason.
+
+ require_fatal( addrCount <= randCount, "Invalid Count label values: addrCount %u > randCount %u",
+ addrCount, randCount );
+
+ // Create a contiguous subarray starting at index 0 that contains <addrCount> randomly chosen integers between
+ // 1 and <randCount>, inclusive.
+ // Loop invariant 1: Array elements with indexes in [0, i - 1] have been randomly chosen.
+ // Loop invariant 2: Array elements with indexes in [i, randCount - 1] are candidates for being chosen.
+
+ for( i = 0; i < addrCount; ++i )
+ {
+ uint8_t tmp;
+ uint32_t j;
+
+ j = RandomRange( i, randCount - 1 );
+ if( i != j )
+ {
+ tmp = randIntegers[ i ];
+ randIntegers[ i ] = randIntegers[ j ];
+ randIntegers[ j ] = tmp;
+ }
+ }
+ }
+
+ recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
+ for( i = 0; i < addrCount; ++i )
+ {
+ if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
+ {
+ truncated = true;
+ goto done;
+ }
+
+ // Set record NAME.
+
+ err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
+ require_noerr( err, exit );
+
+ // Set record TYPE, CLASS, TTL, and RDLENGTH.
+
+ dns_fixed_fields_record_init( &fields, (uint16_t) inQType, kDNSServiceClass_IN, ttl, (uint16_t) rdataLen );
+ err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+
+ // Set record RDATA.
+
+ *lsb = ( randCount > 0 ) ? randIntegers[ i ] : ( *lsb + 1 );
+
+ err = DataBuffer_Append( inDB, rdata, rdataLen );
+ require_noerr( err, exit );
+
+ ++answerCount;
+ }
+ }
+ else if( inQType == kDNSServiceType_SRV )
+ {
+ require_quiet( nameHasSRV, done );
+
+ dns_fixed_fields_record_init( &fields, kDNSServiceType_SRV, kDNSServiceClass_IN, me->defaultTTL, 0 );
+
+ for( i = 0; i < srvCount; ++i )
+ {
+ dns_fixed_fields_srv fieldsSRV;
+ size_t rdataLen;
+ size_t recordLen;
+ const ParsedSRV * const srv = &srvArray[ i ];
+
+ rdataLen = sizeof( fieldsSRV ) + srvDomainLen + srv->targetLen + 1;
+ recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
+
+ if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
+ {
+ truncated = true;
+ goto done;
+ }
+
+ // Append record NAME.
+
+ err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
+ require_noerr( err, exit );
+
+ // Append record TYPE, CLASS, TTL, and RDLENGTH.
+
+ WriteBig16( fields.rdlength, rdataLen );
+ err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+
+ // Append SRV RDATA.
+
+ dns_fixed_fields_srv_init( &fieldsSRV, srv->priority, srv->weight, srv->port );
+
+ err = DataBuffer_Append( inDB, &fieldsSRV, sizeof( fieldsSRV ) );
+ require_noerr( err, exit );
+
+ if( srv->targetLen > 0 )
+ {
+ err = DataBuffer_Append( inDB, srv->targetPtr, srv->targetLen );
+ require_noerr( err, exit );
+ }
+
+ if( srvDomainLen > 0 )
+ {
+ err = DataBuffer_Append( inDB, srvDomainPtr, srvDomainLen );
+ require_noerr( err, exit );
+ }
+
+ err = DataBuffer_Append( inDB, "", 1 ); // Append root label.
+ require_noerr( err, exit );
+
+ ++answerCount;
+ }
+ }
+ else if( inQType == kDNSServiceType_SOA )
+ {
+ size_t nameLen, recordLen;
+
+ require_quiet( nameHasSOA, done );
+
+ nameLen = DomainNameLength( me->domain );
+ if( !inForTCP )
+ {
+ err = AppendSOARecord( NULL, me->domain, nameLen, 0, 0, 0, kRootLabel, kRootLabel, 0, 0, 0, 0, 0, &recordLen );
+ require_noerr( err, exit );
+
+ if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
+ {
+ truncated = true;
+ goto done;
+ }
+ }
+
+ err = AppendSOARecord( inDB, me->domain, nameLen, kDNSServiceType_SOA, kDNSServiceClass_IN, me->defaultTTL,
+ kRootLabel, kRootLabel, me->serial, 1 * kSecondsPerDay, 2 * kSecondsPerHour, 1000 * kSecondsPerHour,
+ me->defaultTTL, NULL );
+ require_noerr( err, exit );
+
+ ++answerCount;
+ }
+
+done:
+ hdr = (DNSHeader *) DataBuffer_GetPtr( inDB );
+ flags = DNSHeaderGetFlags( hdr );
+ if( notImplemented )
+ {
+ rcode = kDNSRCode_NotImplemented;
+ }
+ else
+ {
+ flags |= kDNSHeaderFlag_AuthAnswer;
+ if( truncated ) flags |= kDNSHeaderFlag_Truncation;
+ rcode = nameExists ? kDNSRCode_NoError : kDNSRCode_NXDomain;
+ }
+ DNSFlagsSetRCode( flags, rcode );
+ DNSHeaderSetFlags( hdr, flags );
+ DNSHeaderSetAnswerCount( hdr, answerCount );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+static Boolean
+ _DNSServerNameIsHostname(
+ DNSServerRef me,
+ const uint8_t * inName,
+ uint32_t * outAliasCount,
+ uint32_t inAliasTTLs[ kMaxAliasTTLCount ],
+ size_t * outAliasTTLCount,
+ unsigned int * outCount,
+ unsigned int * outRandCount,
+ uint32_t * outTTL,
+ Boolean * outHasA,
+ Boolean * outHasAAAA,
+ Boolean * outHasSOA )
+{
+ OSStatus err;
+ const uint8_t * label;
+ const uint8_t * nextLabel;
+ uint32_t aliasCount = 0; // Arg from Alias label. Valid values are in [2, 2^31 - 1].
+ unsigned int count = 0; // First arg from Count label. Valid values are in [1, 255].
+ unsigned int randCount = 0; // Second arg from Count label. Valid values are in [count, 255].
+ int32_t ttl = -1; // Arg from TTL label. Valid values are in [0, 2^31 - 1].
+ size_t aliasTTLCount = 0; // Count of TTL args from Alias-TTL label.
+ int hasTagLabel = false;
+ int hasIPv4Label = false;
+ int hasIPv6Label = false;
+ int isNameValid = false;
+
+ for( label = inName; label[ 0 ]; label = nextLabel )
+ {
+ uint32_t arg;
+
+ nextLabel = &label[ 1 + label[ 0 ] ];
+
+ // Check if the first label is a valid alias TTL sequence label.
+
+ if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_AliasTTL ) == 0 ) )
+ {
+ const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_AliasTTL ) ];
+ const char * const end = (const char *) nextLabel;
+ const char * next;
+
+ check( label[ 0 ] <= kDomainLabelLengthMax );
+
+ while( ptr < end )
+ {
+ if( *ptr != '-' ) break;
+ ++ptr;
+ err = DecimalTextToUInt32( ptr, end, &arg, &next );
+ if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
+ inAliasTTLs[ aliasTTLCount++ ] = arg;
+ ptr = next;
+ }
+ if( ( aliasTTLCount == 0 ) || ( ptr != end ) ) break;
+ }
+
+ // Check if the first label is a valid alias label.
+
+ else if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Alias ) == 0 ) )
+ {
+ const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Alias ) ];
+ const char * const end = (const char *) nextLabel;
+
+ if( ptr < end )
+ {
+ if( *ptr++ != '-' ) break;
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ if( err || ( arg < 2 ) || ( arg > INT32_MAX ) ) break; // Alias count must be in [2, 2^31 - 1].
+ aliasCount = arg;
+ if( ptr != end ) break;
+ }
+ else
+ {
+ aliasCount = 1;
+ }
+ }
+
+ // Check if this label is a valid count label.
+
+ else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Count ) == 0 )
+ {
+ const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Count ) ];
+ const char * const end = (const char *) nextLabel;
+
+ if( count > 0 ) break; // Count cannot be specified more than once.
+
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ if( err || ( arg < 1 ) || ( arg > 255 ) ) break; // Count must be in [1, 255].
+ count = (unsigned int) arg;
+
+ if( ptr < end )
+ {
+ if( *ptr++ != '-' ) break;
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ if( err || ( arg < (uint32_t) count ) || ( arg > 255 ) ) break; // Rand count must be in [count, 255].
+ randCount = (unsigned int) arg;
+ if( ptr != end ) break;
+ }
+ }
+
+ // Check if this label is a valid TTL label.
+
+ else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_TTL ) == 0 )
+ {
+ const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_TTL ) ];
+ const char * const end = (const char *) nextLabel;
+
+ if( ttl >= 0 ) break; // TTL cannot be specified more than once.
+
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
+ ttl = (int32_t) arg;
+ if( ptr != end ) break;
+ }
+
+ // Check if this label is a valid IPv4 label.
+
+ else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv4 ) == 0 )
+ {
+ if( hasIPv4Label || hasIPv6Label ) break; // Valid names have at most one IPv4 or IPv6 label.
+ hasIPv4Label = true;
+ }
+
+ // Check if this label is a valid IPv6 label.
+
+ else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv6 ) == 0 )
+ {
+ if( hasIPv4Label || hasIPv6Label ) break; // Valid names have at most one IPv4 or IPv6 label.
+ hasIPv6Label = true;
+ }
+
+ // Check if this label is a valid tag label.
+
+ else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Tag ) == 0 )
+ {
+ hasTagLabel = true;
+ }
+
+ // If this and the remaining labels are equal to "d.test.", then the name exists. Otherwise, this label is invalid.
+ // In both cases, there are no more labels to check.
+
+ else
+ {
+ if( DomainNameEqual( label, me->domain ) ) isNameValid = true;
+ break;
+ }
+ }
+ require_quiet( isNameValid, exit );
+
+ if( outAliasCount ) *outAliasCount = aliasCount;
+ if( outAliasTTLCount ) *outAliasTTLCount = aliasTTLCount;
+ if( outCount ) *outCount = ( count > 0 ) ? count : 1;
+ if( outRandCount ) *outRandCount = randCount;
+ if( outTTL ) *outTTL = ( ttl >= 0 ) ? ( (uint32_t) ttl ) : me->defaultTTL;
+ if( outHasA ) *outHasA = ( hasIPv4Label || !hasIPv6Label ) ? true : false;
+ if( outHasAAAA ) *outHasAAAA = ( hasIPv6Label || !hasIPv4Label ) ? true : false;
+ if( outHasSOA )
+ {
+ *outHasSOA = ( !count && ( ttl < 0 ) && !hasIPv4Label && !hasIPv6Label && !hasTagLabel ) ? true : false;
+ }
+
+exit:
+ return( isNameValid ? true : false );
+}
+
+static Boolean
+ _DNSServerNameIsSRVName(
+ DNSServerRef me,
+ const uint8_t * inName,
+ const uint8_t ** outDomainPtr,
+ size_t * outDomainLen,
+ ParsedSRV inSRVArray[ kMaxParsedSRVCount ],
+ size_t * outSRVCount )
+{
+ OSStatus err;
+ const uint8_t * label;
+ const uint8_t * domainPtr;
+ size_t domainLen;
+ size_t srvCount;
+ uint32_t arg;
+ int isNameValid = false;
+
+ label = inName;
+
+ // Ensure that first label, i.e, the service label, begins with a '_' character.
+
+ require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
+ label = DomainNameGetNextLabel( label );
+
+ // Ensure that the second label, i.e., the proto label, begins with a '_' character (usually _tcp or _udp).
+
+ require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
+ label = DomainNameGetNextLabel( label );
+
+ // Parse the domain name, if any.
+
+ domainPtr = label;
+ while( *label )
+ {
+ if( DomainNameEqual( label, me->domain ) ||
+ ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
+ label = DomainNameGetNextLabel( label );
+ }
+ require_quiet( *label, exit );
+
+ domainLen = (size_t)( label - domainPtr );
+
+ // Parse SRV labels, if any.
+
+ srvCount = 0;
+ while( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 )
+ {
+ const uint8_t * const nextLabel = DomainNameGetNextLabel( label );
+ const char * ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_SRV ) ];
+ const char * const end = (const char *) nextLabel;
+ const uint8_t * target;
+ unsigned int priority, weight, port;
+
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ require_quiet( !err && ( arg <= UINT16_MAX ), exit );
+ priority = (unsigned int) arg;
+
+ require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+ ++ptr;
+
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ require_quiet( !err && ( arg <= UINT16_MAX ), exit );
+ weight = (unsigned int) arg;
+
+ require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+ ++ptr;
+
+ err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+ require_quiet( !err && ( arg <= UINT16_MAX ), exit );
+ port = (unsigned int) arg;
+
+ require_quiet( ptr == end, exit );
+
+ target = nextLabel;
+ for( label = nextLabel; *label; label = DomainNameGetNextLabel( label ) )
+ {
+ if( DomainNameEqual( label, me->domain ) ||
+ ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
+ }
+ require_quiet( *label, exit );
+
+ if( inSRVArray )
+ {
+ inSRVArray[ srvCount ].priority = (uint16_t) priority;
+ inSRVArray[ srvCount ].weight = (uint16_t) weight;
+ inSRVArray[ srvCount ].port = (uint16_t) port;
+ inSRVArray[ srvCount ].targetPtr = target;
+ inSRVArray[ srvCount ].targetLen = (uint16_t)( label - target );
+ }
+ ++srvCount;
+ }
+ require_quiet( DomainNameEqual( label, me->domain ), exit );
+ isNameValid = true;
+
+ if( outDomainPtr ) *outDomainPtr = domainPtr;
+ if( outDomainLen ) *outDomainLen = domainLen;
+ if( outSRVCount ) *outSRVCount = srvCount;
+
+exit:
+ return( isNameValid ? true : false );
+}
+
+//===========================================================================================================================
+// _DNSServerTCPReadHandler
+//===========================================================================================================================
+
+typedef struct
+{
+ DNSServerRef server; // Reference to DNS server object.
+ sockaddr_ip clientAddr; // Client's address.
+ dispatch_source_t readSource; // Dispatch read source for client socket.
+ dispatch_source_t writeSource; // Dispatch write source for client socket.
+ size_t offset; // Offset into receive buffer.
+ void * msgPtr; // Pointer to dynamically allocated message buffer.
+ size_t msgLen; // Length of message buffer.
+ Boolean readSuspended; // True if the read source is currently suspended.
+ Boolean writeSuspended; // True if the write source is currently suspended.
+ Boolean receivedLength; // True if receiving DNS message as opposed to the message length.
+ uint8_t lenBuf[ 2 ]; // Buffer for two-octet message length field.
+ iovec_t iov[ 2 ]; // IO vector for writing response message.
+ iovec_t * iovPtr; // Vector pointer for SocketWriteData().
+ int iovCount; // Vector count for SocketWriteData().
+
+} TCPConnectionContext;
+
+static void TCPConnectionStop( TCPConnectionContext *inContext );
+static void TCPConnectionContextFree( TCPConnectionContext *inContext );
+static void TCPConnectionReadHandler( void *inContext );
+static void TCPConnectionWriteHandler( void *inContext );
+
+#define TCPConnectionForget( X ) ForgetCustomEx( X, TCPConnectionStop, TCPConnectionContextFree )
+
+static void _DNSServerTCPReadHandler( void *inContext )
+{
+ OSStatus err;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ DNSServerRef const me = (DNSServerRef) sockCtx->userContext;
+ TCPConnectionContext * connection;
+ socklen_t clientAddrLen;
+ SocketRef newSock = kInvalidSocketRef;
+ SocketContext * newSockCtx = NULL;
+
+ connection = (TCPConnectionContext *) calloc( 1, sizeof( *connection ) );
+ require_action( connection, exit, err = kNoMemoryErr );
+
+ CFRetain( me );
+ connection->server = me;
+
+ clientAddrLen = (socklen_t) sizeof( connection->clientAddr );
+ newSock = accept( sockCtx->sock, &connection->clientAddr.sa, &clientAddrLen );
+ err = map_socket_creation_errno( newSock );
+ require_noerr( err, exit );
+
+ err = SocketContextCreate( newSock, connection, &newSockCtx );
+ require_noerr( err, exit );
+ newSock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( newSockCtx->sock, me->queue, TCPConnectionReadHandler, SocketContextCancelHandler,
+ newSockCtx, &connection->readSource );
+ require_noerr( err, exit );
+ SocketContextRetain( newSockCtx );
+ dispatch_resume( connection->readSource );
+
+ err = DispatchWriteSourceCreate( newSockCtx->sock, me->queue, TCPConnectionWriteHandler, SocketContextCancelHandler,
+ newSockCtx, &connection->writeSource );
+ require_noerr( err, exit );
+ SocketContextRetain( newSockCtx );
+ connection->writeSuspended = true;
+ connection = NULL;
+
+exit:
+ ForgetSocket( &newSock );
+ SocketContextRelease( newSockCtx );
+ TCPConnectionForget( &connection );
+}
+
+//===========================================================================================================================
+// TCPConnectionStop
+//===========================================================================================================================
+
+static void TCPConnectionStop( TCPConnectionContext *inContext )
+{
+ dispatch_source_forget_ex( &inContext->readSource, &inContext->readSuspended );
+ dispatch_source_forget_ex( &inContext->writeSource, &inContext->writeSuspended );
+}
+
+//===========================================================================================================================
+// TCPConnectionContextFree
+//===========================================================================================================================
+
+static void TCPConnectionContextFree( TCPConnectionContext *inContext )
+{
+ check( !inContext->readSource );
+ check( !inContext->writeSource );
+ ForgetCF( &inContext->server );
+ ForgetMem( &inContext->msgPtr );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// TCPConnectionReadHandler
+//===========================================================================================================================
+
+static void TCPConnectionReadHandler( void *inContext )
+{
+ OSStatus err;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ TCPConnectionContext * connection = (TCPConnectionContext *) sockCtx->userContext;
+ struct timeval now;
+ uint8_t * responsePtr = NULL; // malloc'd
+ size_t responseLen;
+
+ // Receive message length.
+
+ if( !connection->receivedLength )
+ {
+ err = SocketReadData( sockCtx->sock, connection->lenBuf, sizeof( connection->lenBuf ), &connection->offset );
+ if( err == EWOULDBLOCK ) goto exit;
+ require_noerr( err, exit );
+
+ connection->offset = 0;
+ connection->msgLen = ReadBig16( connection->lenBuf );
+ connection->msgPtr = malloc( connection->msgLen );
+ require_action( connection->msgPtr, exit, err = kNoMemoryErr );
+ connection->receivedLength = true;
+ }
+
+ // Receive message.
+
+ err = SocketReadData( sockCtx->sock, connection->msgPtr, connection->msgLen, &connection->offset );
+ if( err == EWOULDBLOCK ) goto exit;
+ require_noerr( err, exit );
+
+ gettimeofday( &now, NULL );
+ dispatch_suspend( connection->readSource );
+ connection->readSuspended = true;
+
+ ds_ulog( kLogLevelInfo, "TCP server received %zu bytes from %##a at %{du:time}.\n",
+ connection->msgLen, &connection->clientAddr, &now );
+
+ if( connection->msgLen < kDNSHeaderLength )
+ {
+ ds_ulog( kLogLevelInfo, "TCP DNS message is too small (%zu < %d).\n", connection->msgLen, kDNSHeaderLength );
+ goto exit;
+ }
+
+ ds_ulog( kLogLevelInfo, "TCP received message:\n\n%1{du:dnsmsg}", connection->msgPtr, connection->msgLen );
+
+ // Create response.
+
+ err = _DNSServerAnswerQueryForTCP( connection->server, connection->msgPtr, connection->msgLen, &responsePtr,
+ &responseLen );
+ require_noerr_quiet( err, exit );
+
+ // Send response.
+
+ ds_ulog( kLogLevelInfo, "TCP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
+
+ free( connection->msgPtr );
+ connection->msgPtr = responsePtr;
+ connection->msgLen = responseLen;
+ responsePtr = NULL;
+
+ check( connection->msgLen <= UINT16_MAX );
+ WriteBig16( connection->lenBuf, connection->msgLen );
+ connection->iov[ 0 ].iov_base = connection->lenBuf;
+ connection->iov[ 0 ].iov_len = sizeof( connection->lenBuf );
+ connection->iov[ 1 ].iov_base = connection->msgPtr;
+ connection->iov[ 1 ].iov_len = connection->msgLen;
+
+ connection->iovPtr = connection->iov;
+ connection->iovCount = 2;
+
+ check( connection->writeSuspended );
+ dispatch_resume( connection->writeSource );
+ connection->writeSuspended = false;
+
+exit:
+ FreeNullSafe( responsePtr );
+ if( err && ( err != EWOULDBLOCK ) ) TCPConnectionForget( &connection );
+}
+
+//===========================================================================================================================
+// TCPConnectionWriteHandler
+//===========================================================================================================================
+
+static void TCPConnectionWriteHandler( void *inContext )
+{
+ OSStatus err;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ TCPConnectionContext * connection = (TCPConnectionContext *) sockCtx->userContext;
+
+ err = SocketWriteData( sockCtx->sock, &connection->iovPtr, &connection->iovCount );
+ if( err == EWOULDBLOCK ) goto exit;
+ check_noerr( err );
+
+ TCPConnectionForget( &connection );
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// MDNSReplierCmd
+//===========================================================================================================================
+
+typedef struct
+{
+ uint8_t * hostname; // Used as the base name for hostnames and service names.
+ uint8_t * serviceLabel; // Label containing the base service name.
+ unsigned int maxInstanceCount; // Maximum number of service instances and hostnames.
+ uint64_t * bitmaps; // Array of 64-bit bitmaps for keeping track of needed responses.
+ size_t bitmapCount; // Number of 64-bit bitmaps.
+ dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
+ dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
+ uint32_t ifIndex; // Index of the interface to run on.
+ unsigned int recordCountA; // Number of A records per hostname.
+ unsigned int recordCountAAAA; // Number of AAAA records per hostname.
+ unsigned int maxDropCount; // If > 0, the drop rates apply to only the first <maxDropCount> responses.
+ double ucastDropRate; // Probability of dropping a unicast response.
+ double mcastDropRate; // Probability of dropping a multicast query or response.
+ uint8_t * dropCounters; // If maxDropCount > 0, array of <maxInstanceCount> response drop counters.
+ Boolean noAdditionals; // True if responses are to not include additional records.
+ Boolean useIPv4; // True if the replier is to use IPv4.
+ Boolean useIPv6; // True if the replier is to use IPv6.
+ uint8_t msgBuf[ kMDNSMessageSizeMax ]; // Buffer for received mDNS message.
+#if( TARGET_OS_DARWIN )
+ dispatch_source_t processMonitor; // Process monitor source for process being followed, if any.
+ pid_t followPID; // PID of process being followed, if any. (If it exits, we exit).
+#endif
+
+} MDNSReplierContext;
+
+typedef struct MRResourceRecord MRResourceRecord;
+struct MRResourceRecord
+{
+ MRResourceRecord * next; // Next item in list.
+ uint8_t * name; // Resource record name.
+ uint16_t type; // Resource record type.
+ uint16_t class; // Resource record class.
+ uint32_t ttl; // Resource record TTL.
+ uint16_t rdlength; // Resource record data length.
+ uint8_t * rdata; // Resource record data.
+ const uint8_t * target; // For SRV records, pointer to target in RDATA.
+};
+
+typedef struct MRNameOffsetItem MRNameOffsetItem;
+struct MRNameOffsetItem
+{
+ MRNameOffsetItem * next; // Next item in list.
+ uint16_t offset; // Offset of domain name in response message.
+ uint8_t name[ 1 ]; // Variable-length array for domain name.
+};
+
+#if( TARGET_OS_DARWIN )
+static void _MDNSReplierFollowedProcessHandler( void *inContext );
+#endif
+static void _MDNSReplierReadHandler( void *inContext );
+static OSStatus
+ _MDNSReplierAnswerQuery(
+ MDNSReplierContext * inContext,
+ const uint8_t * inQueryPtr,
+ size_t inQueryLen,
+ sockaddr_ip * inSender,
+ SocketRef inSock,
+ unsigned int inIndex );
+static OSStatus
+ _MDNSReplierAnswerListAdd(
+ MDNSReplierContext * inContext,
+ MRResourceRecord ** inAnswerList,
+ unsigned int inIndex,
+ const uint8_t * inName,
+ unsigned int inType,
+ unsigned int inClass );
+static void
+ _MDNSReplierAnswerListRemovePTR(
+ MRResourceRecord ** inAnswerListPtr,
+ const uint8_t * inName,
+ const uint8_t * inRData );
+static OSStatus
+ _MDNSReplierSendOrDropResponse(
+ MDNSReplierContext * inContext,
+ MRResourceRecord * inAnswerList,
+ sockaddr_ip * inQuerier,
+ SocketRef inSock,
+ unsigned int inIndex,
+ Boolean inUnicast );
+static OSStatus
+ _MDNSReplierCreateResponse(
+ MDNSReplierContext * inContext,
+ MRResourceRecord * inAnswerList,
+ unsigned int inIndex,
+ uint8_t ** outResponsePtr,
+ size_t * outResponseLen );
+static OSStatus
+ _MDNSReplierAppendNameToResponse(
+ DataBuffer * inResponse,
+ const uint8_t * inName,
+ MRNameOffsetItem ** inNameOffsetListPtr );
+static Boolean
+ _MDNSReplierServiceTypeMatch(
+ const MDNSReplierContext * inContext,
+ const uint8_t * inName,
+ unsigned int * outTXTSize,
+ unsigned int * outCount );
+static Boolean
+ _MDNSReplierServiceInstanceNameMatch(
+ const MDNSReplierContext * inContext,
+ const uint8_t * inName,
+ unsigned int * outIndex,
+ unsigned int * outTXTSize,
+ unsigned int * outCount );
+static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName );
+static Boolean
+ _MDNSReplierHostnameMatch(
+ const MDNSReplierContext * inContext,
+ const uint8_t * inName,
+ unsigned int * outIndex );
+static OSStatus _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT );
+static OSStatus
+ _MRResourceRecordCreate(
+ uint8_t * inName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ uint16_t inRDLength,
+ uint8_t * inRData,
+ MRResourceRecord ** outRecord );
+static void _MRResourceRecordFree( MRResourceRecord *inRecord );
+static void _MRResourceRecordFreeList( MRResourceRecord *inList );
+static OSStatus _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem );
+static void _MRNameOffsetItemFree( MRNameOffsetItem *inItem );
+static void _MRNameOffsetItemFreeList( MRNameOffsetItem *inList );
+
+ulog_define_ex( kDNSSDUtilIdentifier, MDNSReplier, kLogLevelInfo, kLogFlags_None, "MDNSReplier", NULL );
+#define mr_ulog( LEVEL, ... ) ulog( &log_category_from_name( MDNSReplier ), (LEVEL), __VA_ARGS__ )
+
+static void MDNSReplierCmd( void )
+{
+ OSStatus err;
+ MDNSReplierContext * context;
+ SocketRef sockV4 = kInvalidSocketRef;
+ SocketRef sockV6 = kInvalidSocketRef;
+ const char * ifname;
+ size_t len;
+ uint8_t name[ 1 + kDomainLabelLengthMax + 1 ];
+ char ifnameBuf[ IF_NAMESIZE + 1 ];
+
+ err = CheckIntegerArgument( gMDNSReplier_MaxInstanceCount, "max instance count", 1, UINT16_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSReplier_RecordCountA, "A record count", 0, 255 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSReplier_RecordCountAAAA, "AAAA record count", 0, 255 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckDoubleArgument( gMDNSReplier_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckDoubleArgument( gMDNSReplier_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSReplier_MaxDropCount, "drop count", 0, 255 );
+ require_noerr_quiet( err, exit );
+
+ if( gMDNSReplier_Foreground )
+ {
+ LogControl( "MDNSReplier:output=file;stdout,MDNSReplier:flags=time;prefix" );
+ }
+
+ context = (MDNSReplierContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->maxInstanceCount = (unsigned int) gMDNSReplier_MaxInstanceCount;
+ context->recordCountA = (unsigned int) gMDNSReplier_RecordCountA;
+ context->recordCountAAAA = (unsigned int) gMDNSReplier_RecordCountAAAA;
+ context->maxDropCount = (unsigned int) gMDNSReplier_MaxDropCount;
+ context->ucastDropRate = gMDNSReplier_UnicastDropRate;
+ context->mcastDropRate = gMDNSReplier_MulticastDropRate;
+ context->noAdditionals = gMDNSReplier_NoAdditionals ? true : false;
+ context->useIPv4 = ( gMDNSReplier_UseIPv4 || !gMDNSReplier_UseIPv6 ) ? true : false;
+ context->useIPv6 = ( gMDNSReplier_UseIPv6 || !gMDNSReplier_UseIPv4 ) ? true : false;
+ context->bitmapCount = ( context->maxInstanceCount + 63 ) / 64;
+
+#if( TARGET_OS_DARWIN )
+ if( gMDNSReplier_FollowPID )
+ {
+ context->followPID = _StringToPID( gMDNSReplier_FollowPID, &err );
+ if( err || ( context->followPID < 0 ) )
+ {
+ FPrintF( stderr, "error: Invalid follow PID: %s\n", gMDNSReplier_FollowPID );
+ goto exit;
+ }
+
+ err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
+ _MDNSReplierFollowedProcessHandler, NULL, context, &context->processMonitor );
+ require_noerr( err, exit );
+ dispatch_resume( context->processMonitor );
+ }
+ else
+ {
+ context->followPID = -1;
+ }
+#endif
+
+ if( context->maxDropCount > 0 )
+ {
+ context->dropCounters = (uint8_t *) calloc( context->maxInstanceCount, sizeof( *context->dropCounters ) );
+ require_action( context->dropCounters, exit, err = kNoMemoryErr );
+ }
+
+ context->bitmaps = (uint64_t *) calloc( context->bitmapCount, sizeof( *context->bitmaps ) );
+ require_action( context->bitmaps, exit, err = kNoMemoryErr );
+
+ // Create the base hostname label.
+
+ len = strlen( gMDNSReplier_Hostname );
+ if( context->maxInstanceCount > 1 )
+ {
+ unsigned int maxInstanceCount, digitCount;
+
+ // When there's more than one instance, extra bytes are needed to append " (<instance index>)" or
+ // "-<instance index>" to the base hostname.
+
+ maxInstanceCount = context->maxInstanceCount;
+ for( digitCount = 0; maxInstanceCount > 0; ++digitCount ) maxInstanceCount /= 10;
+ len += ( 3 + digitCount );
+ }
+
+ if( len <= kDomainLabelLengthMax )
+ {
+ uint8_t * dst = &name[ 1 ];
+ uint8_t * lim = &name[ countof( name ) ];
+
+ SNPrintF_Add( (char **) &dst, (char *) lim, "%s", gMDNSReplier_Hostname );
+ name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
+
+ err = DomainNameDupLower( name, &context->hostname, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ FPrintF( stderr, "error: Base name \"%s\" is too long for max instance count of %u.\n",
+ gMDNSReplier_Hostname, context->maxInstanceCount );
+ goto exit;
+ }
+
+ // Create the service label.
+
+ len = strlen( gMDNSReplier_ServiceTypeTag ) + 3; // We need three extra bytes for the service type prefix "_t-".
+ if( len <= kDomainLabelLengthMax )
+ {
+ uint8_t * dst = &name[ 1 ];
+ uint8_t * lim = &name[ countof( name ) ];
+
+ SNPrintF_Add( (char **) &dst, (char *) lim, "_t-%s", gMDNSReplier_ServiceTypeTag );
+ name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
+
+ err = DomainNameDupLower( name, &context->serviceLabel, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ FPrintF( stderr, "error: Service type tag is too long.\n" );
+ goto exit;
+ }
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+
+ ifname = if_indextoname( context->ifIndex, ifnameBuf );
+ require_action( ifname, exit, err = kNameErr );
+
+ // Set up IPv4 socket.
+
+ if( context->useIPv4 )
+ {
+ err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV4 );
+ require_noerr( err, exit );
+ }
+
+ // Set up IPv6 socket.
+
+ if( context->useIPv6 )
+ {
+ err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV6 );
+ require_noerr( err, exit );
+ }
+
+ // Create dispatch read sources for socket(s).
+
+ if( IsValidSocket( sockV4 ) )
+ {
+ SocketContext * sockCtx;
+
+ err = SocketContextCreate( sockV4, context, &sockCtx );
+ require_noerr( err, exit );
+ sockV4 = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSourceV4 );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSourceV4 );
+ }
+
+ if( IsValidSocket( sockV6 ) )
+ {
+ SocketContext * sockCtx;
+
+ err = SocketContextCreate( sockV6, context, &sockCtx );
+ require_noerr( err, exit );
+ sockV6 = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSourceV6 );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSourceV6 );
+ }
+
+ dispatch_main();
+
+exit:
+ ForgetSocket( &sockV4 );
+ ForgetSocket( &sockV6 );
+ exit( 1 );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// _MDNSReplierFollowedProcessHandler
+//===========================================================================================================================
+
+static void _MDNSReplierFollowedProcessHandler( void *inContext )
+{
+ MDNSReplierContext * const context = (MDNSReplierContext *) inContext;
+
+ if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT )
+ {
+ mr_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited.\n", (int64_t) context->followPID );
+ exit( 0 );
+ }
+}
+#endif
+
+//===========================================================================================================================
+// _MDNSReplierReadHandler
+//===========================================================================================================================
+
+#define ShouldDrop( P ) ( ( (P) > 0.0 ) && ( ( (P) >= 1.0 ) || RandomlyTrue( P ) ) )
+
+static void _MDNSReplierReadHandler( void *inContext )
+{
+ OSStatus err;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ MDNSReplierContext * const context = (MDNSReplierContext *) sockCtx->userContext;
+ size_t msgLen;
+ sockaddr_ip sender;
+ const DNSHeader * hdr;
+ unsigned int flags, questionCount, i, j;
+ const uint8_t * ptr;
+ int drop, isMetaQuery;
+
+ err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &sender, sizeof( sender ),
+ NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ if( msgLen < kDNSHeaderLength )
+ {
+ mr_ulog( kLogLevelInfo, "Message is too small (%zu < %d).\n", msgLen, kDNSHeaderLength );
+ goto exit;
+ }
+
+ // Perform header field checks.
+ // The message ID and most flag bits are silently ignored (see <https://tools.ietf.org/html/rfc6762#section-18>).
+
+ hdr = (DNSHeader *) context->msgBuf;
+ flags = DNSHeaderGetFlags( hdr );
+ require_quiet( ( flags & kDNSHeaderFlag_Response ) == 0, exit ); // Reject responses.
+ require_quiet( DNSFlagsGetOpCode( flags ) == kDNSOpCode_Query, exit ); // Reject opcodes other than standard query.
+ require_quiet( DNSFlagsGetRCode( flags ) == kDNSRCode_NoError, exit ); // Reject non-zero rcodes.
+
+ drop = ( !context->maxDropCount && ShouldDrop( context->mcastDropRate ) ) ? true : false;
+
+ mr_ulog( kLogLevelInfo, "Received %zu byte message from %##a%?s:\n\n%#1{du:dnsmsg}",
+ msgLen, &sender, drop, " (dropping)", context->msgBuf, msgLen );
+
+ // Based on the QNAMEs in the query message, determine from which sets of records we may possibly need answers.
+
+ questionCount = DNSHeaderGetQuestionCount( hdr );
+ require_quiet( questionCount > 0, exit );
+
+ memset( context->bitmaps, 0, context->bitmapCount * sizeof_element( context->bitmaps ) );
+
+ isMetaQuery = false;
+ ptr = (const uint8_t *) &hdr[ 1 ];
+ for( i = 0; i < questionCount; ++i )
+ {
+ unsigned int count, index;
+ uint16_t qtype, qclass;
+ uint8_t qname[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractQuestion( context->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
+ require_noerr_quiet( err, exit );
+
+ if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
+
+ if( _MDNSReplierHostnameMatch( context, qname, &index ) ||
+ _MDNSReplierServiceInstanceNameMatch( context, qname, &index, NULL, NULL ) )
+ {
+ if( ( index >= 1 ) && ( index <= context->maxInstanceCount ) )
+ {
+ context->bitmaps[ ( index - 1 ) / 64 ] |= ( UINT64_C( 1 ) << ( ( index - 1 ) % 64 ) );
+ }
+ }
+ else if( _MDNSReplierServiceTypeMatch( context, qname, NULL, &count ) )
+ {
+ if( ( count >= 1 ) && ( count <= context->maxInstanceCount ) )
+ {
+ for( j = 0; j < (unsigned int) context->bitmapCount; ++j )
+ {
+ if( count < 64 )
+ {
+ context->bitmaps[ j ] |= ( ( UINT64_C( 1 ) << count ) - 1 );
+ break;
+ }
+ else
+ {
+ context->bitmaps[ j ] = ~UINT64_C( 0 );
+ count -= 64;
+ }
+ }
+ }
+ }
+ else if( _MDNSReplierAboutRecordNameMatch( context, qname ) )
+ {
+ isMetaQuery = true;
+ }
+ }
+
+ // Attempt to answer the query message using selected record sets.
+
+ if( isMetaQuery )
+ {
+ err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock, 0 );
+ check_noerr( err );
+ }
+ if( drop ) goto exit;
+
+ for( i = 0; i < context->bitmapCount; ++i )
+ {
+ for( j = 0; ( context->bitmaps[ i ] != 0 ) && ( j < 64 ); ++j )
+ {
+ const uint64_t bitmask = UINT64_C( 1 ) << j;
+
+ if( context->bitmaps[ i ] & bitmask )
+ {
+ context->bitmaps[ i ] &= ~bitmask;
+
+ err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock,
+ ( i * 64 ) + j + 1 );
+ check_noerr( err );
+ }
+ }
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _MDNSReplierAnswerQuery
+//===========================================================================================================================
+
+static OSStatus
+ _MDNSReplierAnswerQuery(
+ MDNSReplierContext * inContext,
+ const uint8_t * inQueryPtr,
+ size_t inQueryLen,
+ sockaddr_ip * inSender,
+ SocketRef inSock,
+ unsigned int inIndex )
+{
+ OSStatus err;
+ const DNSHeader * hdr;
+ const uint8_t * ptr;
+ unsigned int questionCount, answerCount, i;
+ MRResourceRecord * ucastAnswerList = NULL;
+ MRResourceRecord * mcastAnswerList = NULL;
+
+ require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
+
+ // Get answers for questions.
+
+ check( inQueryLen >= kDNSHeaderLength );
+ hdr = (const DNSHeader *) inQueryPtr;
+ questionCount = DNSHeaderGetQuestionCount( hdr );
+
+ ptr = (const uint8_t *) &hdr[ 1 ];
+ for( i = 0; i < questionCount; ++i )
+ {
+ MRResourceRecord ** answerListPtr;
+ uint16_t qtype, qclass;
+ uint8_t qname[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractQuestion( inQueryPtr, inQueryLen, ptr, qname, &qtype, &qclass, &ptr );
+ require_noerr_quiet( err, exit );
+
+ if( qclass & kQClassUnicastResponseBit )
+ {
+ qclass &= ~kQClassUnicastResponseBit;
+ answerListPtr = &ucastAnswerList;
+ }
+ else
+ {
+ answerListPtr = &mcastAnswerList;
+ }
+
+ err = _MDNSReplierAnswerListAdd( inContext, answerListPtr, inIndex, qname, qtype, qclass );
+ require_noerr( err, exit );
+ }
+ require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
+
+ // Suppress known answers.
+ // Records in the Answer section of the query message are known answers, so remove them from the answer lists.
+ // See <https://tools.ietf.org/html/rfc6762#section-7.1>.
+
+ answerCount = DNSHeaderGetAnswerCount( hdr );
+ for( i = 0; i < answerCount; ++i )
+ {
+ const uint8_t * rdataPtr;
+ const uint8_t * recordPtr;
+ uint16_t type, class;
+ uint8_t name[ kDomainNameLengthMax ];
+ uint8_t instance[ kDomainNameLengthMax ];
+
+ recordPtr = ptr;
+ err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, ptr, NULL, &type, &class, NULL, NULL, NULL, &ptr );
+ require_noerr_quiet( err, exit );
+
+ if( ( type != kDNSServiceType_PTR ) || ( class != kDNSServiceClass_IN ) ) continue;
+
+ err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, recordPtr, name, NULL, NULL, NULL, &rdataPtr, NULL, NULL );
+ require_noerr( err, exit );
+
+ err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, rdataPtr, instance, NULL );
+ require_noerr_quiet( err, exit );
+
+ if( ucastAnswerList ) _MDNSReplierAnswerListRemovePTR( &ucastAnswerList, name, instance );
+ if( mcastAnswerList ) _MDNSReplierAnswerListRemovePTR( &mcastAnswerList, name, instance );
+ }
+ require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
+
+ // Send or drop responses.
+
+ if( ucastAnswerList )
+ {
+ err = _MDNSReplierSendOrDropResponse( inContext, ucastAnswerList, inSender, inSock, inIndex, true );
+ require_noerr( err, exit );
+ }
+
+ if( mcastAnswerList )
+ {
+ err = _MDNSReplierSendOrDropResponse( inContext, mcastAnswerList, inSender, inSock, inIndex, false );
+ require_noerr( err, exit );
+ }
+ err = kNoErr;
+
+exit:
+ _MRResourceRecordFreeList( ucastAnswerList );
+ _MRResourceRecordFreeList( mcastAnswerList );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSReplierAnswerListAdd
+//===========================================================================================================================
+
+static OSStatus
+ _MDNSReplierAnswerListAdd(
+ MDNSReplierContext * inContext,
+ MRResourceRecord ** inAnswerList,
+ unsigned int inIndex,
+ const uint8_t * inName,
+ unsigned int inType,
+ unsigned int inClass )
+{
+ OSStatus err;
+ uint8_t * recordName = NULL;
+ uint8_t * rdataPtr = NULL;
+ size_t rdataLen;
+ MRResourceRecord * answer;
+ MRResourceRecord ** answerPtr;
+ const uint8_t * const hostname = inContext->hostname;
+ unsigned int i;
+ uint32_t index;
+ unsigned int count, txtSize;
+
+ require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
+ require_action_quiet( inClass == kDNSServiceClass_IN, exit, err = kNoErr );
+
+ for( answerPtr = inAnswerList; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
+ {
+ if( ( answer->type == inType ) && DomainNameEqual( answer->name, inName ) )
+ {
+ err = kNoErr;
+ goto exit;
+ }
+ }
+
+ // Index 0 is reserved for answering queries about the mdnsreplier, while all other index values up to the maximum
+ // instance count are for answering queries about service instances.
+
+ if( inIndex == 0 )
+ {
+ if( _MDNSReplierAboutRecordNameMatch( inContext, inName ) )
+ {
+ int listHasTXT = false;
+
+ if( inType == kDNSServiceType_ANY )
+ {
+ for( answer = *inAnswerList; answer; answer = answer->next )
+ {
+ if( ( answer->type == kDNSServiceType_TXT ) && DomainNameEqual( answer->name, inName ) )
+ {
+ listHasTXT = true;
+ break;
+ }
+ }
+ }
+
+ if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ err = CreateTXTRecordDataFromString( "ready=yes", ',', &rdataPtr, &rdataLen );
+ require_noerr( err, exit );
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ }
+ else if( inType == kDNSServiceType_NSEC )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_TXT );
+ require_noerr( err, exit );
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ }
+ }
+ }
+ else if( _MDNSReplierHostnameMatch( inContext, inName, &index ) && ( index == inIndex ) )
+ {
+ int listHasA = false;
+ int listHasAAAA = false;
+
+ if( inType == kDNSServiceType_ANY )
+ {
+ for( answer = *inAnswerList; answer; answer = answer->next )
+ {
+ if( answer->type == kDNSServiceType_A )
+ {
+ if( !listHasA && DomainNameEqual( answer->name, inName ) ) listHasA = true;
+ }
+ else if( answer->type == kDNSServiceType_AAAA )
+ {
+ if( !listHasAAAA && DomainNameEqual( answer->name, inName ) ) listHasAAAA = true;
+ }
+ if( listHasA && listHasAAAA ) break;
+ }
+ }
+
+ if( ( inType == kDNSServiceType_A ) || ( ( inType == kDNSServiceType_ANY ) && !listHasA ) )
+ {
+ for( i = 1; i <= inContext->recordCountA; ++i )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ rdataLen = 4;
+ rdataPtr = (uint8_t *) malloc( rdataLen );
+ require_action( rdataPtr, exit, err = kNoMemoryErr );
+
+ rdataPtr[ 0 ] = 0;
+ WriteBig16( &rdataPtr[ 1 ], inIndex );
+ rdataPtr[ 3 ] = (uint8_t) i;
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_A, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ answerPtr = &answer->next;
+ }
+ }
+
+ if( ( inType == kDNSServiceType_AAAA ) || ( ( inType == kDNSServiceType_ANY ) && !listHasAAAA ) )
+ {
+ for( i = 1; i <= inContext->recordCountAAAA; ++i )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ rdataLen = 16;
+ rdataPtr = (uint8_t *) _memdup( kMDNSReplierBaseAddrV6, rdataLen );
+ require_action( rdataPtr, exit, err = kNoMemoryErr );
+
+ WriteBig16( &rdataPtr[ 12 ], inIndex );
+ rdataPtr[ 15 ] = (uint8_t) i;
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_AAAA, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ answerPtr = &answer->next;
+ }
+ }
+ else if( inType == kDNSServiceType_NSEC )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ if( ( inContext->recordCountA > 0 ) && ( inContext->recordCountAAAA > 0 ) )
+ {
+ err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_A, kDNSServiceType_AAAA );
+ require_noerr( err, exit );
+ }
+ else if( inContext->recordCountA > 0 )
+ {
+ err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_A );
+ require_noerr( err, exit );
+ }
+ else if( inContext->recordCountAAAA > 0 )
+ {
+ err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_AAAA );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 0 );
+ require_noerr( err, exit );
+ }
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ }
+ }
+ else if( _MDNSReplierServiceTypeMatch( inContext, inName, NULL, &count ) && ( count >= inIndex ) )
+ {
+ int listHasPTR = false;
+
+ if( inType == kDNSServiceType_ANY )
+ {
+ for( answer = *inAnswerList; answer; answer = answer->next )
+ {
+ if( ( answer->type == kDNSServiceType_PTR ) && DomainNameEqual( answer->name, inName ) )
+ {
+ listHasPTR = true;
+ break;
+ }
+ }
+ }
+
+ if( ( inType == kDNSServiceType_PTR ) || ( ( inType == kDNSServiceType_ANY ) && !listHasPTR ) )
+ {
+ size_t recordNameLen;
+ uint8_t * ptr;
+ uint8_t * lim;
+
+ err = DomainNameDupLower( inName, &recordName, &recordNameLen );
+ require_noerr( err, exit );
+
+ rdataLen = 1 + hostname[ 0 ] + 10 + recordNameLen;
+ rdataPtr = (uint8_t *) malloc( rdataLen );
+ require_action( rdataPtr, exit, err = kNoMemoryErr );
+
+ lim = &rdataPtr[ rdataLen ];
+
+ ptr = &rdataPtr[ 1 ];
+ memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
+ ptr += hostname[ 0 ];
+ if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, " (%u)", inIndex );
+ rdataPtr[ 0 ] = (uint8_t)( ptr - &rdataPtr[ 1 ] );
+
+ check( (size_t)( lim - ptr ) >= recordNameLen );
+ memcpy( ptr, recordName, recordNameLen );
+ ptr += recordNameLen;
+
+ rdataLen = (size_t)( ptr - rdataPtr );
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_PTR, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ }
+ }
+ else if( _MDNSReplierServiceInstanceNameMatch( inContext, inName, &index, &txtSize, &count ) &&
+ ( index == inIndex ) && ( count >= inIndex ) )
+ {
+ int listHasSRV = false;
+ int listHasTXT = false;
+
+ if( inType == kDNSServiceType_ANY )
+ {
+ for( answer = *inAnswerList; answer; answer = answer->next )
+ {
+ if( answer->type == kDNSServiceType_SRV )
+ {
+ if( !listHasSRV && DomainNameEqual( answer->name, inName ) ) listHasSRV = true;
+ }
+ else if( answer->type == kDNSServiceType_TXT )
+ {
+ if( !listHasTXT && DomainNameEqual( answer->name, inName ) ) listHasTXT = true;
+ }
+ if( listHasSRV && listHasTXT ) break;
+ }
+ }
+
+ if( ( inType == kDNSServiceType_SRV ) || ( ( inType == kDNSServiceType_ANY ) && !listHasSRV ) )
+ {
+ dns_fixed_fields_srv * fields;
+ uint8_t * ptr;
+ uint8_t * lim;
+ uint8_t * targetPtr;
+
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ rdataLen = sizeof( dns_fixed_fields_srv ) + 1 + hostname[ 0 ] + 10 + kLocalNameLen;
+ rdataPtr = (uint8_t *) malloc( rdataLen );
+ require_action( rdataPtr, exit, err = kNoMemoryErr );
+
+ lim = &rdataPtr[ rdataLen ];
+
+ fields = (dns_fixed_fields_srv *) rdataPtr;
+ dns_fixed_fields_srv_init( fields, 0, 0, (uint16_t)( kMDNSReplierPortBase + txtSize ) );
+
+ targetPtr = (uint8_t *) &fields[ 1 ];
+
+ ptr = &targetPtr[ 1 ];
+ memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
+ ptr += hostname[ 0 ];
+ if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, "-%u", inIndex );
+ targetPtr[ 0 ] = (uint8_t)( ptr - &targetPtr[ 1 ] );
+
+ check( (size_t)( lim - ptr ) >= kLocalNameLen );
+ memcpy( ptr, kLocalName, kLocalNameLen );
+ ptr += kLocalNameLen;
+
+ rdataLen = (size_t)( ptr - rdataPtr );
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_SRV, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ answerPtr = &answer->next;
+ }
+
+ if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ rdataLen = txtSize;
+ err = _MDNSReplierCreateTXTRecord( inName, rdataLen, &rdataPtr );
+ require_noerr( err, exit );
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ }
+ else if( inType == kDNSServiceType_NSEC )
+ {
+ err = DomainNameDupLower( inName, &recordName, NULL );
+ require_noerr( err, exit );
+
+ err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_TXT, kDNSServiceType_SRV );
+ require_noerr( err, exit );
+
+ err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+ (uint16_t) rdataLen, rdataPtr, &answer );
+ require_noerr( err, exit );
+ recordName = NULL;
+ rdataPtr = NULL;
+
+ *answerPtr = answer;
+ }
+ }
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( recordName );
+ FreeNullSafe( rdataPtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSReplierAnswerListRemovePTR
+//===========================================================================================================================
+
+static void
+ _MDNSReplierAnswerListRemovePTR(
+ MRResourceRecord ** inAnswerListPtr,
+ const uint8_t * inName,
+ const uint8_t * inRData )
+{
+ MRResourceRecord * answer;
+ MRResourceRecord ** answerPtr;
+
+ for( answerPtr = inAnswerListPtr; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
+ {
+ if( ( answer->type == kDNSServiceType_PTR ) && ( answer->class == kDNSServiceClass_IN ) &&
+ DomainNameEqual( answer->name, inName ) && DomainNameEqual( answer->rdata, inRData ) ) break;
+ }
+ if( answer )
+ {
+ *answerPtr = answer->next;
+ _MRResourceRecordFree( answer );
+ }
+}
+
+//===========================================================================================================================
+// _MDNSReplierSendOrDropResponse
+//===========================================================================================================================
+
+static OSStatus
+ _MDNSReplierSendOrDropResponse(
+ MDNSReplierContext * inContext,
+ MRResourceRecord * inAnswerList,
+ sockaddr_ip * inQuerier,
+ SocketRef inSock,
+ unsigned int inIndex,
+ Boolean inUnicast )
+{
+ OSStatus err;
+ uint8_t * responsePtr = NULL;
+ size_t responseLen;
+ const struct sockaddr * destAddr;
+ ssize_t n;
+ const double dropRate = inUnicast ? inContext->ucastDropRate : inContext->mcastDropRate;
+ int drop;
+
+ check( inIndex <= inContext->maxInstanceCount );
+
+ // If maxDropCount > 0, then the drop rates apply only to the first maxDropCount responses. Otherwise, all messages are
+ // subject to their respective drop rate. Also, responses to queries about mDNS replier itself (indicated by index 0),
+ // as opposed to those for service instance records, are never dropped.
+
+ drop = false;
+ if( inIndex > 0 )
+ {
+ if( inContext->maxDropCount > 0 )
+ {
+ uint8_t * const dropCount = &inContext->dropCounters[ inIndex - 1 ];
+
+ if( *dropCount < inContext->maxDropCount )
+ {
+ if( ShouldDrop( dropRate ) ) drop = true;
+ *dropCount += 1;
+ }
+ }
+ else if( ShouldDrop( dropRate ) )
+ {
+ drop = true;
+ }
+ }
+
+ err = _MDNSReplierCreateResponse( inContext, inAnswerList, inIndex, &responsePtr, &responseLen );
+ require_noerr( err, exit );
+
+ if( inUnicast )
+ {
+ destAddr = &inQuerier->sa;
+ }
+ else
+ {
+ destAddr = ( inQuerier->sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
+ }
+
+ mr_ulog( kLogLevelInfo, "%s %zu byte response to %##a:\n\n%#1{du:dnsmsg}",
+ drop ? "Dropping" : "Sending", responseLen, destAddr, responsePtr, responseLen );
+
+ if( !drop )
+ {
+ n = sendto( inSock, (char *) responsePtr, responseLen, 0, destAddr, SockAddrGetSize( destAddr ) );
+ err = map_socket_value_errno( inSock, n == (ssize_t) responseLen, n );
+ require_noerr( err, exit );
+ }
+
+exit:
+ FreeNullSafe( responsePtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSReplierCreateResponse
+//===========================================================================================================================
+
+static OSStatus
+ _MDNSReplierCreateResponse(
+ MDNSReplierContext * inContext,
+ MRResourceRecord * inAnswerList,
+ unsigned int inIndex,
+ uint8_t ** outResponsePtr,
+ size_t * outResponseLen )
+{
+ OSStatus err;
+ DataBuffer responseDB;
+ DNSHeader hdr;
+ MRResourceRecord * answer;
+ uint8_t * responsePtr;
+ size_t responseLen, len;
+ unsigned int answerCount, recordCount;
+ MRNameOffsetItem * nameOffsetList = NULL;
+
+ DataBuffer_Init( &responseDB, NULL, 0, SIZE_MAX );
+
+ // The current answers in the answer list will make up the response's Answer Record Section.
+
+ answerCount = 0;
+ for( answer = inAnswerList; answer; answer = answer->next ) { ++answerCount; }
+
+ // Unless configured not to, add any additional answers to the answer list for the Additional Record Section.
+
+ if( !inContext->noAdditionals )
+ {
+ for( answer = inAnswerList; answer; answer = answer->next )
+ {
+ switch( answer->type )
+ {
+ case kDNSServiceType_PTR:
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_SRV,
+ answer->class );
+ require_noerr( err, exit );
+
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_TXT,
+ answer->class );
+ require_noerr( err, exit );
+ break;
+
+ case kDNSServiceType_SRV:
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_A,
+ answer->class );
+ require_noerr( err, exit );
+
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_AAAA,
+ answer->class );
+ require_noerr( err, exit );
+
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+ answer->class );
+ require_noerr( err, exit );
+ break;
+
+ case kDNSServiceType_TXT:
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+ answer->class );
+ require_noerr( err, exit );
+ break;
+
+ case kDNSServiceType_A:
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_AAAA,
+ answer->class );
+ require_noerr( err, exit );
+
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+ answer->class );
+ require_noerr( err, exit );
+ break;
+
+ case kDNSServiceType_AAAA:
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_A,
+ answer->class );
+ require_noerr( err, exit );
+
+ err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+ answer->class );
+ require_noerr( err, exit );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ // Append a provisional header to the response message.
+
+ memset( &hdr, 0, sizeof( hdr ) );
+ DNSHeaderSetFlags( &hdr, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
+
+ err = DataBuffer_Append( &responseDB, &hdr, sizeof( hdr ) );
+ require_noerr( err, exit );
+
+ // Append answers to response message.
+
+ responseLen = DataBuffer_GetLen( &responseDB );
+ recordCount = 0;
+ for( answer = inAnswerList; answer; answer = answer->next )
+ {
+ dns_fixed_fields_record fields;
+ unsigned int class;
+
+ // Append record NAME.
+
+ err = _MDNSReplierAppendNameToResponse( &responseDB, answer->name, &nameOffsetList );
+ require_noerr( err, exit );
+
+ // Append record TYPE, CLASS, TTL, and provisional RDLENGTH.
+
+ class = answer->class;
+ if( ( answer->type == kDNSServiceType_SRV ) || ( answer->type == kDNSServiceType_TXT ) ||
+ ( answer->type == kDNSServiceType_A ) || ( answer->type == kDNSServiceType_AAAA ) ||
+ ( answer->type == kDNSServiceType_NSEC ) )
+ {
+ class |= kRRClassCacheFlushBit;
+ }
+
+ dns_fixed_fields_record_init( &fields, answer->type, (uint16_t) class, answer->ttl, (uint16_t) answer->rdlength );
+ err = DataBuffer_Append( &responseDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+
+ // Append record RDATA.
+ // The RDATA of PTR, SRV, and NSEC records contain domain names, which are subject to name compression.
+
+ if( ( answer->type == kDNSServiceType_PTR ) || ( answer->type == kDNSServiceType_SRV ) ||
+ ( answer->type == kDNSServiceType_NSEC ) )
+ {
+ size_t rdlength;
+ uint8_t * rdLengthPtr;
+ const size_t rdLengthOffset = DataBuffer_GetLen( &responseDB ) - 2;
+ const size_t rdataOffset = DataBuffer_GetLen( &responseDB );
+
+ if( answer->type == kDNSServiceType_PTR )
+ {
+ err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
+ require_noerr( err, exit );
+ }
+ else if( answer->type == kDNSServiceType_SRV )
+ {
+ require_fatal( answer->target == &answer->rdata[ 6 ], "Bad SRV record target pointer." );
+
+ err = DataBuffer_Append( &responseDB, answer->rdata, (size_t)( answer->target - answer->rdata ) );
+ require_noerr( err, exit );
+
+ err = _MDNSReplierAppendNameToResponse( &responseDB, answer->target, &nameOffsetList );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ const size_t nameLen = DomainNameLength( answer->rdata );
+
+ err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
+ require_noerr( err, exit );
+
+ require_fatal( answer->rdlength > nameLen, "Bad NSEC record data length." );
+
+ err = DataBuffer_Append( &responseDB, &answer->rdata[ nameLen ], answer->rdlength - nameLen );
+ require_noerr( err, exit );
+ }
+
+ // Set the actual RDLENGTH, which may be less than the original due to name compression.
+
+ rdlength = DataBuffer_GetLen( &responseDB ) - rdataOffset;
+ check( rdlength <= UINT16_MAX );
+
+ rdLengthPtr = DataBuffer_GetPtr( &responseDB ) + rdLengthOffset;
+ WriteBig16( rdLengthPtr, rdlength );
+ }
+ else
+ {
+ err = DataBuffer_Append( &responseDB, answer->rdata, answer->rdlength );
+ require_noerr( err, exit );
+ }
+
+ if( DataBuffer_GetLen( &responseDB ) > kMDNSMessageSizeMax ) break;
+ responseLen = DataBuffer_GetLen( &responseDB );
+ ++recordCount;
+ }
+
+ // Set the response header's Answer and Additional record counts.
+ // Note: recordCount may be less than answerCount if including all answerCount records would cause the size of the
+ // response message to exceed the maximum mDNS message size.
+
+ if( recordCount <= answerCount )
+ {
+ DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount );
+ }
+ else
+ {
+ DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), answerCount );
+ DNSHeaderSetAdditionalCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount - answerCount );
+ }
+
+ err = DataBuffer_Detach( &responseDB, &responsePtr, &len );
+ require_noerr( err, exit );
+
+ if( outResponsePtr ) *outResponsePtr = responsePtr;
+ if( outResponseLen ) *outResponseLen = responseLen;
+
+exit:
+ _MRNameOffsetItemFreeList( nameOffsetList );
+ DataBuffer_Free( &responseDB );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSReplierAppendNameToResponse
+//===========================================================================================================================
+
+static OSStatus
+ _MDNSReplierAppendNameToResponse(
+ DataBuffer * inResponse,
+ const uint8_t * inName,
+ MRNameOffsetItem ** inNameOffsetListPtr )
+{
+ OSStatus err;
+ const uint8_t * subname;
+ const uint8_t * limit;
+ size_t nameOffset;
+ MRNameOffsetItem * item;
+ uint8_t compressionPtr[ 2 ];
+
+ nameOffset = DataBuffer_GetLen( inResponse );
+
+ // Find the name's longest subname (more accurately, its longest sub-FQDN) in the name compression list.
+
+ for( subname = inName; subname[ 0 ] != 0; subname += ( 1 + subname[ 0 ] ) )
+ {
+ for( item = *inNameOffsetListPtr; item; item = item->next )
+ {
+ if( DomainNameEqual( item->name, subname ) ) break;
+ }
+
+ // If an item was found for this subname, then append a name compression pointer and we're done. Otherwise, append
+ // the subname's first label.
+
+ if( item )
+ {
+ DNSMessageWriteLabelPointer( compressionPtr, item->offset );
+
+ err = DataBuffer_Append( inResponse, compressionPtr, sizeof( compressionPtr ) );
+ require_noerr( err, exit );
+ break;
+ }
+ else
+ {
+ err = DataBuffer_Append( inResponse, subname, 1 + subname[ 0 ] );
+ require_noerr( err, exit );
+ }
+ }
+
+ // If we made it to the root label, then no subname was able to be compressed. All of the name's labels up to the root
+ // label were appended to the response message, so a root label is needed to terminate the complete name.
+
+ if( subname[ 0 ] == 0 )
+ {
+ err = DataBuffer_Append( inResponse, "", 1 );
+ require_noerr( err, exit );
+ }
+
+ // Add subnames that weren't able to be compressed and their offsets to the name compression list.
+
+ limit = subname;
+ for( subname = inName; subname < limit; subname += ( 1 + subname[ 0 ] ) )
+ {
+ const size_t subnameOffset = nameOffset + (size_t)( subname - inName );
+
+ if( subnameOffset > kDNSCompressionOffsetMax ) break;
+
+ err = _MRNameOffsetItemCreate( subname, (uint16_t) subnameOffset, &item );
+ require_noerr( err, exit );
+
+ item->next = *inNameOffsetListPtr;
+ *inNameOffsetListPtr = item;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSReplierServiceTypeMatch
+//===========================================================================================================================
+
+static Boolean
+ _MDNSReplierServiceTypeMatch(
+ const MDNSReplierContext * inContext,
+ const uint8_t * inName,
+ unsigned int * outTXTSize,
+ unsigned int * outCount )
+{
+ OSStatus err;
+ const char * ptr;
+ const char * end;
+ uint32_t txtSize, count;
+ const uint8_t * const serviceLabel = inContext->serviceLabel;
+ int nameMatches = false;
+
+ require_quiet( inName[ 0 ] >= serviceLabel[ 0 ], exit );
+ if( _memicmp( &inName[ 1 ], &serviceLabel[ 1 ], serviceLabel[ 0 ] ) != 0 ) goto exit;
+
+ ptr = (const char *) &inName[ 1 + serviceLabel[ 0 ] ];
+ end = (const char *) &inName[ 1 + inName[ 0 ] ];
+
+ require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+ ++ptr;
+
+ err = DecimalTextToUInt32( ptr, end, &txtSize, &ptr );
+ require_noerr_quiet( err, exit );
+ require_quiet( txtSize <= UINT16_MAX, exit );
+
+ require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+ ++ptr;
+
+ err = DecimalTextToUInt32( ptr, end, &count, &ptr );
+ require_noerr_quiet( err, exit );
+ require_quiet( count <= UINT16_MAX, exit );
+ require_quiet( ptr == end, exit );
+
+ if( !DomainNameEqual( (const uint8_t *) ptr, (const uint8_t *) "\x04" "_tcp" "\x05" "local" ) ) goto exit;
+ nameMatches = true;
+
+ if( outTXTSize ) *outTXTSize = txtSize;
+ if( outCount ) *outCount = count;
+
+exit:
+ return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+// _MDNSReplierServiceInstanceNameMatch
+//===========================================================================================================================
+
+static Boolean
+ _MDNSReplierServiceInstanceNameMatch(
+ const MDNSReplierContext * inContext,
+ const uint8_t * inName,
+ unsigned int * outIndex,
+ unsigned int * outTXTSize,
+ unsigned int * outCount )
+{
+ OSStatus err;
+ const uint8_t * ptr;
+ const uint8_t * end;
+ uint32_t index;
+ unsigned int txtSize, count;
+ const uint8_t * const hostname = inContext->hostname;
+ int nameMatches = false;
+
+ require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
+ if( _memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
+
+ ptr = &inName[ 1 + hostname[ 0 ] ];
+ end = &inName[ 1 + inName[ 0 ] ];
+ if( ptr < end )
+ {
+ require_quiet( ( end - ptr ) >= 2, exit );
+ require_quiet( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ), exit );
+ ptr += 2;
+
+ err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
+ require_noerr_quiet( err, exit );
+ require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
+
+ require_quiet( ( ( end - ptr ) == 1 ) && ( *ptr == ')' ), exit );
+ ++ptr;
+ }
+ else
+ {
+ index = 1;
+ }
+
+ if( !_MDNSReplierServiceTypeMatch( inContext, ptr, &txtSize, &count ) ) goto exit;
+ nameMatches = true;
+
+ if( outIndex ) *outIndex = index;
+ if( outTXTSize ) *outTXTSize = txtSize;
+ if( outCount ) *outCount = count;
+
+exit:
+ return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+// _MDNSReplierAboutRecordNameMatch
+//===========================================================================================================================
+
+#define _MemIEqual( PTR1, LEN1, PTR2, LEN2 ) \
+ ( ( ( LEN1 ) == ( LEN2 ) ) && ( _memicmp( ( PTR1 ), ( PTR2 ), ( LEN1 ) ) == 0 ) )
+
+static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName )
+{
+ const uint8_t * subname;
+ const uint8_t * const hostname = inContext->hostname;
+ int nameMatches = false;
+
+ if( strnicmpx( &inName[ 1 ], inName[ 0 ], "about" ) != 0 ) goto exit;
+ subname = DomainNameGetNextLabel( inName );
+
+ if( !_MemIEqual( &subname[ 1 ], subname[ 0 ], &hostname[ 1 ], hostname[ 0 ] ) ) goto exit;
+ subname = DomainNameGetNextLabel( subname );
+
+ if( !DomainNameEqual( subname, kLocalName ) ) goto exit;
+ nameMatches = true;
+
+exit:
+ return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+// _MDNSReplierHostnameMatch
+//===========================================================================================================================
+
+static Boolean
+ _MDNSReplierHostnameMatch(
+ const MDNSReplierContext * inContext,
+ const uint8_t * inName,
+ unsigned int * outIndex )
+{
+ OSStatus err;
+ const uint8_t * ptr;
+ const uint8_t * end;
+ uint32_t index;
+ const uint8_t * const hostname = inContext->hostname;
+ int nameMatches = false;
+
+ require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
+ if( _memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
+
+ ptr = &inName[ 1 + hostname[ 0 ] ];
+ end = &inName[ 1 + inName[ 0 ] ];
+ if( ptr < end )
+ {
+ require_quiet( *ptr == '-', exit );
+ ++ptr;
+
+ err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
+ require_noerr_quiet( err, exit );
+ require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
+ require_quiet( ptr == end, exit );
+ }
+ else
+ {
+ index = 1;
+ }
+
+ if( !DomainNameEqual( ptr, kLocalName ) ) goto exit;
+ nameMatches = true;
+
+ if( outIndex ) *outIndex = index;
+
+exit:
+ return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+// _MDNSReplierCreateTXTRecord
+//===========================================================================================================================
+
+static OSStatus _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT )
+{
+ OSStatus err;
+ uint8_t * txt;
+ uint8_t * ptr;
+ size_t i, wholeCount, remCount;
+ uint32_t hash;
+ int n;
+ uint8_t txtStr[ 16 ];
+
+ require_action_quiet( inSize > 0, exit, err = kSizeErr );
+
+ txt = (uint8_t *) malloc( inSize );
+ require_action( txt, exit, err = kNoMemoryErr );
+
+ hash = _FNV1( inRecordName, DomainNameLength( inRecordName ) );
+
+ txtStr[ 0 ] = 15;
+ n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
+ check( n == 15 );
+
+ ptr = txt;
+ wholeCount = inSize / 16;
+ for( i = 0; i < wholeCount; ++i )
+ {
+ memcpy( ptr, txtStr, 16 );
+ ptr += 16;
+ }
+
+ remCount = inSize % 16;
+ if( remCount > 0 )
+ {
+ txtStr[ 0 ] = (uint8_t)( remCount - 1 );
+ memcpy( ptr, txtStr, remCount );
+ ptr += remCount;
+ }
+ check( ptr == &txt[ inSize ] );
+
+ *outTXT = txt;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _MRResourceRecordCreate
+//===========================================================================================================================
+
+static OSStatus
+ _MRResourceRecordCreate(
+ uint8_t * inName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ uint16_t inRDLength,
+ uint8_t * inRData,
+ MRResourceRecord ** outRecord )
+{
+ OSStatus err;
+ MRResourceRecord * obj;
+
+ obj = (MRResourceRecord *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = inName;
+ obj->type = inType;
+ obj->class = inClass;
+ obj->ttl = inTTL;
+ obj->rdlength = inRDLength;
+ obj->rdata = inRData;
+
+ if( inType == kDNSServiceType_SRV )
+ {
+ require_action_quiet( obj->rdlength > sizeof( dns_fixed_fields_srv ), exit, err = kMalformedErr );
+ obj->target = obj->rdata + sizeof( dns_fixed_fields_srv );
+ }
+
+ *outRecord = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MRResourceRecordFree
+//===========================================================================================================================
+
+static void _MRResourceRecordFree( MRResourceRecord *inRecord )
+{
+ ForgetMem( &inRecord->name );
+ ForgetMem( &inRecord->rdata );
+ free( inRecord );
+}
+
+//===========================================================================================================================
+// _MRResourceRecordFreeList
+//===========================================================================================================================
+
+static void _MRResourceRecordFreeList( MRResourceRecord *inList )
+{
+ MRResourceRecord * record;
+
+ while( ( record = inList ) != NULL )
+ {
+ inList = record->next;
+ _MRResourceRecordFree( record );
+ }
+}
+
+//===========================================================================================================================
+// _MRNameOffsetItemCreate
+//===========================================================================================================================
+
+static OSStatus _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem )
+{
+ OSStatus err;
+ MRNameOffsetItem * obj;
+ size_t nameLen;
+
+ require_action_quiet( inOffset <= kDNSCompressionOffsetMax, exit, err = kSizeErr );
+
+ nameLen = DomainNameLength( inName );
+ obj = (MRNameOffsetItem *) calloc( 1, offsetof( MRNameOffsetItem, name ) + nameLen );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->offset = inOffset;
+ memcpy( obj->name, inName, nameLen );
+
+ *outItem = obj;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _MRNameOffsetItemFree
+//===========================================================================================================================
+
+static void _MRNameOffsetItemFree( MRNameOffsetItem *inItem )
+{
+ free( inItem );
+}
+
+//===========================================================================================================================
+// _MRNameOffsetItemFreeList
+//===========================================================================================================================
+
+static void _MRNameOffsetItemFreeList( MRNameOffsetItem *inList )
+{
+ MRNameOffsetItem * item;
+
+ while( ( item = inList ) != NULL )
+ {
+ inList = item->next;
+ _MRNameOffsetItemFree( item );
+ }
+}
+
+//===========================================================================================================================
+// GAIPerfCmd
+//===========================================================================================================================
+
+#define kGAIPerfStandardTTL ( 1 * kSecondsPerHour )
+
+typedef struct GAITesterPrivate * GAITesterRef;
+typedef struct GAITestCase GAITestCase;
+
+typedef struct
+{
+ const char * name; // Domain name that was resolved.
+ uint64_t connectionTimeUs; // Time in microseconds that it took to create a DNS-SD connection.
+ uint64_t firstTimeUs; // Time in microseconds that it took to get the first address result.
+ uint64_t timeUs; // Time in microseconds that it took to get all expected address results.
+ OSStatus error;
+
+} GAITestItemResult;
+
+typedef void ( *GAITesterStopHandler_f )( void *inContext, OSStatus inError );
+typedef void
+ ( *GAITesterResultsHandler_f )(
+ const char * inCaseTitle,
+ NanoTime64 inCaseStartTime,
+ NanoTime64 inCaseEndTime,
+ const GAITestItemResult * inResultArray,
+ size_t inResultCount,
+ void * inContext );
+
+typedef unsigned int GAITestAddrType;
+#define kGAITestAddrType_None 0
+#define kGAITestAddrType_IPv4 ( 1U << 0 )
+#define kGAITestAddrType_IPv6 ( 1U << 1 )
+#define kGAITestAddrType_Both ( kGAITestAddrType_IPv4 | kGAITestAddrType_IPv6 )
+
+#define GAITestAddrTypeIsValid( X ) \
+ ( ( (X) & kGAITestAddrType_Both ) && ( ( (X) & ~kGAITestAddrType_Both ) == 0 ) )
+
+typedef struct
+{
+ GAITesterRef tester; // GAI tester object.
+ CFMutableArrayRef testCaseResults; // Array of test case results.
+ unsigned int iterTimeLimitMs; // Amount of time to allow each iteration to complete.
+ unsigned int callDelayMs; // Amount of time to wait before calling DNSServiceGetAddrInfo().
+ unsigned int serverDelayMs; // Amount of additional time to have server delay its responses.
+ unsigned int defaultIterCount; // Default test case iteration count.
+ dispatch_source_t sigIntSource; // Dispatch source for SIGINT.
+ dispatch_source_t sigTermSource; // Dispatch source for SIGTERM.
+ char * outputFilePath; // File to write test results to. If NULL, then write to stdout.
+ OutputFormatType outputFormat; // Format of test results output.
+ Boolean skipPathEval; // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
+ Boolean badUDPMode; // True if the test DNS server is to run in Bad UDP mode.
+ Boolean testFailed; // True if at least one test case iteration failed.
+
+} GAIPerfContext;
+
+static void GAIPerfContextFree( GAIPerfContext *inContext );
+static OSStatus GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext );
+static OSStatus GAIPerfAddBasicTestCases( GAIPerfContext *inContext );
+static void GAIPerfTesterStopHandler( void *inContext, OSStatus inError );
+static void
+ GAIPerfResultsHandler(
+ const char * inCaseTitle,
+ NanoTime64 inCaseStartTime,
+ NanoTime64 inCaseEndTime,
+ const GAITestItemResult * inResultArray,
+ size_t inResultCount,
+ void * inContext );
+static void GAIPerfSignalHandler( void *inContext );
+
+CFTypeID GAITesterGetTypeID( void );
+static OSStatus
+ GAITesterCreate(
+ dispatch_queue_t inQueue,
+ unsigned int inCallDelayMs,
+ int inServerDelayMs,
+ int inServerDefaultTTL,
+ Boolean inSkipPathEvaluation,
+ Boolean inBadUDPMode,
+ GAITesterRef * outTester );
+static void GAITesterStart( GAITesterRef inTester );
+static void GAITesterStop( GAITesterRef inTester );
+static OSStatus GAITesterAddTestCase( GAITesterRef inTester, GAITestCase *inCase );
+static void
+ GAITesterSetStopHandler(
+ GAITesterRef inTester,
+ GAITesterStopHandler_f inEventHandler,
+ void * inEventContext );
+static void
+ GAITesterSetResultsHandler(
+ GAITesterRef inTester,
+ GAITesterResultsHandler_f inResultsHandler,
+ void * inResultsContext );
+
+static OSStatus GAITestCaseCreate( const char *inTitle, GAITestCase **outCase );
+static void GAITestCaseFree( GAITestCase *inCase );
+static OSStatus
+ GAITestCaseAddItem(
+ GAITestCase * inCase,
+ unsigned int inAliasCount,
+ unsigned int inAddressCount,
+ int inTTL,
+ GAITestAddrType inHasAddrs,
+ GAITestAddrType inWantAddrs,
+ unsigned int inTimeLimitMs,
+ unsigned int inItemCount );
+static OSStatus
+ GAITestCaseAddLocalHostItem(
+ GAITestCase * inCase,
+ GAITestAddrType inWantAddrs,
+ unsigned int inTimeLimitMs,
+ unsigned int inItemCount );
+
+static void GAIPerfCmd( void )
+{
+ OSStatus err;
+ GAIPerfContext * context = NULL;
+
+ err = CheckRootUser();
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gGAIPerf_CallDelayMs, "call delay (ms)", 0, INT_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gGAIPerf_ServerDelayMs, "server delay (ms)", 0, INT_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gGAIPerf_IterationCount, "iteration count", 1, INT_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gGAIPerf_IterationTimeLimitMs, "iteration time limit (ms)", 0, INT_MAX );
+ require_noerr_quiet( err, exit );
+
+ context = (GAIPerfContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->testCaseResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->testCaseResults, exit, err = kNoMemoryErr );
+
+ context->iterTimeLimitMs = (unsigned int) gGAIPerf_IterationTimeLimitMs;
+ context->callDelayMs = (unsigned int) gGAIPerf_CallDelayMs;
+ context->serverDelayMs = (unsigned int) gGAIPerf_ServerDelayMs;
+ context->defaultIterCount = (unsigned int) gGAIPerf_IterationCount;
+ context->skipPathEval = gGAIPerf_SkipPathEvalulation ? true : false;
+ context->badUDPMode = gGAIPerf_BadUDPMode ? true : false;
+
+ if( gGAIPerf_OutputFilePath )
+ {
+ context->outputFilePath = strdup( gGAIPerf_OutputFilePath );
+ require_action( context->outputFilePath, exit, err = kNoMemoryErr );
+ }
+
+ err = OutputFormatFromArgString( gGAIPerf_OutputFormat, &context->outputFormat );
+ require_noerr_quiet( err, exit );
+
+ err = GAITesterCreate( dispatch_get_main_queue(), context->callDelayMs, (int) context->serverDelayMs,
+ kGAIPerfStandardTTL, context->skipPathEval, context->badUDPMode, &context->tester );
+ require_noerr( err, exit );
+
+ check( gGAIPerf_TestSuite );
+ if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Basic ) == 0 )
+ {
+ err = GAIPerfAddBasicTestCases( context );
+ require_noerr( err, exit );
+ }
+ else if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Advanced ) == 0 )
+ {
+ err = GAIPerfAddAdvancedTestCases( context );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ FPrintF( stderr, "error: Invalid test suite name: %s.\n", gGAIPerf_TestSuite );
+ goto exit;
+ }
+
+ GAITesterSetStopHandler( context->tester, GAIPerfTesterStopHandler, context );
+ GAITesterSetResultsHandler( context->tester, GAIPerfResultsHandler, context );
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, GAIPerfSignalHandler, context, &context->sigIntSource );
+ require_noerr( err, exit );
+ dispatch_resume( context->sigIntSource );
+
+ signal( SIGTERM, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGTERM, GAIPerfSignalHandler, context, &context->sigTermSource );
+ require_noerr( err, exit );
+ dispatch_resume( context->sigTermSource );
+
+ GAITesterStart( context->tester );
+ dispatch_main();
+
+exit:
+ if( context ) GAIPerfContextFree( context );
+ exit( 1 );
+}
+
+//===========================================================================================================================
+// GAIPerfContextFree
+//===========================================================================================================================
+
+static void GAIPerfContextFree( GAIPerfContext *inContext )
+{
+ ForgetCF( &inContext->tester );
+ ForgetCF( &inContext->testCaseResults );
+ ForgetMem( &inContext->outputFilePath );
+ dispatch_source_forget( &inContext->sigIntSource );
+ dispatch_source_forget( &inContext->sigTermSource );
+ free( inContext );
+}
+
+//===========================================================================================================================
+// GAIPerfAddAdvancedTestCases
+//===========================================================================================================================
+
+#define kTestCaseTitleBufferSize 128
+
+static void
+ _GAIPerfWriteTestCaseTitle(
+ char inBuffer[ kTestCaseTitleBufferSize ],
+ unsigned int inCNAMERecordCount,
+ unsigned int inARecordCount,
+ unsigned int inAAAARecordCount,
+ GAITestAddrType inRequested,
+ unsigned int inIterationCount,
+ Boolean inIterationsAreUnique );
+static void
+ _GAIPerfWriteLocalHostTestCaseTitle(
+ char inBuffer[ kTestCaseTitleBufferSize ],
+ GAITestAddrType inRequested,
+ unsigned int inIterationCount );
+
+#define kGAIPerfAdvancedTestSuite_MaxAliasCount 4
+#define kGAIPerfAdvancedTestSuite_MaxAddrCount 8
+
+static OSStatus GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext )
+{
+ OSStatus err;
+ unsigned int aliasCount, addressCount, i;
+ GAITestCase * testCase = NULL;
+ char title[ kTestCaseTitleBufferSize ];
+
+ aliasCount = 0;
+ while( aliasCount <= kGAIPerfAdvancedTestSuite_MaxAliasCount )
+ {
+ for( addressCount = 1; addressCount <= kGAIPerfAdvancedTestSuite_MaxAddrCount; addressCount *= 2 )
+ {
+ // Add a test case to resolve a domain name with
+ //
+ // <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
+ //
+ // to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which
+ // requires server queries.
+
+ _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
+ inContext->defaultIterCount, true );
+
+ err = GAITestCaseCreate( title, &testCase );
+ require_noerr( err, exit );
+
+ for( i = 0; i < inContext->defaultIterCount; ++i )
+ {
+ err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
+ kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs, 1 );
+ require_noerr( err, exit );
+ }
+
+ err = GAITesterAddTestCase( inContext->tester, testCase );
+ require_noerr( err, exit );
+ testCase = NULL;
+
+ // Add a test case to resolve a domain name with
+ //
+ // <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
+ //
+ // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique domain name, which requires a server
+ // query. The subsequent iterations resolve the same domain name as the preliminary iteration, which should
+ // ideally require no server queries, i.e., the results should come from the cache.
+
+ _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
+ inContext->defaultIterCount, false );
+
+ err = GAITestCaseCreate( title, &testCase );
+ require_noerr( err, exit );
+
+ err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
+ kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs, inContext->defaultIterCount + 1 );
+ require_noerr( err, exit );
+
+ err = GAITesterAddTestCase( inContext->tester, testCase );
+ require_noerr( err, exit );
+ testCase = NULL;
+ }
+
+ aliasCount = ( aliasCount == 0 ) ? 1 : ( 2 * aliasCount );
+ }
+
+ // Finally, add a test case to resolve localhost to its IPv4 and IPv6 addresses.
+
+ _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
+
+ err = GAITestCaseCreate( title, &testCase );
+ require_noerr( err, exit );
+
+ err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, inContext->iterTimeLimitMs,
+ inContext->defaultIterCount );
+ require_noerr( err, exit );
+
+ err = GAITesterAddTestCase( inContext->tester, testCase );
+ require_noerr( err, exit );
+ testCase = NULL;
+
+exit:
+ if( testCase ) GAITestCaseFree( testCase );
+ return( err );
+}
+
+//===========================================================================================================================
+// _GAIPerfWriteTestCaseTitle
+//===========================================================================================================================
+
+#define GAITestAddrTypeToRequestKeyValue( X ) ( \
+ ( (X) == kGAITestAddrType_Both ) ? "ipv4\\,ipv6" : \
+ ( (X) == kGAITestAddrType_IPv4 ) ? "ipv4" : \
+ ( (X) == kGAITestAddrType_IPv6 ) ? "ipv6" : \
+ "" )
+
+static void
+ _GAIPerfWriteTestCaseTitle(
+ char inBuffer[ kTestCaseTitleBufferSize ],
+ unsigned int inCNAMERecordCount,
+ unsigned int inARecordCount,
+ unsigned int inAAAARecordCount,
+ GAITestAddrType inRequested,
+ unsigned int inIterationCount,
+ Boolean inIterationsAreUnique )
+{
+ SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=dynamic,cname=%u,a=%u,aaaa=%u,req=%s,iterations=%u%?s",
+ inCNAMERecordCount, inARecordCount, inAAAARecordCount, GAITestAddrTypeToRequestKeyValue( inRequested ),
+ inIterationCount, inIterationsAreUnique, ",unique" );
+}
+
+//===========================================================================================================================
+// _GAIPerfWriteLocalHostTestCaseTitle
+//===========================================================================================================================
+
+static void
+ _GAIPerfWriteLocalHostTestCaseTitle(
+ char inBuffer[ kTestCaseTitleBufferSize ],
+ GAITestAddrType inRequested,
+ unsigned int inIterationCount )
+{
+ SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=localhost,req=%s,iterations=%u",
+ GAITestAddrTypeToRequestKeyValue( inRequested ), inIterationCount );
+}
+
+//===========================================================================================================================
+// GAIPerfAddBasicTestCases
+//===========================================================================================================================
+
+#define kGAIPerfBasicTestSuite_AliasCount 2
+#define kGAIPerfBasicTestSuite_AddrCount 4
+
+static OSStatus GAIPerfAddBasicTestCases( GAIPerfContext *inContext )
+{
+ OSStatus err;
+ GAITestCase * testCase = NULL;
+ char title[ kTestCaseTitleBufferSize ];
+ unsigned int i;
+
+ // Test Case #1:
+ // Resolve a domain name with
+ //
+ // 2 CNAME records, 4 A records, and 4 AAAA records
+ //
+ // to its IPv4 and IPv6 addresses. Each of the iterations resolves a unique domain name, which requires server
+ // queries.
+
+ _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
+ kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
+ inContext->defaultIterCount, true );
+
+ err = GAITestCaseCreate( title, &testCase );
+ require_noerr( err, exit );
+
+ for( i = 0; i < inContext->defaultIterCount; ++i )
+ {
+ err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
+ kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs, 1 );
+ require_noerr( err, exit );
+ }
+
+ err = GAITesterAddTestCase( inContext->tester, testCase );
+ require_noerr( err, exit );
+ testCase = NULL;
+
+ // Test Case #2:
+ // Resolve a domain name with
+ //
+ // 2 CNAME records, 4 A records, and 4 AAAA records
+ //
+ // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which
+ // requires server queries. Each of the subsequent iterations resolves the same domain name as the preliminary
+ // iteration, which should ideally require no additional server queries, i.e., the results should come from the cache.
+
+ _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
+ kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
+ inContext->defaultIterCount, false );
+
+ err = GAITestCaseCreate( title, &testCase );
+ require_noerr( err, exit );
+
+ err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
+ kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs,
+ inContext->defaultIterCount + 1 );
+ require_noerr( err, exit );
+
+ err = GAITesterAddTestCase( inContext->tester, testCase );
+ require_noerr( err, exit );
+ testCase = NULL;
+
+ // Test Case #3:
+ // Each iteration resolves localhost to its IPv4 and IPv6 addresses.
+
+ _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
+
+ err = GAITestCaseCreate( title, &testCase );
+ require_noerr( err, exit );
+
+ err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, inContext->iterTimeLimitMs,
+ inContext->defaultIterCount );
+ require_noerr( err, exit );
+
+ err = GAITesterAddTestCase( inContext->tester, testCase );
+ require_noerr( err, exit );
+ testCase = NULL;
+
+exit:
+ if( testCase ) GAITestCaseFree( testCase );
+ return( err );
+}
+
+//===========================================================================================================================
+// GAIPerfTesterStopHandler
+//===========================================================================================================================
+
+#define kGAIPerfResultsKey_Info CFSTR( "info" )
+#define kGAIPerfResultsKey_TestCases CFSTR( "testCases" )
+#define kGAIPerfResultsKey_Success CFSTR( "success" )
+
+#define kGAIPerfInfoKey_CallDelay CFSTR( "callDelayMs" )
+#define kGAIPerfInfoKey_ServerDelay CFSTR( "serverDelayMs" )
+#define kGAIPerfInfoKey_SkippedPathEval CFSTR( "skippedPathEval" )
+#define kGAIPerfInfoKey_UsedBadUDPMode CFSTR( "usedBadUPDMode" )
+
+static void GAIPerfTesterStopHandler( void *inContext, OSStatus inError )
+{
+ OSStatus err;
+ GAIPerfContext * const context = (GAIPerfContext *) inContext;
+ CFPropertyListRef plist;
+ int exitCode;
+
+ err = inError;
+ require_noerr_quiet( err, exit );
+
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO=" // info
+ "{"
+ "%kO=%lli" // callDelayMs
+ "%kO=%lli" // serverDelayMs
+ "%kO=%b" // skippedPathEval
+ "%kO=%b" // usedBadUPDMode
+ "}"
+ "%kO=%O" // testCases
+ "%kO=%b" // success
+ "}",
+ kGAIPerfResultsKey_Info,
+ kGAIPerfInfoKey_CallDelay, (int64_t) context->callDelayMs,
+ kGAIPerfInfoKey_ServerDelay, (int64_t) context->serverDelayMs,
+ kGAIPerfInfoKey_SkippedPathEval, context->skipPathEval,
+ kGAIPerfInfoKey_UsedBadUDPMode, context->badUDPMode,
+ kGAIPerfResultsKey_TestCases, context->testCaseResults,
+ kGAIPerfResultsKey_Success, !context->testFailed );
+ require_noerr( err, exit );
+
+ err = OutputPropertyList( plist, context->outputFormat, context->outputFilePath );
+ CFRelease( plist );
+ require_noerr( err, exit );
+
+exit:
+ exitCode = err ? 1 : ( context->testFailed ? 2 : 0 );
+ GAIPerfContextFree( context );
+ exit( exitCode );
+}
+
+//===========================================================================================================================
+// GAIPerfResultsHandler
+//===========================================================================================================================
+
+// Keys for test case dictionary
+
+#define kGAIPerfTestCaseKey_Title CFSTR( "title" )
+#define kGAIPerfTestCaseKey_StartTime CFSTR( "startTime" )
+#define kGAIPerfTestCaseKey_EndTime CFSTR( "endTime" )
+#define kGAIPerfTestCaseKey_Results CFSTR( "results" )
+#define kGAIPerfTestCaseKey_FirstStats CFSTR( "firstStats" )
+#define kGAIPerfTestCaseKey_ConnectionStats CFSTR( "connectionStats" )
+#define kGAIPerfTestCaseKey_Stats CFSTR( "stats" )
+
+// Keys for test case results array entry dictionaries
+
+#define kGAIPerfTestCaseResultKey_Name CFSTR( "name" )
+#define kGAIPerfTestCaseResultKey_ConnectionTime CFSTR( "connectionTimeUs" )
+#define kGAIPerfTestCaseResultKey_FirstTime CFSTR( "firstTimeUs" )
+#define kGAIPerfTestCaseResultKey_Time CFSTR( "timeUs" )
+
+// Keys for test case stats dictionaries
+
+#define kGAIPerfTestCaseStatsKey_Count CFSTR( "count" )
+#define kGAIPerfTestCaseStatsKey_Min CFSTR( "min" )
+#define kGAIPerfTestCaseStatsKey_Max CFSTR( "max" )
+#define kGAIPerfTestCaseStatsKey_Mean CFSTR( "mean" )
+#define kGAIPerfTestCaseStatsKey_StdDev CFSTR( "sd" )
+
+typedef struct
+{
+ double min;
+ double max;
+ double mean;
+ double stdDev;
+
+} GAIPerfStats;
+
+#define GAIPerfStatsInit( X ) \
+ do { (X)->min = DBL_MAX; (X)->max = DBL_MIN; (X)->mean = 0.0; (X)->stdDev = 0.0; } while( 0 )
+
+static void
+ GAIPerfResultsHandler(
+ const char * inCaseTitle,
+ NanoTime64 inCaseStartTime,
+ NanoTime64 inCaseEndTime,
+ const GAITestItemResult * inResultArray,
+ size_t inResultCount,
+ void * inContext )
+{
+ OSStatus err;
+ GAIPerfContext * const context = (GAIPerfContext *) inContext;
+ int namesAreDynamic, namesAreUnique;
+ const char * ptr;
+ size_t count, startIndex;
+ CFMutableArrayRef results = NULL;
+ GAIPerfStats stats, firstStats, connStats;
+ double sum, firstSum, connSum;
+ size_t keyValueLen, i;
+ char keyValue[ 16 ]; // Size must be at least strlen( "name=dynamic" ) + 1 bytes.
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+ const GAITestItemResult * result;
+
+ // If this test case resolves the same "d.test." name in each iteration (title contains the "name=dynamic" key-value
+ // pair, but not the "unique" key), then don't count the first iteration, whose purpose is to populate the cache with
+ // the domain name's CNAME, A, and AAAA records.
+
+ namesAreDynamic = false;
+ namesAreUnique = false;
+ ptr = inCaseTitle;
+ while( _ParseQuotedEscapedString( ptr, NULL, ",", keyValue, sizeof( keyValue ), &keyValueLen, NULL, &ptr ) )
+ {
+ if( strnicmpx( keyValue, keyValueLen, "name=dynamic" ) == 0 )
+ {
+ namesAreDynamic = true;
+ }
+ else if( strnicmpx( keyValue, keyValueLen, "unique" ) == 0 )
+ {
+ namesAreUnique = true;
+ }
+ if( namesAreDynamic && namesAreUnique ) break;
+ }
+
+ startIndex = ( ( inResultCount > 0 ) && namesAreDynamic && !namesAreUnique ) ? 1 : 0;
+ results = CFArrayCreateMutable( NULL, (CFIndex)( inResultCount - startIndex ), &kCFTypeArrayCallBacks );
+ require_action( results, exit, err = kNoMemoryErr );
+
+ GAIPerfStatsInit( &stats );
+ GAIPerfStatsInit( &firstStats );
+ GAIPerfStatsInit( &connStats );
+
+ sum = 0.0;
+ firstSum = 0.0;
+ connSum = 0.0;
+ count = 0;
+ for( i = startIndex; i < inResultCount; ++i )
+ {
+ double value;
+
+ result = &inResultArray[ i ];
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, results,
+ "{"
+ "%kO=%s" // name
+ "%kO=%lli" // connectionTimeUs
+ "%kO=%lli" // firstTimeUs
+ "%kO=%lli" // timeUs
+ "%kO=%lli" // error
+ "}",
+ kGAIPerfTestCaseResultKey_Name, result->name,
+ kGAIPerfTestCaseResultKey_ConnectionTime, (int64_t) result->connectionTimeUs,
+ kGAIPerfTestCaseResultKey_FirstTime, (int64_t) result->firstTimeUs,
+ kGAIPerfTestCaseResultKey_Time, (int64_t) result->timeUs,
+ CFSTR( "error" ), (int64_t) result->error );
+ require_noerr( err, exit );
+
+ if( !result->error )
+ {
+ value = (double) result->timeUs;
+ if( value < stats.min ) stats.min = value;
+ if( value > stats.max ) stats.max = value;
+ sum += value;
+
+ value = (double) result->firstTimeUs;
+ if( value < firstStats.min ) firstStats.min = value;
+ if( value > firstStats.max ) firstStats.max = value;
+ firstSum += value;
+
+ value = (double) result->connectionTimeUs;
+ if( value < connStats.min ) connStats.min = value;
+ if( value > connStats.max ) connStats.max = value;
+ connSum += value;
+
+ ++count;
+ }
+ else
+ {
+ context->testFailed = true;
+ }
+ }
+
+ if( count > 0 )
+ {
+ stats.mean = sum / count;
+ firstStats.mean = firstSum / count;
+ connStats.mean = connSum / count;
+
+ sum = 0.0;
+ firstSum = 0.0;
+ connSum = 0.0;
+ for( i = startIndex; i < inResultCount; ++i )
+ {
+ double diff;
+
+ result = &inResultArray[ i ];
+ if( result->error ) continue;
+
+ diff = stats.mean - (double) result->timeUs;
+ sum += ( diff * diff );
+
+ diff = firstStats.mean - (double) result->firstTimeUs;
+ firstSum += ( diff * diff );
+
+ diff = connStats.mean - (double) result->connectionTimeUs;
+ connSum += ( diff * diff );
+ }
+ stats.stdDev = sqrt( sum / count );
+ firstStats.stdDev = sqrt( firstSum / count );
+ connStats.stdDev = sqrt( connSum / count );
+ }
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->testCaseResults,
+ "{"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%O"
+ "%kO="
+ "{"
+ "%kO=%lli"
+ "%kO=%f"
+ "%kO=%f"
+ "%kO=%f"
+ "%kO=%f"
+ "}"
+ "%kO="
+ "{"
+ "%kO=%lli"
+ "%kO=%f"
+ "%kO=%f"
+ "%kO=%f"
+ "%kO=%f"
+ "}"
+ "%kO="
+ "{"
+ "%kO=%lli"
+ "%kO=%f"
+ "%kO=%f"
+ "%kO=%f"
+ "%kO=%f"
+ "}"
+ "}",
+ kGAIPerfTestCaseKey_Title, inCaseTitle,
+ kGAIPerfTestCaseKey_StartTime, _NanoTime64ToTimestamp( inCaseStartTime, startTime, sizeof( startTime ) ),
+ kGAIPerfTestCaseKey_EndTime, _NanoTime64ToTimestamp( inCaseEndTime, endTime, sizeof( endTime ) ),
+ kGAIPerfTestCaseKey_Results, results,
+ kGAIPerfTestCaseKey_Stats,
+ kGAIPerfTestCaseStatsKey_Count, (int64_t) count,
+ kGAIPerfTestCaseStatsKey_Min, stats.min,
+ kGAIPerfTestCaseStatsKey_Max, stats.max,
+ kGAIPerfTestCaseStatsKey_Mean, stats.mean,
+ kGAIPerfTestCaseStatsKey_StdDev, stats.stdDev,
+ kGAIPerfTestCaseKey_FirstStats,
+ kGAIPerfTestCaseStatsKey_Count, (int64_t) count,
+ kGAIPerfTestCaseStatsKey_Min, firstStats.min,
+ kGAIPerfTestCaseStatsKey_Max, firstStats.max,
+ kGAIPerfTestCaseStatsKey_Mean, firstStats.mean,
+ kGAIPerfTestCaseStatsKey_StdDev, firstStats.stdDev,
+ kGAIPerfTestCaseKey_ConnectionStats,
+ kGAIPerfTestCaseStatsKey_Count, (int64_t) count,
+ kGAIPerfTestCaseStatsKey_Min, connStats.min,
+ kGAIPerfTestCaseStatsKey_Max, connStats.max,
+ kGAIPerfTestCaseStatsKey_Mean, connStats.mean,
+ kGAIPerfTestCaseStatsKey_StdDev, connStats.stdDev );
+ require_noerr( err, exit );
+
+exit:
+ CFReleaseNullSafe( results );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// GAIPerfSignalHandler
+//===========================================================================================================================
+
+static void GAIPerfSignalHandler( void *inContext )
+{
+ GAIPerfContext * const context = (GAIPerfContext *) inContext;
+
+ if( !context->tester ) exit( 1 );
+ GAITesterStop( context->tester );
+ context->tester = NULL;
+}
+
+//===========================================================================================================================
+// GAITesterCreate
+//===========================================================================================================================
+
+// A character set of lower-case alphabet characters and digits and a string length of six allows for 36^6 = 2,176,782,336
+// possible strings to use in the Tag label.
+
+#define kGAITesterTagStringLen 6
+
+typedef struct GAITestItem GAITestItem;
+struct GAITestItem
+{
+ GAITestItem * next; // Next test item in list.
+ char * name; // Domain name to resolve.
+ uint64_t connectionTimeUs; // Time in microseconds that it took to create a DNS-SD connection.
+ uint64_t firstTimeUs; // Time in microseconds that it took to get the first address result.
+ uint64_t timeUs; // Time in microseconds that it took to get all expected address results.
+ unsigned int addressCount; // Address count of the domain name, i.e., the Count label argument.
+ OSStatus error; // Current status/error.
+ unsigned int timeLimitMs; // Time limit in milliseconds for the test item's completion.
+ Boolean hasV4; // True if the domain name has one or more IPv4 addresses.
+ Boolean hasV6; // True if the domain name has one or more IPv6 addresses.
+ Boolean wantV4; // True if DNSServiceGetAddrInfo() should be called to get IPv4 addresses.
+ Boolean wantV6; // True if DNSServiceGetAddrInfo() should be called to get IPv6 addresses.
+};
+
+struct GAITestCase
+{
+ GAITestCase * next; // Next test case in list.
+ GAITestItem * itemList; // List of test items.
+ char * title; // Title of the test case.
+};
+
+struct GAITesterPrivate
+{
+ CFRuntimeBase base; // CF object base.
+ dispatch_queue_t queue; // Serial work queue.
+ DNSServiceRef connection; // Reference to the shared DNS-SD connection.
+ DNSServiceRef getAddrInfo; // Reference to the current DNSServiceGetAddrInfo operation.
+ GAITestCase * caseList; // List of test cases.
+ GAITestCase * currentCase; // Pointer to the current test case.
+ GAITestItem * currentItem; // Pointer to the current test item.
+ NanoTime64 caseStartTime; // Start time of current test case in Unix time as nanoseconds.
+ NanoTime64 caseEndTime; // End time of current test case in Unix time as nanoseconds.
+ unsigned int callDelayMs; // Amount of time to wait before calling DNSServiceGetAddrInfo().
+ Boolean skipPathEval; // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
+ Boolean stopped; // True if the tester has been stopped.
+ Boolean badUDPMode; // True if the test DNS server is to run in Bad UDP mode.
+ dispatch_source_t timer; // Timer for enforcing a test item's time limit.
+ pcap_t * pcap; // Captures traffic between mDNSResponder and test DNS server.
+ pid_t serverPID; // PID of the test DNS server.
+ int serverDelayMs; // Additional time to have the server delay its responses by.
+ int serverDefaultTTL; // Default TTL for the server's records.
+ GAITesterStopHandler_f stopHandler; // User's stop handler.
+ void * stopContext; // User's event handler context.
+ GAITesterResultsHandler_f resultsHandler; // User's results handler.
+ void * resultsContext; // User's results handler context.
+
+ // Variables for current test item.
+
+ uint64_t bitmapV4; // Bitmap of IPv4 results that have yet to be received.
+ uint64_t bitmapV6; // Bitmap of IPv6 results that have yet to be received.
+ uint64_t startTicks; // Start ticks of DNSServiceGetAddrInfo().
+ uint64_t connTicks; // Ticks when the connection was created.
+ uint64_t firstTicks; // Ticks when the first DNSServiceGetAddrInfo result was received.
+ uint64_t endTicks; // Ticks when the last DNSServiceGetAddrInfo result was received.
+ Boolean gotFirstResult; // True if the first result has been received.
+};
+
+CF_CLASS_DEFINE( GAITester );
+
+static void _GAITesterStartNextTest( GAITesterRef inTester );
+static OSStatus _GAITesterCreatePacketCapture( pcap_t **outPCap );
+static void _GAITesterFirstGAITimeout( void *inContext );
+static void _GAITesterTimeout( void *inContext );
+static void DNSSD_API
+ _GAITesterFirstGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ _GAITesterGetAddrInfoCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+static void _GAITesterCompleteCurrentTest( GAITesterRef inTester, OSStatus inError );
+
+#define ForgetPacketCapture( X ) ForgetCustom( X, pcap_close )
+
+static OSStatus
+ GAITestItemCreate(
+ const char * inName,
+ unsigned int inAddressCount,
+ GAITestAddrType inHasAddrs,
+ GAITestAddrType inWantAddrs,
+ unsigned int inTimeLimitMs,
+ GAITestItem ** outItem );
+static OSStatus GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem );
+static void GAITestItemFree( GAITestItem *inItem );
+
+static OSStatus
+ GAITesterCreate(
+ dispatch_queue_t inQueue,
+ unsigned int inCallDelayMs,
+ int inServerDelayMs,
+ int inServerDefaultTTL,
+ Boolean inSkipPathEvaluation,
+ Boolean inBadUDPMode,
+ GAITesterRef * outTester )
+{
+ OSStatus err;
+ GAITesterRef obj = NULL;
+
+ CF_OBJECT_CREATE( GAITester, obj, err, exit );
+
+ ReplaceDispatchQueue( &obj->queue, inQueue );
+ obj->callDelayMs = inCallDelayMs;
+ obj->serverPID = -1;
+ obj->serverDelayMs = inServerDelayMs;
+ obj->serverDefaultTTL = inServerDefaultTTL;
+ obj->skipPathEval = inSkipPathEvaluation;
+ obj->badUDPMode = inBadUDPMode;
+
+ *outTester = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ CFReleaseNullSafe( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _GAITesterFinalize
+//===========================================================================================================================
+
+static void _GAITesterFinalize( CFTypeRef inObj )
+{
+ GAITesterRef const me = (GAITesterRef) inObj;
+ GAITestCase * testCase;
+
+ check( !me->getAddrInfo );
+ check( !me->connection );
+ check( !me->timer );
+ dispatch_forget( &me->queue );
+ while( ( testCase = me->caseList ) != NULL )
+ {
+ me->caseList = testCase->next;
+ GAITestCaseFree( testCase );
+ }
+}
+
+//===========================================================================================================================
+// GAITesterStart
+//===========================================================================================================================
+
+static void _GAITesterStart( void *inContext );
+static void _GAITesterStop( GAITesterRef me, OSStatus inError );
+
+static void GAITesterStart( GAITesterRef me )
+{
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _GAITesterStart );
+}
+
+#define kGAITesterFirstGAITimeoutSecs 4
+
+static void _GAITesterStart( void *inContext )
+{
+ OSStatus err;
+ GAITesterRef const me = (GAITesterRef) inContext;
+ DNSServiceFlags flags;
+ char name[ 64 ];
+ char tag[ kGAITesterTagStringLen + 1 ];
+
+ err = SpawnCommand( &me->serverPID, "dnssdutil server --loopback --follow %lld%?s%?d%?s%?d%?s",
+ (int64_t) getpid(),
+ me->serverDefaultTTL >= 0, " --defaultTTL ",
+ me->serverDefaultTTL >= 0, me->serverDefaultTTL,
+ me->serverDelayMs >= 0, " --responseDelay ",
+ me->serverDelayMs >= 0, me->serverDelayMs,
+ me->badUDPMode, " --badUDPMode" );
+ require_noerr_quiet( err, exit );
+
+ SNPrintF( name, sizeof( name ), "tag-gaitester-probe-%s.ipv4.d.test",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+
+ flags = 0;
+ if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
+
+ err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, kDNSServiceProtocol_IPv4, name,
+ _GAITesterFirstGAICallback, me );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( me->getAddrInfo, me->queue );
+ require_noerr( err, exit );
+
+ err = DispatchTimerOneShotCreate( dispatch_time_seconds( kGAITesterFirstGAITimeoutSecs ),
+ UINT64_C_safe( kGAITesterFirstGAITimeoutSecs ) * kNanosecondsPerSecond / 10, me->queue,
+ _GAITesterFirstGAITimeout, me, &me->timer );
+ require_noerr( err, exit );
+ dispatch_resume( me->timer );
+
+exit:
+ if( err ) _GAITesterStop( me, err );
+}
+
+//===========================================================================================================================
+// GAITesterStop
+//===========================================================================================================================
+
+static void _GAITesterUserStop( void *inContext );
+
+static void GAITesterStop( GAITesterRef me )
+{
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _GAITesterUserStop );
+}
+
+static void _GAITesterUserStop( void *inContext )
+{
+ GAITesterRef const me = (GAITesterRef) inContext;
+
+ _GAITesterStop( me, kCanceledErr );
+ CFRelease( me );
+}
+
+static void _GAITesterStop( GAITesterRef me, OSStatus inError )
+{
+ OSStatus err;
+
+ ForgetPacketCapture( &me->pcap );
+ dispatch_source_forget( &me->timer );
+ DNSServiceForget( &me->getAddrInfo );
+ DNSServiceForget( &me->connection );
+ if( me->serverPID != -1 )
+ {
+ err = kill( me->serverPID, SIGTERM );
+ err = map_global_noerr_errno( err );
+ check_noerr( err );
+ me->serverPID = -1;
+ }
+
+ if( !me->stopped )
+ {
+ me->stopped = true;
+ if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
+ CFRelease( me );
+ }
+}
+
+//===========================================================================================================================
+// GAITesterAddTestCase
+//===========================================================================================================================
+
+static OSStatus GAITesterAddTestCase( GAITesterRef me, GAITestCase *inCase )
+{
+ OSStatus err;
+ GAITestCase ** ptr;
+
+ require_action_quiet( inCase->itemList, exit, err = kCountErr );
+
+ for( ptr = &me->caseList; *ptr; ptr = &( *ptr )->next ) {}
+ *ptr = inCase;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITesterSetStopHandler
+//===========================================================================================================================
+
+static void GAITesterSetStopHandler( GAITesterRef me, GAITesterStopHandler_f inStopHandler, void *inStopContext )
+{
+ me->stopHandler = inStopHandler;
+ me->stopContext = inStopContext;
+}
+
+//===========================================================================================================================
+// GAITesterSetResultsHandler
+//===========================================================================================================================
+
+static void GAITesterSetResultsHandler( GAITesterRef me, GAITesterResultsHandler_f inResultsHandler, void *inResultsContext )
+{
+ me->resultsHandler = inResultsHandler;
+ me->resultsContext = inResultsContext;
+}
+
+//===========================================================================================================================
+// _GAITesterStartNextTest
+//===========================================================================================================================
+
+static void _GAITesterStartNextTest( GAITesterRef me )
+{
+ OSStatus err;
+ GAITestItem * item;
+ DNSServiceFlags flags;
+ DNSServiceProtocol protocols;
+ int done = false;
+
+ if( me->currentItem ) me->currentItem = me->currentItem->next;
+
+ if( !me->currentItem )
+ {
+ if( me->currentCase )
+ {
+ // No more test items means that the current test case has completed.
+
+ me->caseEndTime = NanoTimeGetCurrent();
+
+ if( me->resultsHandler )
+ {
+ size_t resultCount, i;
+ GAITestItemResult * resultArray;
+
+ resultCount = 0;
+ for( item = me->currentCase->itemList; item; item = item->next ) ++resultCount;
+ check( resultCount > 0 );
+
+ resultArray = (GAITestItemResult *) calloc( resultCount, sizeof( *resultArray ) );
+ require_action( resultArray, exit, err = kNoMemoryErr );
+
+ item = me->currentCase->itemList;
+ for( i = 0; i < resultCount; ++i )
+ {
+ resultArray[ i ].name = item->name;
+ resultArray[ i ].connectionTimeUs = item->connectionTimeUs;
+ resultArray[ i ].firstTimeUs = item->firstTimeUs;
+ resultArray[ i ].timeUs = item->timeUs;
+ resultArray[ i ].error = item->error;
+ item = item->next;
+ }
+ me->resultsHandler( me->currentCase->title, me->caseStartTime, me->caseEndTime, resultArray, resultCount,
+ me->resultsContext );
+ ForgetMem( &resultArray );
+ }
+
+ me->currentCase = me->currentCase->next;
+ if( !me->currentCase )
+ {
+ done = true;
+ err = kNoErr;
+ goto exit;
+ }
+ }
+ else
+ {
+ me->currentCase = me->caseList;
+ }
+ require_action_quiet( me->currentCase->itemList, exit, err = kInternalErr );
+ me->currentItem = me->currentCase->itemList;
+ }
+
+ item = me->currentItem;
+ check( ( item->addressCount >= 1 ) && ( item->addressCount <= 64 ) );
+
+ if( !item->wantV4 ) me->bitmapV4 = 0;
+ else if( !item->hasV4 ) me->bitmapV4 = 1;
+ else if( item->addressCount < 64 ) me->bitmapV4 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
+ else me->bitmapV4 = ~UINT64_C( 0 );
+
+ if( !item->wantV6 ) me->bitmapV6 = 0;
+ else if( !item->hasV6 ) me->bitmapV6 = 1;
+ else if( item->addressCount < 64 ) me->bitmapV6 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
+ else me->bitmapV6 = ~UINT64_C( 0 );
+ check( ( me->bitmapV4 != 0 ) || ( me->bitmapV6 != 0 ) );
+ me->gotFirstResult = false;
+
+ // Perform preliminary tasks if this is the start of a new test case.
+
+ if( item == me->currentCase->itemList )
+ {
+ // Flush mDNSResponder's cache.
+
+ err = systemf( NULL, "killall -HUP mDNSResponder" );
+ require_noerr( err, exit );
+ sleep( 1 );
+
+ me->caseStartTime = NanoTimeGetCurrent();
+ me->caseEndTime = kNanoTime_Invalid;
+ }
+
+ // Start a packet capture.
+
+ check( !me->pcap );
+ err = _GAITesterCreatePacketCapture( &me->pcap );
+ require_noerr( err, exit );
+
+ // Start timer for test item's time limit.
+
+ check( !me->timer );
+ if( item->timeLimitMs > 0 )
+ {
+ unsigned int timeLimitMs;
+
+ timeLimitMs = item->timeLimitMs;
+ if( me->callDelayMs > 0 ) timeLimitMs += (unsigned int) me->callDelayMs;
+ if( me->serverDelayMs > 0 ) timeLimitMs += (unsigned int) me->serverDelayMs;
+
+ err = DispatchTimerCreate( dispatch_time_milliseconds( timeLimitMs ), DISPATCH_TIME_FOREVER,
+ ( (uint64_t) timeLimitMs ) * kNanosecondsPerMillisecond / 10,
+ me->queue, _GAITesterTimeout, NULL, me, &me->timer );
+ require_noerr( err, exit );
+ dispatch_resume( me->timer );
+ }
+
+ // Call DNSServiceGetAddrInfo().
+
+ if( me->callDelayMs > 0 ) usleep( ( (useconds_t) me->callDelayMs ) * kMicrosecondsPerMillisecond );
+
+ flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
+ if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
+
+ protocols = 0;
+ if( item->wantV4 ) protocols |= kDNSServiceProtocol_IPv4;
+ if( item->wantV6 ) protocols |= kDNSServiceProtocol_IPv6;
+
+ me->startTicks = UpTicks();
+
+ check( !me->connection );
+ err = DNSServiceCreateConnection( &me->connection );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( me->connection, me->queue );
+ require_noerr( err, exit );
+
+ me->connTicks = UpTicks();
+
+ check( !me->getAddrInfo );
+ me->getAddrInfo = me->connection;
+ err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, protocols, item->name,
+ _GAITesterGetAddrInfoCallback, me );
+ require_noerr( err, exit );
+
+exit:
+ if( err || done ) _GAITesterStop( me, err );
+}
+
+//===========================================================================================================================
+// _GAITesterCreatePacketCapture
+//===========================================================================================================================
+
+static OSStatus _GAITesterCreatePacketCapture( pcap_t **outPCap )
+{
+ OSStatus err;
+ pcap_t * pcap;
+ struct bpf_program program;
+ char errBuf[ PCAP_ERRBUF_SIZE ];
+
+ pcap = pcap_create( "lo0", errBuf );
+ require_action_string( pcap, exit, err = kUnknownErr, errBuf );
+
+ err = pcap_set_buffer_size( pcap, 512 * kBytesPerKiloByte );
+ require_noerr_action( err, exit, err = kUnknownErr );
+
+ err = pcap_set_snaplen( pcap, 512 );
+ require_noerr_action( err, exit, err = kUnknownErr );
+
+ err = pcap_set_immediate_mode( pcap, 0 );
+ require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+
+ err = pcap_activate( pcap );
+ require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+
+ err = pcap_setdirection( pcap, PCAP_D_INOUT );
+ require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+
+ err = pcap_setnonblock( pcap, 1, errBuf );
+ require_noerr_action_string( err, exit, err = kUnknownErr, errBuf );
+
+ err = pcap_compile( pcap, &program, "udp port 53", 1, PCAP_NETMASK_UNKNOWN );
+ require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+
+ err = pcap_setfilter( pcap, &program );
+ pcap_freecode( &program );
+ require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+
+ *outPCap = pcap;
+ pcap = NULL;
+
+exit:
+ if( pcap ) pcap_close( pcap );
+ return( err );
+}
+
+//===========================================================================================================================
+// _GAITesterFirstGAITimeout
+//===========================================================================================================================
+
+static void _GAITesterFirstGAITimeout( void *inContext )
+{
+ GAITesterRef const me = (GAITesterRef) inContext;
+
+ _GAITesterStop( me, kNoResourcesErr );
+}
+
+//===========================================================================================================================
+// _GAITesterTimeout
+//===========================================================================================================================
+
+static void _GAITesterTimeout( void *inContext )
+{
+ GAITesterRef const me = (GAITesterRef) inContext;
+
+ _GAITesterCompleteCurrentTest( me, kTimeoutErr );
+}
+
+//===========================================================================================================================
+// _GAITesterFirstGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _GAITesterFirstGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ GAITesterRef const me = (GAITesterRef) inContext;
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inHostname );
+ Unused( inSockAddr );
+ Unused( inTTL );
+
+ if( ( inFlags & kDNSServiceFlagsAdd ) && !inError )
+ {
+ dispatch_source_forget( &me->timer );
+ DNSServiceForget( &me->getAddrInfo );
+
+ _GAITesterStartNextTest( me );
+ }
+}
+
+//===========================================================================================================================
+// _GAITesterGetAddrInfoCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _GAITesterGetAddrInfoCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ GAITesterRef const me = (GAITesterRef) inContext;
+ GAITestItem * const item = me->currentItem;
+ const sockaddr_ip * const sip = (const sockaddr_ip *) inSockAddr;
+ uint64_t nowTicks;
+ uint64_t * bitmapPtr;
+ uint64_t bitmask;
+ int hasAddr;
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inHostname );
+ Unused( inTTL );
+
+ nowTicks = UpTicks();
+
+ require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
+
+ // Check if we were expecting an IP address result of this type.
+
+ if( sip->sa.sa_family == AF_INET )
+ {
+ bitmapPtr = &me->bitmapV4;
+ hasAddr = item->hasV4;
+ }
+ else if( sip->sa.sa_family == AF_INET6 )
+ {
+ bitmapPtr = &me->bitmapV6;
+ hasAddr = item->hasV6;
+ }
+ else
+ {
+ err = kTypeErr;
+ goto exit;
+ }
+
+ bitmask = 0;
+ if( hasAddr )
+ {
+ uint32_t addrOffset;
+
+ require_noerr_action_quiet( inError, exit, err = inError );
+
+ if( sip->sa.sa_family == AF_INET )
+ {
+ const uint32_t addrV4 = ntohl( sip->v4.sin_addr.s_addr );
+
+ if( strcasecmp( item->name, "localhost." ) == 0 )
+ {
+ if( addrV4 == INADDR_LOOPBACK ) bitmask = 1;
+ }
+ else
+ {
+ addrOffset = addrV4 - kDNSServerBaseAddrV4;
+ if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
+ {
+ bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
+ }
+ }
+ }
+ else
+ {
+ const uint8_t * const addrV6 = sip->v6.sin6_addr.s6_addr;
+
+ if( strcasecmp( item->name, "localhost." ) == 0 )
+ {
+ if( memcmp( addrV6, in6addr_loopback.s6_addr, 16 ) == 0 ) bitmask = 1;
+ }
+ else if( memcmp( addrV6, kDNSServerBaseAddrV6, 15 ) == 0 )
+ {
+ addrOffset = addrV6[ 15 ];
+ if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
+ {
+ bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
+ }
+ }
+ }
+ }
+ else
+ {
+ require_action_quiet( inError == kDNSServiceErr_NoSuchRecord, exit, err = inError ? inError : kUnexpectedErr );
+ bitmask = 1;
+ }
+ require_action_quiet( bitmask != 0, exit, err = kValueErr );
+ require_action_quiet( *bitmapPtr & bitmask, exit, err = kDuplicateErr );
+
+ *bitmapPtr &= ~bitmask;
+ if( !me->gotFirstResult )
+ {
+ me->firstTicks = nowTicks;
+ me->gotFirstResult = true;
+ }
+ err = kNoErr;
+
+exit:
+ if( err || ( ( me->bitmapV4 == 0 ) && ( me->bitmapV6 == 0 ) ) )
+ {
+ me->endTicks = nowTicks;
+ _GAITesterCompleteCurrentTest( me, err );
+ }
+}
+
+//===========================================================================================================================
+// _GAITesterCompleteCurrentTest
+//===========================================================================================================================
+
+static OSStatus
+ _GAITesterGetDNSMessageFromPacket(
+ const uint8_t * inPacketPtr,
+ size_t inPacketLen,
+ const uint8_t ** outMsgPtr,
+ size_t * outMsgLen );
+
+static void _GAITesterCompleteCurrentTest( GAITesterRef me, OSStatus inError )
+{
+ OSStatus err;
+ GAITestItem * const item = me->currentItem;
+ struct timeval timeStamps[ 4 ];
+ struct timeval * tsPtr;
+ struct timeval * tsQA = NULL;
+ struct timeval * tsQAAAA = NULL;
+ struct timeval * tsRA = NULL;
+ struct timeval * tsRAAAA = NULL;
+ struct timeval * t1;
+ struct timeval * t2;
+ int64_t idleTimeUs;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ dispatch_source_forget( &me->timer );
+ DNSServiceForget( &me->getAddrInfo );
+ DNSServiceForget( &me->connection );
+
+ item->error = inError;
+ if( item->error )
+ {
+ err = kNoErr;
+ goto exit;
+ }
+
+ err = DomainNameFromString( name, item->name, NULL );
+ require_noerr( err, exit );
+
+ tsPtr = &timeStamps[ 0 ];
+ for( ;; )
+ {
+ int status;
+ struct pcap_pkthdr * pktHdr;
+ const uint8_t * packet;
+ const uint8_t * msgPtr;
+ size_t msgLen;
+ const DNSHeader * hdr;
+ unsigned int flags;
+ const uint8_t * ptr;
+ uint16_t qtype, qclass;
+ uint8_t qname[ kDomainNameLengthMax ];
+
+ status = pcap_next_ex( me->pcap, &pktHdr, &packet );
+ if( status != 1 ) break;
+ if( _GAITesterGetDNSMessageFromPacket( packet, pktHdr->caplen, &msgPtr, &msgLen ) != kNoErr ) continue;
+ if( msgLen < kDNSHeaderLength ) continue;
+
+ hdr = (const DNSHeader *) msgPtr;
+ flags = DNSHeaderGetFlags( hdr );
+ if( DNSFlagsGetOpCode( flags ) != kDNSOpCode_Query ) continue;
+ if( DNSHeaderGetQuestionCount( hdr ) < 1 ) continue;
+
+ ptr = (const uint8_t *) &hdr[ 1 ];
+ if( DNSMessageExtractQuestion( msgPtr, msgLen, ptr, qname, &qtype, &qclass, NULL ) != kNoErr ) continue;
+ if( qclass != kDNSServiceClass_IN ) continue;
+ if( !DomainNameEqual( qname, name ) ) continue;
+
+ if( item->wantV4 && ( qtype == kDNSServiceType_A ) )
+ {
+ if( flags & kDNSHeaderFlag_Response )
+ {
+ if( tsQA && !tsRA )
+ {
+ tsRA = tsPtr++;
+ *tsRA = pktHdr->ts;
+ }
+ }
+ else if( !tsQA )
+ {
+ tsQA = tsPtr++;
+ *tsQA = pktHdr->ts;
+ }
+ }
+ else if( item->wantV6 && ( qtype == kDNSServiceType_AAAA ) )
+ {
+ if( flags & kDNSHeaderFlag_Response )
+ {
+ if( tsQAAAA && !tsRAAAA )
+ {
+ tsRAAAA = tsPtr++;
+ *tsRAAAA = pktHdr->ts;
+ }
+ }
+ else if( !tsQAAAA )
+ {
+ tsQAAAA = tsPtr++;
+ *tsQAAAA = pktHdr->ts;
+ }
+ }
+ }
+
+ // t1 is the time when the last query was sent.
+
+ if( tsQA && tsQAAAA ) t1 = TIMEVAL_GT( *tsQA, *tsQAAAA ) ? tsQA : tsQAAAA;
+ else t1 = tsQA ? tsQA : tsQAAAA;
+
+ // t2 is when the first response was received.
+
+ if( tsRA && tsRAAAA ) t2 = TIMEVAL_LT( *tsRA, *tsRAAAA ) ? tsRA : tsRAAAA;
+ else t2 = tsRA ? tsRA : tsRAAAA;
+
+ if( t1 && t2 )
+ {
+ idleTimeUs = TIMEVAL_USEC64_DIFF( *t2, *t1 );
+ if( idleTimeUs < 0 ) idleTimeUs = 0;
+ }
+ else
+ {
+ idleTimeUs = 0;
+ }
+
+ item->connectionTimeUs = UpTicksToMicroseconds( me->connTicks - me->startTicks );
+ item->firstTimeUs = UpTicksToMicroseconds( me->firstTicks - me->connTicks ) - (uint64_t) idleTimeUs;
+ item->timeUs = UpTicksToMicroseconds( me->endTicks - me->connTicks ) - (uint64_t) idleTimeUs;
+
+exit:
+ ForgetPacketCapture( &me->pcap );
+ if( err ) _GAITesterStop( me, err );
+ else _GAITesterStartNextTest( me );
+}
+
+//===========================================================================================================================
+// _GAITesterGetDNSMessageFromPacket
+//===========================================================================================================================
+
+#define kHeaderSizeNullLink 4
+#define kHeaderSizeIPv4Min 20
+#define kHeaderSizeIPv6 40
+#define kHeaderSizeUDP 8
+
+#define kIPProtocolUDP 0x11
+
+static OSStatus
+ _GAITesterGetDNSMessageFromPacket(
+ const uint8_t * inPacketPtr,
+ size_t inPacketLen,
+ const uint8_t ** outMsgPtr,
+ size_t * outMsgLen )
+{
+ OSStatus err;
+ const uint8_t * nullLink;
+ uint32_t addressFamily;
+ const uint8_t * ip;
+ int ipHeaderLen;
+ int protocol;
+ const uint8_t * msg;
+ const uint8_t * const end = &inPacketPtr[ inPacketLen ];
+
+ nullLink = &inPacketPtr[ 0 ];
+ require_action_quiet( ( end - nullLink ) >= kHeaderSizeNullLink, exit, err = kUnderrunErr );
+ addressFamily = ReadHost32( &nullLink[ 0 ] );
+
+ ip = &nullLink[ kHeaderSizeNullLink ];
+ if( addressFamily == AF_INET )
+ {
+ require_action_quiet( ( end - ip ) >= kHeaderSizeIPv4Min, exit, err = kUnderrunErr );
+ ipHeaderLen = ( ip[ 0 ] & 0x0F ) * 4;
+ protocol = ip[ 9 ];
+ }
+ else if( addressFamily == AF_INET6 )
+ {
+ require_action_quiet( ( end - ip ) >= kHeaderSizeIPv6, exit, err = kUnderrunErr );
+ ipHeaderLen = kHeaderSizeIPv6;
+ protocol = ip[ 6 ];
+ }
+ else
+ {
+ err = kTypeErr;
+ goto exit;
+ }
+ require_action_quiet( protocol == kIPProtocolUDP, exit, err = kTypeErr );
+ require_action_quiet( ( end - ip ) >= ( ipHeaderLen + kHeaderSizeUDP ), exit, err = kUnderrunErr );
+
+ msg = &ip[ ipHeaderLen + kHeaderSizeUDP ];
+
+ *outMsgPtr = msg;
+ *outMsgLen = (size_t)( end - msg );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITestCaseCreate
+//===========================================================================================================================
+
+static OSStatus GAITestCaseCreate( const char *inTitle, GAITestCase **outCase )
+{
+ OSStatus err;
+ GAITestCase * obj;
+
+ obj = (GAITestCase *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->title = strdup( inTitle );
+ require_action( obj->title, exit, err = kNoMemoryErr );
+
+ *outCase = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) GAITestCaseFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITestCaseFree
+//===========================================================================================================================
+
+static void GAITestCaseFree( GAITestCase *inCase )
+{
+ GAITestItem * item;
+
+ while( ( item = inCase->itemList ) != NULL )
+ {
+ inCase->itemList = item->next;
+ GAITestItemFree( item );
+ }
+ ForgetMem( &inCase->title );
+ free( inCase );
+}
+
+//===========================================================================================================================
+// GAITestCaseAddItem
+//===========================================================================================================================
+
+static OSStatus
+ GAITestCaseAddItem(
+ GAITestCase * inCase,
+ unsigned int inAliasCount,
+ unsigned int inAddressCount,
+ int inTTL,
+ GAITestAddrType inHasAddrs,
+ GAITestAddrType inWantAddrs,
+ unsigned int inTimeLimitMs,
+ unsigned int inItemCount )
+{
+ OSStatus err;
+ GAITestItem * item;
+ GAITestItem * item2;
+ GAITestItem * newItemList = NULL;
+ GAITestItem ** itemPtr;
+ char * ptr;
+ char * end;
+ unsigned int i;
+ char name[ 64 ];
+ char tag[ kGAITesterTagStringLen + 1 ];
+
+ require_action_quiet( inItemCount > 0, exit, err = kNoErr );
+
+ // Limit address count to 64 because we use 64-bit bitmaps for keeping track of addresses.
+
+ require_action_quiet( ( inAddressCount >= 1 ) && ( inAddressCount <= 64 ), exit, err = kCountErr );
+ require_action_quiet( ( inAliasCount >= 0 ) && ( inAliasCount <= INT32_MAX ), exit, err = kCountErr );
+ require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
+
+ ptr = &name[ 0 ];
+ end = &name[ countof( name ) ];
+
+ // Add Alias label.
+
+ if( inAliasCount == 1 ) SNPrintF_Add( &ptr, end, "alias." );
+ else if( inAliasCount >= 2 ) SNPrintF_Add( &ptr, end, "alias-%u.", inAliasCount );
+
+ // Add Count label.
+
+ SNPrintF_Add( &ptr, end, "count-%u.", inAddressCount );
+
+ // Add TTL label.
+
+ if( inTTL >= 0 ) SNPrintF_Add( &ptr, end, "ttl-%d.", inTTL );
+
+ // Add Tag label.
+
+ SNPrintF_Add( &ptr, end, "tag-%s.",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+
+ // Add IPv4 or IPv6 label if necessary.
+
+ if( inHasAddrs == kGAITestAddrType_IPv4 ) SNPrintF_Add( &ptr, end, "ipv4." );
+ else if( inHasAddrs == kGAITestAddrType_IPv6 ) SNPrintF_Add( &ptr, end, "ipv6." );
+
+ // Finally, add the d.test. labels.
+
+ SNPrintF_Add( &ptr, end, "d.test." );
+
+ // Create item.
+
+ err = GAITestItemCreate( name, inAddressCount, inHasAddrs, inWantAddrs, inTimeLimitMs, &item );
+ require_noerr( err, exit );
+
+ newItemList = item;
+ itemPtr = &item->next;
+
+ // Create repeat items.
+
+ for( i = 1; i < inItemCount; ++i )
+ {
+ err = GAITestItemDup( item, &item2 );
+ require_noerr( err, exit );
+
+ *itemPtr = item2;
+ itemPtr = &item2->next;
+ }
+
+ // Append to test case's item list.
+
+ for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
+ *itemPtr = newItemList;
+ newItemList = NULL;
+
+exit:
+ while( ( item = newItemList ) != NULL )
+ {
+ newItemList = item->next;
+ GAITestItemFree( item );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITestCaseAddLocalHostItem
+//===========================================================================================================================
+
+static OSStatus
+ GAITestCaseAddLocalHostItem(
+ GAITestCase * inCase,
+ GAITestAddrType inWantAddrs,
+ unsigned int inTimeLimitMs,
+ unsigned int inItemCount )
+{
+ OSStatus err;
+ GAITestItem * item;
+ GAITestItem * item2;
+ GAITestItem * newItemList = NULL;
+ GAITestItem ** itemPtr;
+ unsigned int i;
+
+ require_action_quiet( inItemCount > 1, exit, err = kNoErr );
+
+ err = GAITestItemCreate( "localhost.", 1, kGAITestAddrType_Both, inWantAddrs, inTimeLimitMs, &item );
+ require_noerr( err, exit );
+
+ newItemList = item;
+ itemPtr = &item->next;
+
+ // Create repeat items.
+
+ for( i = 1; i < inItemCount; ++i )
+ {
+ err = GAITestItemDup( item, &item2 );
+ require_noerr( err, exit );
+
+ *itemPtr = item2;
+ itemPtr = &item2->next;
+ }
+
+ for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
+ *itemPtr = newItemList;
+ newItemList = NULL;
+
+exit:
+ while( ( item = newItemList ) != NULL )
+ {
+ newItemList = item->next;
+ GAITestItemFree( item );
+ }
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITestItemCreate
+//===========================================================================================================================
+
+static OSStatus
+ GAITestItemCreate(
+ const char * inName,
+ unsigned int inAddressCount,
+ GAITestAddrType inHasAddrs,
+ GAITestAddrType inWantAddrs,
+ unsigned int inTimeLimitMs,
+ GAITestItem ** outItem )
+{
+ OSStatus err;
+ GAITestItem * obj = NULL;
+
+ require_action_quiet( inAddressCount >= 1, exit, err = kCountErr );
+ require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
+ require_action_quiet( GAITestAddrTypeIsValid( inWantAddrs ), exit, err = kValueErr );
+
+ obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ obj->addressCount = inAddressCount;
+ obj->hasV4 = ( inHasAddrs & kGAITestAddrType_IPv4 ) ? true : false;
+ obj->hasV6 = ( inHasAddrs & kGAITestAddrType_IPv6 ) ? true : false;
+ obj->wantV4 = ( inWantAddrs & kGAITestAddrType_IPv4 ) ? true : false;
+ obj->wantV6 = ( inWantAddrs & kGAITestAddrType_IPv6 ) ? true : false;
+ obj->error = kInProgressErr;
+ obj->timeLimitMs = inTimeLimitMs;
+
+ *outItem = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) GAITestItemFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITestItemDup
+//===========================================================================================================================
+
+static OSStatus GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem )
+{
+ OSStatus err;
+ GAITestItem * obj;
+
+ obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ *obj = *inItem;
+ obj->next = NULL;
+ if( inItem->name )
+ {
+ obj->name = strdup( inItem->name );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+ }
+
+ *outItem = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) GAITestItemFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// GAITestItemFree
+//===========================================================================================================================
+
+static void GAITestItemFree( GAITestItem *inItem )
+{
+ ForgetMem( &inItem->name );
+ free( inItem );
+}
+
+//===========================================================================================================================
+// MDNSDiscoveryTestCmd
+//===========================================================================================================================
+
+#define kMDNSDiscoveryTestFirstQueryTimeoutSecs 4
+
+typedef struct
+{
+ DNSServiceRef query; // Reference to DNSServiceQueryRecord for replier's "about" TXT record.
+ dispatch_source_t queryTimer; // Used to time out the "about" TXT record query.
+ NanoTime64 startTime; // When the test started.
+ NanoTime64 endTime; // When the test ended.
+ pid_t replierPID; // PID of mDNS replier.
+ uint32_t ifIndex; // Index of interface to run the replier on.
+ unsigned int instanceCount; // Desired number of service instances.
+ unsigned int txtSize; // Desired size of each service instance's TXT record data.
+ unsigned int recordCountA; // Desired number of A records per replier hostname.
+ unsigned int recordCountAAAA; // Desired number of AAAA records per replier hostname.
+ unsigned int maxDropCount; // Replier's --maxDropCount option argument.
+ double ucastDropRate; // Replier's probability of dropping a unicast response.
+ double mcastDropRate; // Replier's probability of dropping a multicast query or response.
+ Boolean noAdditionals; // True if the replier is to not include additional records in responses.
+ Boolean useIPv4; // True if the replier is to use IPv4.
+ Boolean useIPv6; // True if the replier is to use IPv6.
+ Boolean flushedCache; // True if mDNSResponder's record cache was flushed before testing.
+ char * replierCommand; // Command used to run the replier.
+ char * serviceType; // Type of services to browse for.
+ ServiceBrowserRef browser; // Service browser.
+ unsigned int browseTimeSecs; // Amount of time to spend browsing in seconds.
+ const char * outputFilePath; // File to write test results to. If NULL, then write to stdout.
+ OutputFormatType outputFormat; // Format of test results output.
+ Boolean outputAppendNewline; // True if a newline character should be appended to JSON output.
+ char hostname[ 32 + 1 ]; // Base hostname that the replier is to use for instance and host names.
+ char tag[ 4 + 1 ]; // Tag that the replier is to use in its service types.
+
+} MDNSDiscoveryTestContext;
+
+static void _MDNSDiscoveryTestFirstQueryTimeout( void *inContext );
+static void DNSSD_API
+ _MDNSDiscoveryTestAboutQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static void
+ _MDNSDiscoveryTestServiceBrowserCallback(
+ ServiceBrowserResults * inResults,
+ OSStatus inError,
+ void * inContext );
+static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen );
+
+static void MDNSDiscoveryTestCmd( void )
+{
+ OSStatus err;
+ MDNSDiscoveryTestContext * context;
+ char queryName[ sizeof_field( MDNSDiscoveryTestContext, hostname ) + 15 ];
+
+ context = (MDNSDiscoveryTestContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ err = CheckIntegerArgument( gMDNSDiscoveryTest_InstanceCount, "instance count", 1, UINT16_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSDiscoveryTest_TXTSize, "TXT size", 1, UINT16_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSDiscoveryTest_BrowseTimeSecs, "browse time (seconds)", 1, INT_MAX );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountA, "A record count", 0, 64 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountAAAA, "AAAA record count", 0, 64 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckDoubleArgument( gMDNSDiscoveryTest_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckDoubleArgument( gMDNSDiscoveryTest_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
+ require_noerr_quiet( err, exit );
+
+ err = CheckIntegerArgument( gMDNSDiscoveryTest_MaxDropCount, "drop count", 0, 255 );
+ require_noerr_quiet( err, exit );
+
+ context->replierPID = -1;
+ context->instanceCount = (unsigned int) gMDNSDiscoveryTest_InstanceCount;
+ context->txtSize = (unsigned int) gMDNSDiscoveryTest_TXTSize;
+ context->browseTimeSecs = (unsigned int) gMDNSDiscoveryTest_BrowseTimeSecs;
+ context->recordCountA = (unsigned int) gMDNSDiscoveryTest_RecordCountA;
+ context->recordCountAAAA = (unsigned int) gMDNSDiscoveryTest_RecordCountAAAA;
+ context->ucastDropRate = gMDNSDiscoveryTest_UnicastDropRate;
+ context->mcastDropRate = gMDNSDiscoveryTest_MulticastDropRate;
+ context->maxDropCount = (unsigned int) gMDNSDiscoveryTest_MaxDropCount;
+ context->outputFilePath = gMDNSDiscoveryTest_OutputFilePath;
+ context->outputAppendNewline = gMDNSDiscoveryTest_OutputAppendNewline ? true : false;
+ context->noAdditionals = gMDNSDiscoveryTest_NoAdditionals ? true : false;
+ context->useIPv4 = ( gMDNSDiscoveryTest_UseIPv4 || !gMDNSDiscoveryTest_UseIPv6 ) ? true : false;
+ context->useIPv6 = ( gMDNSDiscoveryTest_UseIPv6 || !gMDNSDiscoveryTest_UseIPv4 ) ? true : false;
+
+ if( gMDNSDiscoveryTest_Interface )
+ {
+ err = InterfaceIndexFromArgString( gMDNSDiscoveryTest_Interface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_All, NULL, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+ }
+
+ err = OutputFormatFromArgString( gMDNSDiscoveryTest_OutputFormat, &context->outputFormat );
+ require_noerr_quiet( err, exit );
+
+ if( gMDNSDiscoveryTest_FlushCache )
+ {
+ err = CheckRootUser();
+ require_noerr_quiet( err, exit );
+
+ err = systemf( NULL, "killall -HUP mDNSResponder" );
+ require_noerr( err, exit );
+ sleep( 1 );
+ context->flushedCache = true;
+ }
+
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->hostname ) - 1,
+ context->hostname );
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->tag ) - 1, context->tag );
+
+ ASPrintF( &context->serviceType, "_t-%s-%u-%u._tcp", context->tag, context->txtSize, context->instanceCount );
+ require_action( context->serviceType, exit, err = kUnknownErr );
+
+ ASPrintF( &context->replierCommand,
+ "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount %u "
+ "--countA %u --countAAAA %u --udrop %.1f --mdrop %.1f --maxDropCount %u %?s%?s%?s",
+ (int64_t) getpid(),
+ context->ifIndex,
+ context->hostname,
+ context->tag,
+ context->instanceCount,
+ context->recordCountA,
+ context->recordCountAAAA,
+ context->ucastDropRate,
+ context->mcastDropRate,
+ context->maxDropCount,
+ context->noAdditionals, " --noAdditionals",
+ context->useIPv4, " --ipv4",
+ context->useIPv6, " --ipv6" );
+ require_action_quiet( context->replierCommand, exit, err = kUnknownErr );
+
+ err = SpawnCommand( &context->replierPID, "%s", context->replierCommand );
+ require_noerr_quiet( err, exit );
+
+ // Query for the replier's about TXT record. A response means it's fully up and running.
+
+ SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->hostname );
+ err = DNSServiceQueryRecord( &context->query, kDNSServiceFlagsForceMulticast, context->ifIndex, queryName,
+ kDNSServiceType_TXT, kDNSServiceClass_IN, _MDNSDiscoveryTestAboutQueryCallback, context );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->query, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ err = DispatchTimerCreate( dispatch_time_seconds( kMDNSDiscoveryTestFirstQueryTimeoutSecs ),
+ DISPATCH_TIME_FOREVER, UINT64_C_safe( kMDNSDiscoveryTestFirstQueryTimeoutSecs ) * kNanosecondsPerSecond / 10, NULL,
+ _MDNSDiscoveryTestFirstQueryTimeout, NULL, context, &context->queryTimer );
+ require_noerr( err, exit );
+ dispatch_resume( context->queryTimer );
+
+ context->startTime = NanoTimeGetCurrent();
+ dispatch_main();
+
+exit:
+ exit( 1 );
+}
+
+//===========================================================================================================================
+// _MDNSDiscoveryTestFirstQueryTimeout
+//===========================================================================================================================
+
+static void _MDNSDiscoveryTestFirstQueryTimeout( void *inContext )
+{
+ MDNSDiscoveryTestContext * const context = (MDNSDiscoveryTestContext *) inContext;
+
+ dispatch_source_forget( &context->queryTimer );
+
+ FPrintF( stderr, "error: Query for mdnsreplier's \"about\" TXT record timed out.\n" );
+ exit( 1 );
+}
+
+//===========================================================================================================================
+// _MDNSDiscoveryTestAboutQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _MDNSDiscoveryTestAboutQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ MDNSDiscoveryTestContext * const context = (MDNSDiscoveryTestContext *) inContext;
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inFullName );
+ Unused( inType );
+ Unused( inClass );
+ Unused( inRDataLen );
+ Unused( inRDataPtr );
+ Unused( inTTL );
+
+ err = inError;
+ require_noerr( err, exit );
+ require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
+
+ DNSServiceForget( &context->query );
+ dispatch_source_forget( &context->queryTimer );
+
+ err = ServiceBrowserCreate( dispatch_get_main_queue(), 0, "local.", context->browseTimeSecs, false, &context->browser );
+ require_noerr( err, exit );
+
+ err = ServiceBrowserAddServiceType( context->browser, context->serviceType );
+ require_noerr( err, exit );
+
+ ServiceBrowserSetCallback( context->browser, _MDNSDiscoveryTestServiceBrowserCallback, context );
+ ServiceBrowserStart( context->browser );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// _MDNSDiscoveryTestServiceBrowserCallback
+//===========================================================================================================================
+
+#define kMDNSDiscoveryTestResultsKey_ReplierInfo CFSTR( "replierInfo" )
+#define kMDNSDiscoveryTestResultsKey_StartTime CFSTR( "startTime" )
+#define kMDNSDiscoveryTestResultsKey_EndTime CFSTR( "endTime" )
+#define kMDNSDiscoveryTestResultsKey_BrowseTimeSecs CFSTR( "browseTimeSecs" )
+#define kMDNSDiscoveryTestResultsKey_ServiceType CFSTR( "serviceType" )
+#define kMDNSDiscoveryTestResultsKey_FlushedCache CFSTR( "flushedCache" )
+#define kMDNSDiscoveryTestResultsKey_UnexpectedInstances CFSTR( "unexpectedInstances" )
+#define kMDNSDiscoveryTestResultsKey_MissingInstances CFSTR( "missingInstances" )
+#define kMDNSDiscoveryTestResultsKey_IncorrectInstances CFSTR( "incorrectInstances" )
+#define kMDNSDiscoveryTestResultsKey_Success CFSTR( "success" )
+#define kMDNSDiscoveryTestResultsKey_TotalResolveTime CFSTR( "totalResolveTimeUs" )
+
+#define kMDNSDiscoveryTestReplierInfoKey_Command CFSTR( "command" )
+#define kMDNSDiscoveryTestReplierInfoKey_InstanceCount CFSTR( "instanceCount" )
+#define kMDNSDiscoveryTestReplierInfoKey_TXTSize CFSTR( "txtSize" )
+#define kMDNSDiscoveryTestReplierInfoKey_RecordCountA CFSTR( "recordCountA" )
+#define kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA CFSTR( "recordCountAAAA" )
+#define kMDNSDiscoveryTestReplierInfoKey_Hostname CFSTR( "hostname" )
+#define kMDNSDiscoveryTestReplierInfoKey_NoAdditionals CFSTR( "noAdditionals" )
+#define kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate CFSTR( "ucastDropRate" )
+#define kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate CFSTR( "mcastDropRate" )
+#define kMDNSDiscoveryTestReplierInfoKey_MaxDropCount CFSTR( "maxDropCount" )
+
+#define kMDNSDiscoveryTestUnexpectedInstanceKey_Name CFSTR( "name" )
+#define kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex CFSTR( "interfaceIndex" )
+
+#define kMDNSDiscoveryTestIncorrectInstanceKey_Name CFSTR( "name" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve CFSTR( "didResolve" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname CFSTR( "badHostname" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_BadPort CFSTR( "badPort" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT CFSTR( "badTXT" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs CFSTR( "unexpectedAddrs" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs CFSTR( "missingAddrs" )
+
+static void _MDNSDiscoveryTestServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
+{
+ OSStatus err;
+ MDNSDiscoveryTestContext * const context = (MDNSDiscoveryTestContext *) inContext;
+ const SBRDomain * domain;
+ const SBRServiceType * type;
+ const SBRServiceInstance * instance;
+ const SBRServiceInstance ** instanceArray = NULL;
+ const SBRIPAddress * ipaddr;
+ size_t hostnameLen;
+ const char * ptr;
+ const char * end;
+ unsigned int i;
+ uint32_t u32;
+ CFMutableArrayRef unexpectedInstances;
+ CFMutableArrayRef missingInstances;
+ CFMutableArrayRef incorrectInstances;
+ CFMutableDictionaryRef plist = NULL;
+ CFMutableDictionaryRef badDict = NULL;
+ CFMutableArrayRef unexpectedAddrs = NULL;
+ CFMutableArrayRef missingAddrs = NULL;
+ uint64_t maxResolveTimeUs;
+ int success = false;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+
+ context->endTime = NanoTimeGetCurrent();
+
+ err = inError;
+ require_noerr( err, exit );
+
+ _NanoTime64ToTimestamp( context->startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( context->endTime, endTime, sizeof( endTime ) );
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO="
+ "{"
+ "%kO=%s" // replierCommand
+ "%kO=%lli" // txtSize
+ "%kO=%lli" // instanceCount
+ "%kO=%lli" // recordCountA
+ "%kO=%lli" // recordCountAAAA
+ "%kO=%s" // hostname
+ "%kO=%b" // noAdditionals
+ "%kO=%f" // ucastDropRate
+ "%kO=%f" // mcastDropRate
+ "%kO=%i" // maxDropCount
+ "}"
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%lli" // browseTimeSecs
+ "%kO=%s" // serviceType
+ "%kO=%b" // flushedCache
+ "%kO=[%@]" // unexpectedInstances
+ "%kO=[%@]" // missingInstances
+ "%kO=[%@]" // incorrectInstances
+ "}",
+ kMDNSDiscoveryTestResultsKey_ReplierInfo,
+ kMDNSDiscoveryTestReplierInfoKey_Command, context->replierCommand,
+ kMDNSDiscoveryTestReplierInfoKey_InstanceCount, (int64_t) context->instanceCount,
+ kMDNSDiscoveryTestReplierInfoKey_TXTSize, (int64_t) context->txtSize,
+ kMDNSDiscoveryTestReplierInfoKey_RecordCountA, (int64_t) context->recordCountA,
+ kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA, (int64_t) context->recordCountAAAA,
+ kMDNSDiscoveryTestReplierInfoKey_Hostname, context->hostname,
+ kMDNSDiscoveryTestReplierInfoKey_NoAdditionals, context->noAdditionals,
+ kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate, context->ucastDropRate,
+ kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate, context->mcastDropRate,
+ kMDNSDiscoveryTestReplierInfoKey_MaxDropCount, context->maxDropCount,
+ kMDNSDiscoveryTestResultsKey_StartTime, startTime,
+ kMDNSDiscoveryTestResultsKey_EndTime, endTime,
+ kMDNSDiscoveryTestResultsKey_BrowseTimeSecs, (int64_t) context->browseTimeSecs,
+ kMDNSDiscoveryTestResultsKey_ServiceType, context->serviceType,
+ kMDNSDiscoveryTestResultsKey_FlushedCache, context->flushedCache,
+ kMDNSDiscoveryTestResultsKey_UnexpectedInstances, &unexpectedInstances,
+ kMDNSDiscoveryTestResultsKey_MissingInstances, &missingInstances,
+ kMDNSDiscoveryTestResultsKey_IncorrectInstances, &incorrectInstances );
+ require_noerr( err, exit );
+
+ for( domain = inResults->domainList; domain && ( strcasecmp( domain->name, "local." ) != 0 ); domain = domain->next ) {}
+ require_action( domain, exit, err = kInternalErr );
+
+ for( type = domain->typeList; type && ( strcasecmp( type->name, context->serviceType ) != 0 ); type = type->next ) {}
+ require_action( type, exit, err = kInternalErr );
+
+ instanceArray = (const SBRServiceInstance **) calloc( context->instanceCount, sizeof( *instanceArray ) );
+ require_action( instanceArray, exit, err = kNoMemoryErr );
+
+ hostnameLen = strlen( context->hostname );
+ for( instance = type->instanceList; instance; instance = instance->next )
+ {
+ unsigned int instanceNumber = 0;
+
+ if( strcmp_prefix( instance->name, context->hostname ) == 0 )
+ {
+ ptr = &instance->name[ hostnameLen ];
+ if( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ) )
+ {
+ ptr += 2;
+ for( end = ptr; isdigit_safe( *end ); ++end ) {}
+ if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
+ {
+ if( ( u32 >= 2 ) && ( u32 <= context->instanceCount ) && ( ptr[ 0 ] == ')' ) && ( ptr[ 1 ] == '\0' ) )
+ {
+ instanceNumber = u32;
+ }
+ }
+ }
+ else if( *ptr == '\0' )
+ {
+ instanceNumber = 1;
+ }
+ }
+ if( ( instanceNumber != 0 ) && ( instance->ifIndex == context->ifIndex ) )
+ {
+ check( !instanceArray[ instanceNumber - 1 ] );
+ instanceArray[ instanceNumber - 1 ] = instance;
+ }
+ else
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedInstances,
+ "{"
+ "%kO=%s"
+ "%kO=%lli"
+ "}",
+ kMDNSDiscoveryTestUnexpectedInstanceKey_Name, instance->name,
+ kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex, (int64_t) instance->ifIndex );
+ require_noerr( err, exit );
+ }
+ }
+
+ maxResolveTimeUs = 0;
+ for( i = 1; i <= context->instanceCount; ++i )
+ {
+ int isHostnameValid;
+ int isTXTValid;
+
+ instance = instanceArray[ i - 1 ];
+ if( !instance )
+ {
+ if( i == 1 )
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", context->hostname );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ char * instanceName = NULL;
+
+ ASPrintF( &instanceName, "%s (%u)", context->hostname, i );
+ require_action( instanceName, exit, err = kUnknownErr );
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", instanceName );
+ free( instanceName );
+ require_noerr( err, exit );
+ }
+ continue;
+ }
+
+ if( !instance->hostname )
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, incorrectInstances,
+ "{"
+ "%kO=%s"
+ "%kO=%b"
+ "}",
+ kMDNSDiscoveryTestIncorrectInstanceKey_Name, instance->name,
+ kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve, false );
+ require_noerr( err, exit );
+ continue;
+ }
+
+ badDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
+ require_action( badDict, exit, err = kNoMemoryErr );
+
+ isHostnameValid = false;
+ if( strcmp_prefix( instance->hostname, context->hostname ) == 0 )
+ {
+ ptr = &instance->hostname[ hostnameLen ];
+ if( i == 1 )
+ {
+ if( strcmp( ptr, ".local." ) == 0 ) isHostnameValid = true;
+ }
+ else if( *ptr == '-' )
+ {
+ ++ptr;
+ for( end = ptr; isdigit_safe( *end ); ++end ) {}
+ if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
+ {
+ if( ( u32 == i ) && ( strcmp( ptr, ".local." ) == 0 ) ) isHostnameValid = true;
+ }
+ }
+ }
+ if( !isHostnameValid )
+ {
+ err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname, instance->hostname,
+ kSizeCString );
+ require_noerr( err, exit );
+ }
+
+ if( instance->port != (uint16_t)( kMDNSReplierPortBase + context->txtSize ) )
+ {
+ err = CFDictionarySetInt64( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadPort, instance->port );
+ require_noerr( err, exit );
+ }
+
+ isTXTValid = false;
+ if( instance->txtLen == context->txtSize )
+ {
+ uint8_t name[ kDomainNameLengthMax ];
+
+ err = DomainNameFromString( name, instance->name, NULL );
+ require_noerr( err, exit );
+
+ err = DomainNameAppendString( name, type->name, NULL );
+ require_noerr( err, exit );
+
+ err = DomainNameAppendString( name, "local", NULL );
+ require_noerr( err, exit );
+
+ if( _MDNSDiscoveryTestTXTRecordIsValid( name, instance->txtPtr, instance->txtLen ) ) isTXTValid = true;
+ }
+ if( !isTXTValid )
+ {
+ char * hexStr = NULL;
+
+ ASPrintF( &hexStr, "%.4H", instance->txtPtr, (int) instance->txtLen, (int) instance->txtLen );
+ require_action( hexStr, exit, err = kUnknownErr );
+
+ err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT, hexStr, kSizeCString );
+ free( hexStr );
+ require_noerr( err, exit );
+ }
+
+ if( isHostnameValid )
+ {
+ uint64_t addrV4Bitmap, addrV6Bitmap, bitmask, resolveTimeUs;
+ unsigned int j;
+ uint8_t addrV4[ 4 ];
+ uint8_t addrV6[ 16 ];
+
+ if( context->recordCountA < 64 ) addrV4Bitmap = ( UINT64_C( 1 ) << context->recordCountA ) - 1;
+ else addrV4Bitmap = ~UINT64_C( 0 );
+
+ if( context->recordCountAAAA < 64 ) addrV6Bitmap = ( UINT64_C( 1 ) << context->recordCountAAAA ) - 1;
+ else addrV6Bitmap = ~UINT64_C( 0 );
+
+ addrV4[ 0 ] = 0;
+ WriteBig16( &addrV4[ 1 ], i );
+ addrV4[ 3 ] = 0;
+
+ memcpy( addrV6, kMDNSReplierBaseAddrV6, 16 );
+ WriteBig16( &addrV6[ 12 ], i );
+
+ unexpectedAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( unexpectedAddrs, exit, err = kNoMemoryErr );
+
+ resolveTimeUs = 0;
+ for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
+ {
+ const uint8_t * addrPtr;
+ unsigned int lsb;
+ int isAddrValid = false;
+
+ if( ipaddr->sip.sa.sa_family == AF_INET )
+ {
+ addrPtr = (const uint8_t *) &ipaddr->sip.v4.sin_addr.s_addr;
+ lsb = addrPtr[ 3 ];
+ if( ( memcmp( addrPtr, addrV4, 3 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountA ) )
+ {
+ bitmask = UINT64_C( 1 ) << ( lsb - 1 );
+ addrV4Bitmap &= ~bitmask;
+ isAddrValid = true;
+ }
+ }
+ else if( ipaddr->sip.sa.sa_family == AF_INET6 )
+ {
+ addrPtr = ipaddr->sip.v6.sin6_addr.s6_addr;
+ lsb = addrPtr[ 15 ];
+ if( ( memcmp( addrPtr, addrV6, 15 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountAAAA ) )
+ {
+ bitmask = UINT64_C( 1 ) << ( lsb - 1 );
+ addrV6Bitmap &= ~bitmask;
+ isAddrValid = true;
+ }
+ }
+ if( isAddrValid )
+ {
+ if( ipaddr->resolveTimeUs > resolveTimeUs ) resolveTimeUs = ipaddr->resolveTimeUs;
+ }
+ else
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedAddrs, "%##a", &ipaddr->sip );
+ require_noerr( err, exit );
+ }
+ }
+
+ resolveTimeUs += ( instance->discoverTimeUs + instance->resolveTimeUs );
+ if( resolveTimeUs > maxResolveTimeUs ) maxResolveTimeUs = resolveTimeUs;
+
+ if( CFArrayGetCount( unexpectedAddrs ) > 0 )
+ {
+ CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs, unexpectedAddrs );
+ }
+ ForgetCF( &unexpectedAddrs );
+
+ missingAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( missingAddrs, exit, err = kNoMemoryErr );
+
+ for( j = 1; addrV4Bitmap != 0; ++j )
+ {
+ bitmask = UINT64_C( 1 ) << ( j - 1 );
+ if( addrV4Bitmap & bitmask )
+ {
+ addrV4Bitmap &= ~bitmask;
+ addrV4[ 3 ] = (uint8_t) j;
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.4a", addrV4 );
+ require_noerr( err, exit );
+ }
+ }
+ for( j = 1; addrV6Bitmap != 0; ++j )
+ {
+ bitmask = UINT64_C( 1 ) << ( j - 1 );
+ if( addrV6Bitmap & bitmask )
+ {
+ addrV6Bitmap &= ~bitmask;
+ addrV6[ 15 ] = (uint8_t) j;
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.16a", addrV6 );
+ require_noerr( err, exit );
+ }
+ }
+
+ if( CFArrayGetCount( missingAddrs ) > 0 )
+ {
+ CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs, missingAddrs );
+ }
+ ForgetCF( &missingAddrs );
+ }
+
+ if( CFDictionaryGetCount( badDict ) > 0 )
+ {
+ err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_Name, instance->name,
+ kSizeCString );
+ require_noerr( err, exit );
+
+ CFDictionarySetBoolean( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve, true );
+ CFArrayAppendValue( incorrectInstances, badDict );
+ }
+ ForgetCF( &badDict );
+ }
+
+ if( ( CFArrayGetCount( unexpectedInstances ) == 0 ) &&
+ ( CFArrayGetCount( missingInstances ) == 0 ) &&
+ ( CFArrayGetCount( incorrectInstances ) == 0 ) )
+ {
+ err = CFDictionarySetInt64( plist, kMDNSDiscoveryTestResultsKey_TotalResolveTime, (int64_t) maxResolveTimeUs );
+ require_noerr( err, exit );
+ success = true;
+ }
+ else
+ {
+ success = false;
+ }
+ CFDictionarySetBoolean( plist, kMDNSDiscoveryTestResultsKey_Success, success );
+
+ err = OutputPropertyList( plist, context->outputFormat, context->outputFilePath );
+ require_noerr_quiet( err, exit );
+
+exit:
+ ForgetCF( &context->browser );
+ if( context->replierPID != -1 )
+ {
+ kill( context->replierPID, SIGTERM );
+ context->replierPID = -1;
+ }
+ FreeNullSafe( instanceArray );
+ CFReleaseNullSafe( plist );
+ CFReleaseNullSafe( badDict );
+ CFReleaseNullSafe( unexpectedAddrs );
+ CFReleaseNullSafe( missingAddrs );
+ exit( err ? 1 : ( success ? 0 : 2 ) );
+}
+
+//===========================================================================================================================
+// _MDNSDiscoveryTestTXTRecordIsValid
+//===========================================================================================================================
+
+static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen )
+{
+ uint32_t hash;
+ int n;
+ const uint8_t * ptr;
+ size_t i, wholeCount, remCount;
+ uint8_t txtStr[ 16 ];
+
+ if( inTXTLen == 0 ) return( false );
+
+ hash = _FNV1( inRecordName, DomainNameLength( inRecordName ) );
+
+ txtStr[ 0 ] = 15;
+ n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
+ check( n == 15 );
+
+ ptr = inTXTPtr;
+ wholeCount = inTXTLen / 16;
+ for( i = 0; i < wholeCount; ++i )
+ {
+ if( memcmp( ptr, txtStr, 16 ) != 0 ) return( false );
+ ptr += 16;
+ }
+
+ remCount = inTXTLen % 16;
+ if( remCount > 0 )
+ {
+ txtStr[ 0 ] = (uint8_t)( remCount - 1 );
+ if( memcmp( ptr, txtStr, remCount ) != 0 ) return( false );
+ ptr += remCount;
+ }
+ check( ptr == &inTXTPtr[ inTXTLen ] );
+ return( true );
+}
+
+//===========================================================================================================================
+// DotLocalTestCmd
+//===========================================================================================================================
+
+#define kDotLocalTestPreparationTimeLimitSecs 5
+#define kDotLocalTestSubtestDurationSecs 5
+
+// Constants for SRV record query subtest.
+
+#define kDotLocalTestSRV_Priority 1
+#define kDotLocalTestSRV_Weight 0
+#define kDotLocalTestSRV_Port 80
+#define kDotLocalTestSRV_TargetName ( (const uint8_t *) "\x03" "www" "\x07" "example" "\x03" "com" )
+#define kDotLocalTestSRV_TargetStr "www.example.com."
+#define kDotLocalTestSRV_ResultStr "1 0 80 " kDotLocalTestSRV_TargetStr
+
+typedef enum
+{
+ kDotLocalTestState_Unset = 0,
+ kDotLocalTestState_Preparing = 1,
+ kDotLocalTestState_GAIMDNSOnly = 2,
+ kDotLocalTestState_GAIDNSOnly = 3,
+ kDotLocalTestState_GAIBoth = 4,
+ kDotLocalTestState_GAINeither = 5,
+ kDotLocalTestState_GAINoSuchRecord = 6,
+ kDotLocalTestState_QuerySRV = 7,
+ kDotLocalTestState_Done = 8
+
+} DotLocalTestState;
+
+typedef struct
+{
+ const char * testDesc; // Description of the current subtest.
+ char * queryName; // Query name for GetAddrInfo or QueryRecord operation.
+ dispatch_source_t timer; // Timer used for limiting the time for each subtest.
+ NanoTime64 startTime; // Timestamp of when the subtest started.
+ NanoTime64 endTime; // Timestamp of when the subtest ended.
+ CFMutableArrayRef correctResults; // Operation results that were expected.
+ CFMutableArrayRef duplicateResults; // Operation results that were expected, but were already received.
+ CFMutableArrayRef unexpectedResults; // Operation results that were unexpected.
+ OSStatus error; // Subtest's error code.
+ uint32_t addrDNSv4; // If hasDNSv4 is true, the expected DNS IPv4 address for queryName.
+ uint32_t addrMDNSv4; // If hasMDNSv4 is true, the expected MDNS IPv4 address for queryName.
+ uint8_t addrDNSv6[ 16 ]; // If hasDNSv6 is true, the expected DNS IPv6 address for queryName.
+ uint8_t addrMDNSv6[ 16 ]; // If hasMDNSv6 is true, the expected MDNS IPv6 address for queryName.
+ Boolean hasDNSv4; // True if queryName has a DNS IPv4 address.
+ Boolean hasDNSv6; // True if queryName has a DNS IPv6 address.
+ Boolean hasMDNSv4; // True if queryName has an MDNS IPv4 address.
+ Boolean hasMDNSv6; // True if queryName has an MDNS IPv6 address.
+ Boolean needDNSv4; // True if operation is expecting, but hasn't received a DNS IPv4 result.
+ Boolean needDNSv6; // True if operation is expecting, but hasn't received a DNS IPv6 result.
+ Boolean needMDNSv4; // True if operation is expecting, but hasn't received an MDNS IPv4 result.
+ Boolean needMDNSv6; // True if operation is expecting, but hasn't received an MDNS IPv6 result.
+ Boolean needSRV; // True if operation is expecting, but hasn't received an SRV result.
+
+} DotLocalSubtest;
+
+typedef struct
+{
+ dispatch_source_t timer; // Timer used for limiting the time for each state/subtest.
+ DotLocalSubtest * subtest; // Current subtest's state.
+ DNSServiceRef connection; // Shared connection for DNS-SD operations.
+ DNSServiceRef op; // Reference for the current DNS-SD operation.
+ DNSServiceRef op2; // Reference for mdnsreplier probe query used during preparing state.
+ DNSRecordRef localSOARef; // Reference returned by DNSServiceRegisterRecord() for local. SOA record.
+ char * replierCmd; // Command used to invoke the mdnsreplier.
+ char * serverCmd; // Command used to invoke the test DNS server.
+ CFMutableArrayRef reportsGAI; // Reports for subtests that use DNSServiceGetAddrInfo.
+ CFMutableArrayRef reportsQuerySRV; // Reports for subtests that use DNSServiceQueryRecord for SRV records.
+ NanoTime64 startTime; // Timestamp for when the test started.
+ NanoTime64 endTime; // Timestamp for when the test ended.
+ DotLocalTestState state; // The test's current state.
+ pid_t replierPID; // PID of spawned mdnsreplier.
+ pid_t serverPID; // PID of spawned test DNS server.
+ uint32_t ifIndex; // Interface index used for mdnsreplier.
+ char * outputFilePath; // File to write test results to. If NULL, then write to stdout.
+ OutputFormatType outputFormat; // Format of test results output.
+ Boolean registeredSOA; // True if the dummy local. SOA record was successfully registered.
+ Boolean serverIsReady; // True if response was received for test DNS server probe query.
+ Boolean replierIsReady; // True if response was received for mdnsreplier probe query.
+ Boolean testFailed; // True if at least one subtest failed.
+ char labelStr[ 20 + 1 ]; // Unique label string used for for making the query names used by subtests.
+ // The format of this string is "dotlocal-test-<six random chars>".
+} DotLocalTestContext;
+
+static void _DotLocalTestStateMachine( DotLocalTestContext *inContext );
+static void DNSSD_API
+ _DotLocalTestProbeQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ _DotLocalTestRegisterRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSRecordRef inRecordRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ void * inContext );
+static void _DotLocalTestTimerHandler( void *inContext );
+static void DNSSD_API
+ _DotLocalTestGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ _DotLocalTestQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+
+static void DotLocalTestCmd( void )
+{
+ OSStatus err;
+ DotLocalTestContext * context;
+ uint8_t * rdataPtr;
+ size_t rdataLen;
+ DNSServiceFlags flags;
+ char queryName[ 64 ];
+ char randBuf[ 6 + 1 ]; // Large enough for four and six character random strings below.
+
+ context = (DotLocalTestContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->startTime = NanoTimeGetCurrent();
+ context->endTime = kNanoTime_Invalid;
+
+ context->state = kDotLocalTestState_Preparing;
+
+ if( gDotLocalTest_Interface )
+ {
+ err = InterfaceIndexFromArgString( gDotLocalTest_Interface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_All, NULL, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+ }
+
+ if( gDotLocalTest_OutputFilePath )
+ {
+ context->outputFilePath = strdup( gDotLocalTest_OutputFilePath );
+ require_action( context->outputFilePath, exit, err = kNoMemoryErr );
+ }
+
+ err = OutputFormatFromArgString( gDotLocalTest_OutputFormat, &context->outputFormat );
+ require_noerr_quiet( err, exit );
+
+ context->reportsGAI = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->reportsGAI, exit, err = kNoMemoryErr );
+
+ context->reportsQuerySRV = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->reportsQuerySRV, exit, err = kNoMemoryErr );
+
+ SNPrintF( context->labelStr, sizeof( context->labelStr ), "dotlocal-test-%s",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 6, randBuf ) );
+
+ // Spawn an mdnsreplier.
+
+ ASPrintF( &context->replierCmd,
+ "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount 2 --countA 1"
+ " --countAAAA 1",
+ (int64_t) getpid(), context->ifIndex, context->labelStr,
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 4, randBuf ) );
+ require_action_quiet( context->replierCmd, exit, err = kUnknownErr );
+
+ err = SpawnCommand( &context->replierPID, "%s", context->replierCmd );
+ require_noerr( err, exit );
+
+ // Spawn a test DNS server
+
+ ASPrintF( &context->serverCmd,
+ "dnssdutil server --loopback --follow %lld --port 0 --defaultTTL 300 --domain %s.local.",
+ (int64_t) getpid(), context->labelStr );
+ require_action_quiet( context->serverCmd, exit, err = kUnknownErr );
+
+ err = SpawnCommand( &context->serverPID, "%s", context->serverCmd );
+ require_noerr( err, exit );
+
+ // Create a shared DNS-SD connection.
+
+ err = DNSServiceCreateConnection( &context->connection );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->connection, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ // Create probe query for DNS server, i.e., query for any name that has an A record.
+
+ SNPrintF( queryName, sizeof( queryName ), "tag-dotlocal-test-probe.ipv4.%s.local.", context->labelStr );
+
+ flags = kDNSServiceFlagsShareConnection;
+#if( TARGET_OS_WATCH )
+ flags |= kDNSServiceFlagsPathEvaluationDone;
+#endif
+
+ context->op = context->connection;
+ err = DNSServiceQueryRecord( &context->op, flags, kDNSServiceInterfaceIndexAny, queryName, kDNSServiceType_A,
+ kDNSServiceClass_IN, _DotLocalTestProbeQueryRecordCallback, context );
+ require_noerr( err, exit );
+
+ // Create probe query for mdnsreplier's "about" TXT record.
+
+ SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->labelStr );
+
+ flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsForceMulticast;
+#if( TARGET_OS_WATCH )
+ flags |= kDNSServiceFlagsPathEvaluationDone;
+#endif
+
+ context->op2 = context->connection;
+ err = DNSServiceQueryRecord( &context->op2, flags, context->ifIndex, queryName, kDNSServiceType_TXT, kDNSServiceClass_IN,
+ _DotLocalTestProbeQueryRecordCallback, context );
+ require_noerr( err, exit );
+
+ // Register a dummy local. SOA record.
+
+ err = CreateSOARecordData( kRootLabel, kRootLabel, 1976040101, 1 * kSecondsPerDay, 2 * kSecondsPerHour,
+ 1000 * kSecondsPerHour, 2 * kSecondsPerDay, &rdataPtr, &rdataLen );
+ require_noerr( err, exit );
+
+ err = DNSServiceRegisterRecord( context->connection, &context->localSOARef, kDNSServiceFlagsUnique,
+ kDNSServiceInterfaceIndexLocalOnly, "local.", kDNSServiceType_SOA, kDNSServiceClass_IN, 1,
+ rdataPtr, 1 * kSecondsPerHour, _DotLocalTestRegisterRecordCallback, context );
+ require_noerr( err, exit );
+
+ // Start timer for probe responses and SOA record registration.
+
+ err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestPreparationTimeLimitSecs ),
+ INT64_C_safe( kDotLocalTestPreparationTimeLimitSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
+ _DotLocalTestTimerHandler, context, &context->timer );
+ require_noerr( err, exit );
+ dispatch_resume( context->timer );
+
+ dispatch_main();
+
+exit:
+ if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// _DotLocalTestStateMachine
+//===========================================================================================================================
+
+static OSStatus _DotLocalSubtestCreate( DotLocalSubtest **outSubtest );
+static void _DotLocalSubtestFree( DotLocalSubtest *inSubtest );
+static OSStatus _DotLocalTestStartSubtest( DotLocalTestContext *inContext );
+static OSStatus _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext );
+static void _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext ) ATTRIBUTE_NORETURN;
+
+static void _DotLocalTestStateMachine( DotLocalTestContext *inContext )
+{
+ OSStatus err;
+ DotLocalTestState nextState;
+
+ DNSServiceForget( &inContext->op );
+ DNSServiceForget( &inContext->op2 );
+ dispatch_source_forget( &inContext->timer );
+
+ switch( inContext->state )
+ {
+ case kDotLocalTestState_Preparing: nextState = kDotLocalTestState_GAIMDNSOnly; break;
+ case kDotLocalTestState_GAIMDNSOnly: nextState = kDotLocalTestState_GAIDNSOnly; break;
+ case kDotLocalTestState_GAIDNSOnly: nextState = kDotLocalTestState_GAIBoth; break;
+ case kDotLocalTestState_GAIBoth: nextState = kDotLocalTestState_GAINeither; break;
+ case kDotLocalTestState_GAINeither: nextState = kDotLocalTestState_GAINoSuchRecord; break;
+ case kDotLocalTestState_GAINoSuchRecord: nextState = kDotLocalTestState_QuerySRV; break;
+ case kDotLocalTestState_QuerySRV: nextState = kDotLocalTestState_Done; break;
+ default: err = kStateErr; goto exit;
+ }
+
+ if( inContext->state == kDotLocalTestState_Preparing )
+ {
+ if( !inContext->registeredSOA || !inContext->serverIsReady || !inContext->replierIsReady )
+ {
+ FPrintF( stderr, "Preparation timed out: Registered SOA? %s. Server ready? %s. mdnsreplier ready? %s.\n",
+ YesNoStr( inContext->registeredSOA ),
+ YesNoStr( inContext->serverIsReady ),
+ YesNoStr( inContext->replierIsReady ) );
+ err = kNotPreparedErr;
+ goto exit;
+ }
+ }
+ else
+ {
+ err = _DotLocalTestFinalizeSubtest( inContext );
+ require_noerr( err, exit );
+ }
+
+ inContext->state = nextState;
+ if( inContext->state == kDotLocalTestState_Done ) _DotLocalTestFinalizeAndExit( inContext );
+ err = _DotLocalTestStartSubtest( inContext );
+
+exit:
+ if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// _DotLocalSubtestCreate
+//===========================================================================================================================
+
+static OSStatus _DotLocalSubtestCreate( DotLocalSubtest **outSubtest )
+{
+ OSStatus err;
+ DotLocalSubtest * obj;
+
+ obj = (DotLocalSubtest *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->correctResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( obj->correctResults, exit, err = kNoMemoryErr );
+
+ obj->duplicateResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( obj->duplicateResults, exit, err = kNoMemoryErr );
+
+ obj->unexpectedResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( obj->unexpectedResults, exit, err = kNoMemoryErr );
+
+ *outSubtest = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _DotLocalSubtestFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _DotLocalSubtestFree
+//===========================================================================================================================
+
+static void _DotLocalSubtestFree( DotLocalSubtest *inSubtest )
+{
+ ForgetMem( &inSubtest->queryName );
+ ForgetCF( &inSubtest->correctResults );
+ ForgetCF( &inSubtest->duplicateResults );
+ ForgetCF( &inSubtest->unexpectedResults );
+ free( inSubtest );
+}
+
+//===========================================================================================================================
+// _DotLocalTestStartSubtest
+//===========================================================================================================================
+
+static OSStatus _DotLocalTestStartSubtest( DotLocalTestContext *inContext )
+{
+ OSStatus err;
+ DotLocalSubtest * subtest = NULL;
+ DNSServiceRef op = NULL;
+ DNSServiceFlags flags;
+
+ err = _DotLocalSubtestCreate( &subtest );
+ require_noerr( err, exit );
+
+ if( inContext->state == kDotLocalTestState_GAIMDNSOnly )
+ {
+ ASPrintF( &subtest->queryName, "%s-2.local.", inContext->labelStr );
+ require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+
+ subtest->hasMDNSv4 = subtest->needMDNSv4 = true;
+ subtest->hasMDNSv6 = subtest->needMDNSv6 = true;
+
+ subtest->addrMDNSv4 = htonl( 0x00000201 ); // 0.0.2.1
+ memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 ); // 2001:db8:2::2:1
+ subtest->addrMDNSv6[ 13 ] = 2;
+ subtest->addrMDNSv6[ 15 ] = 1;
+
+ subtest->testDesc = kDotLocalTestSubtestDesc_GAIMDNSOnly;
+ }
+
+ else if( inContext->state == kDotLocalTestState_GAIDNSOnly )
+ {
+ ASPrintF( &subtest->queryName, "tag-dns-only.%s.local.", inContext->labelStr );
+ require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+
+ subtest->hasDNSv4 = subtest->needDNSv4 = true;
+ subtest->hasDNSv6 = subtest->needDNSv6 = true;
+
+ subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 ); // 203.0.113.1
+ memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 ); // 2001:db8:1::1
+ subtest->addrDNSv6[ 15 ] = 1;
+
+ subtest->testDesc = kDotLocalTestSubtestDesc_GAIDNSOnly;
+ }
+
+ else if( inContext->state == kDotLocalTestState_GAIBoth )
+ {
+ ASPrintF( &subtest->queryName, "%s.local.", inContext->labelStr );
+ require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+
+ subtest->hasDNSv4 = subtest->needDNSv4 = true;
+ subtest->hasDNSv6 = subtest->needDNSv6 = true;
+ subtest->hasMDNSv4 = subtest->needMDNSv4 = true;
+ subtest->hasMDNSv6 = subtest->needMDNSv6 = true;
+
+ subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 ); // 203.0.113.1
+ memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 ); // 2001:db8:1::1
+ subtest->addrDNSv6[ 15 ] = 1;
+
+ subtest->addrMDNSv4 = htonl( 0x00000101 ); // 0.0.1.1
+ memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 ); // 2001:db8:2::1:1
+ subtest->addrMDNSv6[ 13 ] = 1;
+ subtest->addrMDNSv6[ 15 ] = 1;
+
+ subtest->testDesc = kDotLocalTestSubtestDesc_GAIBoth;
+ }
+
+ else if( inContext->state == kDotLocalTestState_GAINeither )
+ {
+ ASPrintF( &subtest->queryName, "doesnotexit-%s.local.", inContext->labelStr );
+ require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+
+ subtest->testDesc = kDotLocalTestSubtestDesc_GAINeither;
+ }
+
+ else if( inContext->state == kDotLocalTestState_GAINoSuchRecord )
+ {
+ ASPrintF( &subtest->queryName, "doesnotexit-dns.%s.local.", inContext->labelStr );
+ require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+
+ subtest->hasDNSv4 = subtest->needDNSv4 = true;
+ subtest->hasDNSv6 = subtest->needDNSv6 = true;
+ subtest->testDesc = kDotLocalTestSubtestDesc_GAINoSuchRecord;
+ }
+
+ else if( inContext->state == kDotLocalTestState_QuerySRV )
+ {
+ ASPrintF( &subtest->queryName, "_http._tcp.srv-%u-%u-%u.%s%s.local.",
+ kDotLocalTestSRV_Priority, kDotLocalTestSRV_Weight, kDotLocalTestSRV_Port, kDotLocalTestSRV_TargetStr,
+ inContext->labelStr );
+ require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+
+ subtest->needSRV = true;
+ subtest->testDesc = kDotLocalTestSubtestDesc_QuerySRV;
+ }
+
+ else
+ {
+ err = kStateErr;
+ goto exit;
+ }
+
+ // Start new operation.
+
+ flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
+#if( TARGET_OS_WATCH )
+ flags |= kDNSServiceFlagsPathEvaluationDone;
+#endif
+
+ subtest->startTime = NanoTimeGetCurrent();
+ subtest->endTime = kNanoTime_Invalid;
+
+ if( inContext->state == kDotLocalTestState_QuerySRV )
+ {
+ op = inContext->connection;
+ err = DNSServiceQueryRecord( &op, flags, kDNSServiceInterfaceIndexAny, subtest->queryName,
+ kDNSServiceType_SRV, kDNSServiceClass_IN, _DotLocalTestQueryRecordCallback, inContext );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ op = inContext->connection;
+ err = DNSServiceGetAddrInfo( &op, flags, kDNSServiceInterfaceIndexAny,
+ kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, subtest->queryName, _DotLocalTestGAICallback, inContext );
+ require_noerr( err, exit );
+ }
+
+ // Start timer.
+
+ check( !inContext->timer );
+ err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestSubtestDurationSecs ),
+ INT64_C_safe( kDotLocalTestSubtestDurationSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
+ _DotLocalTestTimerHandler, inContext, &inContext->timer );
+ require_noerr( err, exit );
+ dispatch_resume( inContext->timer );
+
+ check( !inContext->op );
+ inContext->op = op;
+ op = NULL;
+
+ check( !inContext->subtest );
+ inContext->subtest = subtest;
+ subtest = NULL;
+
+exit:
+ if( subtest ) _DotLocalSubtestFree( subtest );
+ if( op ) DNSServiceRefDeallocate( op );
+ return( err );
+}
+
+//===========================================================================================================================
+// _DotLocalTestFinalizeSubtest
+//===========================================================================================================================
+
+#define kDotLocalTestReportKey_StartTime CFSTR( "startTime" ) // String.
+#define kDotLocalTestReportKey_EndTime CFSTR( "endTime" ) // String.
+#define kDotLocalTestReportKey_Success CFSTR( "success" ) // Boolean.
+#define kDotLocalTestReportKey_MDNSReplierCmd CFSTR( "replierCmd" ) // String.
+#define kDotLocalTestReportKey_DNSServerCmd CFSTR( "serverCmd" ) // String.
+#define kDotLocalTestReportKey_GetAddrInfoTests CFSTR( "testsGAI" ) // Array of Dictionaries.
+#define kDotLocalTestReportKey_QuerySRVTests CFSTR( "testsQuerySRV" ) // Array of Dictionaries.
+#define kDotLocalTestReportKey_Description CFSTR( "description" ) // String.
+#define kDotLocalTestReportKey_QueryName CFSTR( "queryName" ) // String.
+#define kDotLocalTestReportKey_Error CFSTR( "error" ) // Integer.
+#define kDotLocalTestReportKey_Results CFSTR( "results" ) // Dictionary of Arrays.
+#define kDotLocalTestReportKey_CorrectResults CFSTR( "correct" ) // Array of Strings
+#define kDotLocalTestReportKey_DuplicateResults CFSTR( "duplicates" ) // Array of Strings.
+#define kDotLocalTestReportKey_UnexpectedResults CFSTR( "unexpected" ) // Array of Strings.
+#define kDotLocalTestReportKey_MissingResults CFSTR( "missing" ) // Array of Strings.
+
+static OSStatus _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext )
+{
+ OSStatus err;
+ DotLocalSubtest * subtest;
+ CFMutableDictionaryRef reportDict;
+ CFMutableDictionaryRef resultsDict;
+ CFMutableArrayRef missingResults, reportArray;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+
+ subtest = inContext->subtest;
+ inContext->subtest = NULL;
+
+ subtest->endTime = NanoTimeGetCurrent();
+ _NanoTime64ToTimestamp( subtest->startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( subtest->endTime, endTime, sizeof( endTime ) );
+
+ reportDict = NULL;
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &reportDict,
+ "{"
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%s" // queryName
+ "%kO=%s" // description
+ "%kO={%@}" // results
+ "}",
+ kDotLocalTestReportKey_StartTime, startTime,
+ kDotLocalTestReportKey_EndTime, endTime,
+ kDotLocalTestReportKey_QueryName, subtest->queryName,
+ kDotLocalTestReportKey_Description, subtest->testDesc,
+ kDotLocalTestReportKey_Results, &resultsDict );
+ require_noerr( err, exit );
+
+ missingResults = NULL;
+ switch( inContext->state )
+ {
+ case kDotLocalTestState_GAIMDNSOnly:
+ case kDotLocalTestState_GAIDNSOnly:
+ case kDotLocalTestState_GAIBoth:
+ case kDotLocalTestState_GAINeither:
+ if( subtest->needDNSv4 || subtest->needDNSv6 || subtest->needMDNSv4 || subtest->needMDNSv6 )
+ {
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
+ "["
+ "%.4a" // Expected DNS IPv4 address
+ "%.16a" // Expected DNS IPv6 address
+ "%.4a" // Expected MDNS IPv4 address
+ "%.16a" // Expected MDNS IPv6 address
+ "]",
+ subtest->needDNSv4 ? &subtest->addrDNSv4 : NULL,
+ subtest->needDNSv6 ? subtest->addrDNSv6 : NULL,
+ subtest->needMDNSv4 ? &subtest->addrMDNSv4 : NULL,
+ subtest->needMDNSv6 ? subtest->addrMDNSv6 : NULL );
+ require_noerr( err, exit );
+ }
+ break;
+
+ case kDotLocalTestState_QuerySRV:
+ if( subtest->needSRV )
+ {
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
+ "["
+ "%s" // Expected SRV record data as a string.
+ "]",
+ kDotLocalTestSRV_ResultStr );
+ require_noerr( err, exit );
+ }
+ break;
+
+ case kDotLocalTestState_GAINoSuchRecord:
+ if( subtest->needDNSv4 || subtest->needDNSv6 )
+ {
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
+ "["
+ "%s" // No Such Record (A)
+ "%s" // No Such Record (AAAA)
+ "]",
+ subtest->needDNSv4 ? kNoSuchRecordAStr : NULL,
+ subtest->needDNSv6 ? kNoSuchRecordAAAAStr : NULL );
+ require_noerr( err, exit );
+ }
+ break;
+
+ default:
+ err = kStateErr;
+ goto exit;
+ }
+
+ CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_CorrectResults, subtest->correctResults );
+
+ if( missingResults )
+ {
+ CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_MissingResults, missingResults );
+ ForgetCF( &missingResults );
+ if( !subtest->error ) subtest->error = kNotFoundErr;
+ }
+
+ if( CFArrayGetCount( subtest->unexpectedResults ) > 0 )
+ {
+ CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_UnexpectedResults, subtest->unexpectedResults );
+ if( !subtest->error ) subtest->error = kUnexpectedErr;
+ }
+
+ if( CFArrayGetCount( subtest->duplicateResults ) > 0 )
+ {
+ CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_DuplicateResults, subtest->duplicateResults );
+ if( !subtest->error ) subtest->error = kDuplicateErr;
+ }
+
+ if( subtest->error ) inContext->testFailed = true;
+ err = CFDictionarySetInt64( reportDict, kDotLocalTestReportKey_Error, subtest->error );
+ require_noerr( err, exit );
+
+ reportArray = ( inContext->state == kDotLocalTestState_QuerySRV ) ? inContext->reportsQuerySRV : inContext->reportsGAI;
+ CFArrayAppendValue( reportArray, reportDict );
+
+exit:
+ _DotLocalSubtestFree( subtest );
+ CFReleaseNullSafe( reportDict );
+ return( err );
+}
+
+//===========================================================================================================================
+// _DotLocalTestFinalizeAndExit
+//===========================================================================================================================
+
+static void _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext )
+{
+ OSStatus err;
+ CFPropertyListRef plist;
+ char timestampStart[ 32 ];
+ char timestampEnd[ 32 ];
+
+ check( !inContext->subtest );
+ inContext->endTime = NanoTimeGetCurrent();
+
+ if( inContext->replierPID != -1 )
+ {
+ kill( inContext->replierPID, SIGTERM );
+ inContext->replierPID = -1;
+ }
+ if( inContext->serverPID != -1 )
+ {
+ kill( inContext->serverPID, SIGTERM );
+ inContext->serverPID = -1;
+ }
+ err = DNSServiceRemoveRecord( inContext->connection, inContext->localSOARef, 0 );
+ require_noerr( err, exit );
+
+ _NanoTime64ToTimestamp( inContext->startTime, timestampStart, sizeof( timestampStart ) );
+ _NanoTime64ToTimestamp( inContext->endTime, timestampEnd, sizeof( timestampEnd ) );
+
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%O" // testsGAI
+ "%kO=%O" // testsQuerySRV
+ "%kO=%b" // success
+ "%kO=%s" // replierCmd
+ "%kO=%s" // serverCmd
+ "}",
+ kDotLocalTestReportKey_StartTime, timestampStart,
+ kDotLocalTestReportKey_EndTime, timestampEnd,
+ kDotLocalTestReportKey_GetAddrInfoTests, inContext->reportsGAI,
+ kDotLocalTestReportKey_QuerySRVTests, inContext->reportsQuerySRV,
+ kDotLocalTestReportKey_Success, inContext->testFailed ? false : true,
+ kDotLocalTestReportKey_MDNSReplierCmd, inContext->replierCmd,
+ kDotLocalTestReportKey_DNSServerCmd, inContext->serverCmd );
+ require_noerr( err, exit );
+
+ ForgetCF( &inContext->reportsGAI );
+ ForgetCF( &inContext->reportsQuerySRV );
+
+ err = OutputPropertyList( plist, inContext->outputFormat, inContext->outputFilePath );
+ CFRelease( plist );
+ require_noerr( err, exit );
+
+ exit( inContext->testFailed ? 2 : 0 );
+
+exit:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// _DotLocalTestProbeQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _DotLocalTestProbeQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
+
+ Unused( inInterfaceIndex );
+ Unused( inFullName );
+ Unused( inType );
+ Unused( inClass );
+ Unused( inRDataLen );
+ Unused( inRDataPtr );
+ Unused( inTTL );
+
+ check( context->state == kDotLocalTestState_Preparing );
+
+ require_quiet( ( inFlags & kDNSServiceFlagsAdd ) && !inError, exit );
+
+ if( inSDRef == context->op )
+ {
+ DNSServiceForget( &context->op );
+ context->serverIsReady = true;
+ }
+ else if( inSDRef == context->op2 )
+ {
+ DNSServiceForget( &context->op2 );
+ context->replierIsReady = true;
+ }
+
+ if( context->registeredSOA && context->serverIsReady && context->replierIsReady )
+ {
+ _DotLocalTestStateMachine( context );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _DotLocalTestRegisterRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _DotLocalTestRegisterRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSRecordRef inRecordRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ void * inContext )
+{
+ DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
+
+ Unused( inSDRef );
+ Unused( inRecordRef );
+ Unused( inFlags );
+
+ if( inError ) ErrQuit( 1, "error: local. SOA record registration failed: %#m\n", inError );
+
+ if( !context->registeredSOA )
+ {
+ context->registeredSOA = true;
+ if( context->serverIsReady && context->replierIsReady ) _DotLocalTestStateMachine( context );
+ }
+}
+
+//===========================================================================================================================
+// _DotLocalTestTimerHandler
+//===========================================================================================================================
+
+static void _DotLocalTestTimerHandler( void *inContext )
+{
+ _DotLocalTestStateMachine( (DotLocalTestContext *) inContext );
+}
+
+//===========================================================================================================================
+// _DotLocalTestGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _DotLocalTestGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
+ DotLocalSubtest * const subtest = context->subtest;
+ const sockaddr_ip * const sip = (const sockaddr_ip *) inSockAddr;
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inHostname );
+ Unused( inTTL );
+
+ require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
+ require_action_quiet( ( sip->sa.sa_family == AF_INET ) || ( sip->sa.sa_family == AF_INET6 ), exit, err = kTypeErr );
+
+ if( context->state == kDotLocalTestState_GAINoSuchRecord )
+ {
+ if( inError == kDNSServiceErr_NoSuchRecord )
+ {
+ CFMutableArrayRef array = NULL;
+ const char * noSuchRecordStr;
+
+ if( sip->sa.sa_family == AF_INET )
+ {
+ array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needDNSv4 = false;
+
+ noSuchRecordStr = kNoSuchRecordAStr;
+ }
+ else
+ {
+ array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needDNSv6 = false;
+
+ noSuchRecordStr = kNoSuchRecordAAAAStr;
+ }
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", noSuchRecordStr );
+ require_noerr( err, fatal );
+ }
+ else if( !inError )
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%##a", sip );
+ require_noerr( err, fatal );
+ }
+ else
+ {
+ err = inError;
+ goto exit;
+ }
+ }
+ else
+ {
+ if( !inError )
+ {
+ CFMutableArrayRef array = NULL;
+
+ if( sip->sa.sa_family == AF_INET )
+ {
+ const uint32_t addrV4 = sip->v4.sin_addr.s_addr;
+
+ if( subtest->hasDNSv4 && ( addrV4 == subtest->addrDNSv4 ) )
+ {
+ array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needDNSv4 = false;
+ }
+ else if( subtest->hasMDNSv4 && ( addrV4 == subtest->addrMDNSv4 ) )
+ {
+ array = subtest->needMDNSv4 ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needMDNSv4 = false;
+ }
+ }
+ else
+ {
+ const uint8_t * const addrV6 = sip->v6.sin6_addr.s6_addr;
+
+ if( subtest->hasDNSv6 && ( memcmp( addrV6, subtest->addrDNSv6, 16 ) == 0 ) )
+ {
+ array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needDNSv6 = false;
+ }
+ else if( subtest->hasMDNSv6 && ( memcmp( addrV6, subtest->addrMDNSv6, 16 ) == 0 ) )
+ {
+ array = subtest->needMDNSv6 ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needMDNSv6 = false;
+ }
+ }
+ if( !array ) array = subtest->unexpectedResults;
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%##a", sip );
+ require_noerr( err, fatal );
+ }
+ else if( inError == kDNSServiceErr_NoSuchRecord )
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%s",
+ ( sip->sa.sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr );
+ require_noerr( err, fatal );
+ }
+ else
+ {
+ err = inError;
+ goto exit;
+ }
+ }
+
+exit:
+ if( err )
+ {
+ subtest->error = err;
+ _DotLocalTestStateMachine( context );
+ }
+ return;
+
+fatal:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// _DotLocalTestQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _DotLocalTestQueryRecordCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ DotLocalTestContext * const context = (DotLocalTestContext *) inContext;
+ DotLocalSubtest * const subtest = context->subtest;
+ const dns_fixed_fields_srv * fields;
+ const uint8_t * target;
+ const uint8_t * ptr;
+ const uint8_t * end;
+ char * rdataStr;
+ unsigned int priority, weight, port;
+ CFMutableArrayRef array;
+
+ Unused( inSDRef );
+ Unused( inInterfaceIndex );
+ Unused( inFullName );
+ Unused( inTTL );
+
+ check( context->state == kDotLocalTestState_QuerySRV );
+
+ err = inError;
+ require_noerr_quiet( err, exit );
+ require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
+ require_action_quiet( ( inType == kDNSServiceType_SRV ) && ( inClass == kDNSServiceClass_IN ), exit, err = kTypeErr );
+ require_action_quiet( inRDataLen > sizeof( dns_fixed_fields_srv ), exit, err = kSizeErr );
+
+ fields = (const dns_fixed_fields_srv *) inRDataPtr;
+ priority = dns_fixed_fields_srv_get_priority( fields );
+ weight = dns_fixed_fields_srv_get_weight( fields );
+ port = dns_fixed_fields_srv_get_port( fields );
+ target = (const uint8_t *) &fields[ 1 ];
+ end = ( (const uint8_t *) inRDataPtr ) + inRDataLen;
+ for( ptr = target; ( ptr < end ) && ( *ptr != 0 ); ptr += ( 1 + *ptr ) ) {}
+
+ if( ( priority == kDotLocalTestSRV_Priority ) &&
+ ( weight == kDotLocalTestSRV_Weight ) &&
+ ( port == kDotLocalTestSRV_Port ) &&
+ ( ptr < end ) && DomainNameEqual( target, kDotLocalTestSRV_TargetName ) )
+ {
+ array = subtest->needSRV ? subtest->correctResults : subtest->duplicateResults;
+ subtest->needSRV = false;
+ }
+ else
+ {
+ array = subtest->unexpectedResults;
+ }
+
+ rdataStr = NULL;
+ DNSRecordDataToString( inRDataPtr, inRDataLen, kDNSServiceType_SRV, NULL, 0, &rdataStr );
+ if( !rdataStr )
+ {
+ ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, inRDataLen );
+ require_action( rdataStr, fatal, err = kNoMemoryErr );
+ }
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", rdataStr );
+ free( rdataStr );
+ require_noerr( err, fatal );
+
+exit:
+ if( err )
+ {
+ subtest->error = err;
+ _DotLocalTestStateMachine( context );
+ }
+ return;
+
+fatal:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// ProbeConflictTestCmd
+//===========================================================================================================================
+
+#define kProbeConflictTestService_DefaultName "pctest-name"
+#define kProbeConflictTestService_Port 60000
+
+#define kProbeConflictTestTXTPtr "\x13" "PROBE-CONFLICT-TEST"
+#define kProbeConflictTestTXTLen sizeof_string( kProbeConflictTestTXTPtr )
+
+typedef struct
+{
+ const char * description;
+ const char * program;
+ Boolean expectsRename;
+
+} ProbeConflictTestCase;
+
+#define kPCTProgPreWait "wait 1000;" // Wait 1 second before sending gratuitous response.
+#define kPCTProgPostWait "wait 8000;" // Wait 8 seconds after sending gratuitous response.
+ // This allows ~2.75 seconds for probing and ~5 seconds for a rename.
+
+static const ProbeConflictTestCase kProbeConflictTestCases[] =
+{
+ // No conflicts
+
+ { "No probe conflicts.", kPCTProgPreWait "probes n-n-n;" "send;" kPCTProgPostWait, false },
+
+ // One multicast probe conflict
+
+ { "One multicast probe conflict (1).", kPCTProgPreWait "probes m;" "send;" kPCTProgPostWait, false },
+ { "One multicast probe conflict (2).", kPCTProgPreWait "probes n-m;" "send;" kPCTProgPostWait, false },
+ { "One multicast probe conflict (3).", kPCTProgPreWait "probes n-n-m;" "send;" kPCTProgPostWait, false },
+
+ // One unicast probe conflict
+
+ { "One unicast probe conflict (1).", kPCTProgPreWait "probes u;" "send;" kPCTProgPostWait, true },
+ { "One unicast probe conflict (2).", kPCTProgPreWait "probes n-u;" "send;" kPCTProgPostWait, true },
+ { "One unicast probe conflict (3).", kPCTProgPreWait "probes n-n-u;" "send;" kPCTProgPostWait, true },
+
+ // One multicast and one unicast probe conflict
+
+ { "Multicast and unicast probe conflict (1).", kPCTProgPreWait "probes m-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (2).", kPCTProgPreWait "probes m-n-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (3).", kPCTProgPreWait "probes m-n-n-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (4).", kPCTProgPreWait "probes n-m-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (5).", kPCTProgPreWait "probes n-m-n-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (6).", kPCTProgPreWait "probes n-m-n-n-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (7).", kPCTProgPreWait "probes n-n-m-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (8).", kPCTProgPreWait "probes n-n-m-n-u;" "send;" kPCTProgPostWait, true },
+ { "Multicast and unicast probe conflict (9).", kPCTProgPreWait "probes n-n-m-n-n-u;" "send;" kPCTProgPostWait, true },
+
+ // Two multicast probe conflicts
+
+ { "Two multicast probe conflicts (1).", kPCTProgPreWait "probes m-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (2).", kPCTProgPreWait "probes m-n-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (3).", kPCTProgPreWait "probes m-n-n-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (4).", kPCTProgPreWait "probes n-m-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (5).", kPCTProgPreWait "probes n-m-n-m-n;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (6).", kPCTProgPreWait "probes n-m-n-n-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (7).", kPCTProgPreWait "probes n-n-m-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (8).", kPCTProgPreWait "probes n-n-m-n-m;" "send;" kPCTProgPostWait, true },
+ { "Two multicast probe conflicts (9).", kPCTProgPreWait "probes n-n-m-n-n-m;" "send;" kPCTProgPostWait, true },
+};
+
+#define kProbeConflictTestCaseCount countof( kProbeConflictTestCases )
+
+typedef struct
+{
+ DNSServiceRef registration; // Test service registration.
+ NanoTime64 testStartTime; // Test's start time.
+ NanoTime64 startTime; // Current test case's start time.
+ MDNSColliderRef collider; // mDNS collider object.
+ CFMutableArrayRef results; // Array of test case results.
+ char * serviceName; // Test service's instance name as a string. (malloced)
+ char * serviceType; // Test service's service type as a string. (malloced)
+ uint8_t * recordName; // FQDN of collider's record (same as test service's SRV+TXT records). (malloced)
+ unsigned int testCaseIndex; // Index of the current test case.
+ uint32_t ifIndex; // Index of the interface that the collider is to operate on.
+ char * outputFilePath; // File to write test results to. If NULL, then write to stdout. (malloced)
+ OutputFormatType outputFormat; // Format of test report output.
+ Boolean registered; // True if the test service instance is currently registered.
+ Boolean testFailed; // True if at least one test case failed.
+
+} ProbeConflictTestContext;
+
+static void DNSSD_API
+ _ProbeConflictTestRegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext );
+static void _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError );
+static OSStatus _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext );
+static OSStatus _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed );
+static void _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext ) ATTRIBUTE_NORETURN;
+
+static void ProbeConflictTestCmd( void )
+{
+ OSStatus err;
+ ProbeConflictTestContext * context;
+ const char * serviceName;
+ char tag[ 6 + 1 ];
+
+ context = (ProbeConflictTestContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ if( gProbeConflictTest_Interface )
+ {
+ err = InterfaceIndexFromArgString( gProbeConflictTest_Interface, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_All, NULL, &context->ifIndex );
+ require_noerr_quiet( err, exit );
+ }
+
+ if( gProbeConflictTest_OutputFilePath )
+ {
+ context->outputFilePath = strdup( gProbeConflictTest_OutputFilePath );
+ require_action( context->outputFilePath, exit, err = kNoMemoryErr );
+ }
+
+ err = OutputFormatFromArgString( gProbeConflictTest_OutputFormat, &context->outputFormat );
+ require_noerr_quiet( err, exit );
+
+ context->results = CFArrayCreateMutable( NULL, kProbeConflictTestCaseCount, &kCFTypeArrayCallBacks );
+ require_action( context->results, exit, err = kNoMemoryErr );
+
+ serviceName = gProbeConflictTest_UseComputerName ? NULL : kProbeConflictTestService_DefaultName;
+
+ ASPrintF( &context->serviceType, "_pctest-%s._udp",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+ require_action( context->serviceType, exit, err = kNoMemoryErr );
+
+ context->testStartTime = NanoTimeGetCurrent();
+ err = DNSServiceRegister( &context->registration, 0, context->ifIndex, serviceName, context->serviceType, "local.",
+ NULL, htons( kProbeConflictTestService_Port ), 0, NULL, _ProbeConflictTestRegisterCallback, context );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( context->registration, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ dispatch_main();
+
+exit:
+ exit( 1 );
+}
+
+//===========================================================================================================================
+// _ProbeConflictTestRegisterCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _ProbeConflictTestRegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext )
+{
+ OSStatus err;
+ ProbeConflictTestContext * const context = (ProbeConflictTestContext *) inContext;
+
+ Unused( inSDRef );
+ Unused( inType );
+ Unused( inDomain );
+
+ err = inError;
+ require_noerr( err, exit );
+
+ if( !context->registered )
+ {
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ uint8_t * ptr;
+ size_t recordNameLen;
+ unsigned int len;
+ uint8_t name[ kDomainNameLengthMax ];
+
+ context->registered = true;
+
+ FreeNullSafe( context->serviceName );
+ context->serviceName = strdup( inName );
+ require_action( context->serviceName, exit, err = kNoMemoryErr );
+
+ err = DomainNameFromString( name, context->serviceName, NULL );
+ require_noerr( err, exit );
+
+ err = DomainNameAppendString( name, context->serviceType, NULL );
+ require_noerr( err, exit );
+
+ err = DomainNameAppendString( name, "local", NULL );
+ require_noerr( err, exit );
+
+ ForgetMem( &context->recordName );
+ err = DomainNameDup( name, &context->recordName, &recordNameLen );
+ require_noerr( err, exit );
+ require_fatal( recordNameLen > 0, "Record name length is zero." ); // Prevents dubious static analyzer warning.
+
+ // Make the first label all caps so that it's easier to spot in system logs.
+
+ ptr = context->recordName;
+ for( len = *ptr++; len > 0; --len, ++ptr ) *ptr = (uint8_t) toupper_safe( *ptr );
+
+ err = _ProbeConflictTestStartNextTest( context );
+ require_noerr( err, exit );
+ }
+ }
+ else
+ {
+ if( !( inFlags & kDNSServiceFlagsAdd ) )
+ {
+ context->registered = false;
+ err = _ProbeConflictTestStopCurrentTest( context, true );
+ require_noerr( err, exit );
+ }
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// _ProbeConflictTestColliderStopHandler
+//===========================================================================================================================
+
+static void _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError )
+{
+ OSStatus err;
+ ProbeConflictTestContext * const context = (ProbeConflictTestContext *) inContext;
+
+ err = inError;
+ require_noerr_quiet( err, exit );
+
+ ForgetCF( &context->collider );
+
+ err = _ProbeConflictTestStopCurrentTest( context, false );
+ require_noerr( err, exit );
+
+ err = _ProbeConflictTestStartNextTest( context );
+ require_noerr( err, exit );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// _ProbeConflictTestStartNextTest
+//===========================================================================================================================
+
+static OSStatus _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext )
+{
+ OSStatus err;
+ const ProbeConflictTestCase * testCase;
+
+ check( !inContext->collider );
+
+ if( inContext->testCaseIndex < kProbeConflictTestCaseCount )
+ {
+ testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
+ }
+ else
+ {
+ _ProbeConflictTestFinalizeAndExit( inContext );
+ }
+
+ err = MDNSColliderCreate( dispatch_get_main_queue(), &inContext->collider );
+ require_noerr( err, exit );
+
+ err = MDNSColliderSetProgram( inContext->collider, testCase->program );
+ require_noerr( err, exit );
+
+ err = MDNSColliderSetRecord( inContext->collider, inContext->recordName, kDNSServiceType_TXT,
+ kProbeConflictTestTXTPtr, kProbeConflictTestTXTLen );
+ require_noerr( err, exit );
+
+ MDNSColliderSetProtocols( inContext->collider, kMDNSColliderProtocol_IPv4 );
+ MDNSColliderSetInterfaceIndex( inContext->collider, inContext->ifIndex );
+ MDNSColliderSetStopHandler( inContext->collider, _ProbeConflictTestColliderStopHandler, inContext );
+
+ inContext->startTime = NanoTimeGetCurrent();
+ err = MDNSColliderStart( inContext->collider );
+ require_noerr( err, exit );
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ProbeConflictTestStopCurrentTest
+//===========================================================================================================================
+
+#define kProbeConflictTestCaseResultKey_Description CFSTR( "description" )
+#define kProbeConflictTestCaseResultKey_StartTime CFSTR( "startTime" )
+#define kProbeConflictTestCaseResultKey_EndTime CFSTR( "endTime" )
+#define kProbeConflictTestCaseResultKey_ExpectedRename CFSTR( "expectedRename" )
+#define kProbeConflictTestCaseResultKey_ServiceName CFSTR( "serviceName" )
+#define kProbeConflictTestCaseResultKey_Passed CFSTR( "passed" )
+
+static OSStatus _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed )
+{
+ OSStatus err;
+ const ProbeConflictTestCase * testCase;
+ NanoTime64 now;
+ Boolean passed;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+
+ now = NanoTimeGetCurrent();
+
+ if( inContext->collider )
+ {
+ MDNSColliderSetStopHandler( inContext->collider, NULL, NULL );
+ MDNSColliderStop( inContext->collider );
+ CFRelease( inContext->collider );
+ inContext->collider = NULL;
+ }
+
+ testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
+ passed = ( ( testCase->expectsRename && inRenamed ) || ( !testCase->expectsRename && !inRenamed ) ) ? true : false;
+ if( !passed ) inContext->testFailed = true;
+
+ _NanoTime64ToTimestamp( inContext->startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, inContext->results,
+ "{"
+ "%kO=%s" // description
+ "%kO=%b" // expectedRename
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%s" // serviceName
+ "%kO=%b" // passed
+ "}",
+ kProbeConflictTestCaseResultKey_Description, testCase->description,
+ kProbeConflictTestCaseResultKey_ExpectedRename, testCase->expectsRename,
+ kProbeConflictTestCaseResultKey_StartTime, startTime,
+ kProbeConflictTestCaseResultKey_EndTime, endTime,
+ kProbeConflictTestCaseResultKey_ServiceName, inContext->serviceName,
+ kProbeConflictTestCaseResultKey_Passed, passed );
+ require_noerr( err, exit );
+
+ ++inContext->testCaseIndex;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ProbeConflictTestFinalizeAndExit
+//===========================================================================================================================
+
+#define kProbeConflictTestReportKey_StartTime CFSTR( "startTime" )
+#define kProbeConflictTestReportKey_EndTime CFSTR( "endTime" )
+#define kProbeConflictTestReportKey_ServiceType CFSTR( "serviceType" )
+#define kProbeConflictTestReportKey_Results CFSTR( "results" )
+#define kProbeConflictTestReportKey_Passed CFSTR( "passed" )
+
+static void _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext )
+{
+ OSStatus err;
+ CFPropertyListRef plist;
+ NanoTime64 now;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+
+ now = NanoTimeGetCurrent();
+
+ check( !inContext->collider );
+
+ _NanoTime64ToTimestamp( inContext->testStartTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%s" // serviceType
+ "%kO=%O" // results
+ "%kO=%b" // passed
+ "}",
+ kProbeConflictTestReportKey_StartTime, startTime,
+ kProbeConflictTestReportKey_EndTime, endTime,
+ kProbeConflictTestReportKey_ServiceType, inContext->serviceType,
+ kProbeConflictTestReportKey_Results, inContext->results,
+ kProbeConflictTestReportKey_Passed, inContext->testFailed ? false : true );
+ require_noerr( err, exit );
+ ForgetCF( &inContext->results );
+
+ err = OutputPropertyList( plist, inContext->outputFormat, inContext->outputFilePath );
+ CFRelease( plist );
+ require_noerr( err, exit );
+
+ exit( inContext->testFailed ? 2 : 0 );
+
+exit:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedsTestCmd
+//===========================================================================================================================
+
+#define NOTIFICATION_TIME_THRESHOLD 1500 // The maximum wating time allowed before notification happens
+#define TEST_REPETITION 2 // the number of repetition that one test has to passed
+#define LOOPBACK_INTERFACE_NAME "lo0"
+#define WIFI_TEST_QUESTION_NAME "www.example.com"
+#define EXPENSIVE_CONSTRAINED_MAX_RETRIES 1
+#define EXPENSIVE_CONSTRAINED_TEST_INTERVAL 5
+// Use "-n tag-expensive-test.ttl-86400.d.test." to run the test locally
+// #define LOOPBACK_TEST_QUESTION_NAME "tag-expensive-test.ttl-86400.d.test."
+
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_START_TIME CFSTR( "Start Time" )
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_END_TIME CFSTR( "End Time" )
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_ALL_PASSED CFSTR( "All Tests Passed" )
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_SUBTEST_RESULT CFSTR( "Subtest Results" )
+
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_START_TIME CFSTR( "Start Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_END_TIME CFSTR( "End Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_QNAME CFSTR( "Question Name" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_FLAGS CFSTR( "DNS Service Flags" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_PROTOCOLS CFSTR( "Protocols" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_INDEX CFSTR( "Interface Index" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_NAME CFSTR( "Interface Name" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_RESULT CFSTR( "Result" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_ERROR CFSTR( "Error Description" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_TEST_PROGRESS CFSTR( "Test Progress" )
+
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_START_TIME CFSTR( "Start Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_END_TIME CFSTR( "End Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_STATE CFSTR( "State" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPECT_RESULT CFSTR( "Expected Result" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_ACTUAL_RESULT CFSTR( "Actual Result" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPENSIVE_PREV_NOW CFSTR( "Expensive Prev->Now" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CONSTRAINED_PREV_NOW CFSTR( "Constrained Prev->Now" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CALL_BACK CFSTR( "Call Back" )
+
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_TIMESTAMP CFSTR( "Timestamp" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_NAME CFSTR( "Answer Name" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_FLAGS CFSTR( "Add or Remove" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_INTERFACE CFSTR( "Interface Index" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_ADDRESS CFSTR( "Address" )
+
+// All the states that ends with _PREPARE represents the state where the test state is reset and initialized.
+enum ExpensiveConstrainedTestState
+{
+ TEST_BEGIN,
+ TEST_EXPENSIVE_PREPARE,
+ TEST_EXPENSIVE, // Test if mDNSResponder can handle "expensive" status change of the corresponding interface
+ TEST_CONSTRAINED_PREPARE,
+ TEST_CONSTRAINED, // Test if mDNSResponder can handle "constrained" status change of the corresponding interface
+ TEST_EXPENSIVE_CONSTRAINED_PREPARE,
+ TEST_EXPENSIVE_CONSTRAINED, // Test if mDNSResponder can handle "expensive" and "constrained" status change of the corresponding interface at the same time
+ TEST_FAILED,
+ TEST_SUCCEEDED
+};
+enum ExpensiveConstrainedTestOperation
+{
+ RESULT_ADD, // received response for the given query, which means mDNSResponder is able to send out the query over the interface, because the interface status is changed.
+ RESULT_RMV, // received negative response for the given query, which means mDNSResponder is not able to send out the query over the interface, because the interface status is changed.
+ NO_UPDATE // no status update notification
+};
+
+typedef struct
+{
+ uint32_t subtestIndex; // The index of parameter for the subtest
+ DNSServiceRef opRef; // sdRef for the DNSServiceGetAddrInfo operation.
+ const char * name; // Hostname to resolve.
+ DNSServiceFlags flags; // Flags argument for DNSServiceGetAddrInfo().
+ DNSServiceProtocol protocols; // Protocols argument for DNSServiceGetAddrInfo().
+ uint32_t ifIndex; // Interface index argument for DNSServiceGetAddrInfo().
+ char ifName[IFNAMSIZ]; // Interface name for the given interface index.
+ dispatch_source_t timer; // The test will check if the current behavior is valid, which is called by
+ // the timer per 2s.
+ pid_t serverPID;
+ Boolean isExpensivePrev; // If the interface is expensive in the previous test step.
+ Boolean isExpensiveNow; // If the interface is expensive now.
+ Boolean isConstrainedPrev; // If the interface is constrained in the previous test step.
+ Boolean isConstrainedNow; // If the interface is constrained now.
+ Boolean startFromExpensive; // All the test will start from expensive/constrained interface, so there won's be an answer until the interface is changed.
+ uint8_t numOfRetries; // the number of retries we can have if the test fail
+ struct timeval updateTime; // The time when interface status(expensive or constrained) is changed.
+ struct timeval notificationTime; // The time when callback function, which is passed to DNSServiceGetAddrInfo, gets called.
+ uint32_t counter; // To record how many times the test has repeated.
+ enum ExpensiveConstrainedTestState state; // The current test state.
+ enum ExpensiveConstrainedTestOperation expectedOperation; // the test expects this kind of notification
+ enum ExpensiveConstrainedTestOperation operation; // represents what notification the callback function gets.
+
+ NanoTime64 testReport_startTime; // when the entire test starts
+ CFMutableArrayRef subtestReport; // stores the log message for every subtest
+ NanoTime64 subtestReport_startTime; // when the subtest starts
+ CFMutableArrayRef subtestProgress; // one test iteration
+ NanoTime64 subtestProgress_startTime; // when the test iteration starts
+ CFMutableArrayRef subtestProgress_callBack; // array of ADD/REMOVE events
+ char * outputFilePath; // File to write test results to. If NULL, then write to stdout. (malloced)
+ OutputFormatType outputFormat; // Format of test report output.
+} ExpensiveConstrainedContext;
+
+// structure that controls how the subtest is run
+typedef struct
+{
+ const char *qname; // the name of the query, when the ends with ".d.test.", test will send query to local DNS server
+ Boolean deny_expensive; // if the query should avoid using expensive interface
+ Boolean deny_constrained; // if the query should avoid using constrained interface
+ Boolean start_from_expensive; // if the query should starts from using an expensive interface
+ Boolean ipv4_query; // only allow IPv4 query
+ Boolean ipv6_query; // only allow IPv6 query
+ int8_t test_passed; // if the subtest passes
+} ExpensiveConstrainedTestParams;
+
+static ExpensiveConstrainedTestParams ExpensiveConstrainedSubtestParams[] =
+{
+// qname deny_expensive deny_constrained start_from_expensive ipv4_query ipv6_query
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, false, false, true, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, false, true, true, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", false, true, false, true, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", false, true, true, true, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, true, false, true, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, true, true, true, true, -1},
+// IPv4 Only
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, false, false, true, false, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, false, true, true, false, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", false, true, false, true, false, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", false, true, true, true, false, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, true, false, true, false, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, true, true, true, false, -1},
+// IPv6 Only
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, false, false, false, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, false, true, false, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", false, true, false, false, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", false, true, true, false, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, true, false, false, true, -1},
+ {"tag-expensive_constrained-test.ttl-86400.d.test.", true, true, true, false, true, -1}
+};
+
+static void ExpensiveConstrainedSetupLocalDNSServer( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedStartTestHandler( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedStopTestHandler( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedSetupTimer( ExpensiveConstrainedContext *context, uint32_t second );
+static void ExpensiveConstrainedTestTimerEventHandler( ExpensiveConstrainedContext *context );
+static void DNSSD_API
+ ExpensiveConstrainedCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+static void ExpensiveConstrainedInitializeContext( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedStopAndCleanTheTest( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedSubtestProgressReport( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedSubtestReport( ExpensiveConstrainedContext *context, const char *error_description );
+static void ExpensiveConstrainedFinalResultReport( ExpensiveConstrainedContext *context, Boolean allPassed );
+static const char *ExpensiveConstrainedProtocolString(DNSServiceProtocol protocol);
+static const char *ExpensiveConstrainedStateString(enum ExpensiveConstrainedTestState state);
+static const char *ExpensiveConstrainedOperationString(enum ExpensiveConstrainedTestOperation operation);
+static Boolean expensiveConstrainedEndsWith( const char *str, const char *suffix );
+
+//===========================================================================================================================
+// ExpensiveConstrainedTestCmd
+//===========================================================================================================================
+static void ExpensiveConstrainedTestCmd( void )
+{
+ OSStatus err;
+ dispatch_source_t signalSource = NULL;
+ ExpensiveConstrainedContext * context = NULL;
+
+ // Set up SIGINT handler.
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // create the test context
+ context = (ExpensiveConstrainedContext *) calloc( 1, sizeof(*context) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ // get the command line option
+ err = OutputFormatFromArgString( gExpensiveConstrainedTest_OutputFormat, &context->outputFormat );
+ require_noerr_quiet( err, exit );
+ if ( gExpensiveConstrainedTest_OutputFilePath )
+ {
+ context->outputFilePath = strdup( gExpensiveConstrainedTest_OutputFilePath );
+ require_noerr_quiet( context->outputFilePath, exit );
+ }
+
+ // initialize context
+ context->subtestIndex = 0;
+ context->numOfRetries = EXPENSIVE_CONSTRAINED_MAX_RETRIES;
+
+ // initialize the CFArray used to store the log
+ context->subtestReport = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ context->testReport_startTime = NanoTimeGetCurrent();
+
+ // setup local DNS server
+ ExpensiveConstrainedSetupLocalDNSServer( context );
+
+ ExpensiveConstrainedStartTestHandler( context );
+
+ dispatch_main();
+
+exit:
+ exit( 1 );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedSetupLocalDNSServer
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSetupLocalDNSServer( ExpensiveConstrainedContext *context )
+{
+ pid_t current_pid = getpid();
+ OSStatus err = SpawnCommand( &context->serverPID, "dnssdutil server -l --follow %d", current_pid );
+ if (err != 0)
+ {
+ FPrintF( stdout, "dnssdutil server -l --follow <PID> failed, error: %d\n", err );
+ exit( 1 );
+ }
+ sleep(2);
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedStartTestHandler
+//===========================================================================================================================
+
+static void ExpensiveConstrainedStartTestHandler( ExpensiveConstrainedContext *context )
+{
+ // setup 3s timer
+ ExpensiveConstrainedSetupTimer( context, EXPENSIVE_CONSTRAINED_TEST_INTERVAL );
+
+ // set the event handler for the 3s timer
+ dispatch_source_set_event_handler( context->timer, ^{
+ ExpensiveConstrainedTestTimerEventHandler( context );
+ } );
+
+ dispatch_resume( context->timer );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedStartTestHandler
+//===========================================================================================================================
+
+static void ExpensiveConstrainedStopTestHandler( ExpensiveConstrainedContext *context )
+{
+ dispatch_cancel( context->timer );
+ dispatch_release( context->timer );
+ context->timer = NULL;
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedSetupTimer
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSetupTimer( ExpensiveConstrainedContext *context, uint32_t second )
+{
+ // set the timer source, the event handler will be called for every "second" seconds
+ context->timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue() );
+ if ( context->timer == NULL )
+ {
+ FPrintF( stdout, "dispatch_source_create:DISPATCH_SOURCE_TYPE_TIMER failed\n" );
+ exit( 1 );
+ }
+ // the first block will be put into the queue "second"s after calling dispatch_resume
+ dispatch_source_set_timer( context->timer, dispatch_time( DISPATCH_TIME_NOW, second * NSEC_PER_SEC ),
+ (unsigned long long)(second) * NSEC_PER_SEC, 100ull * NSEC_PER_MSEC );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedTestTimerEventHandler
+//===========================================================================================================================
+
+static void ExpensiveConstrainedTestTimerEventHandler( ExpensiveConstrainedContext *context )
+{
+ OSStatus err;
+ char buffer[ 1024 ];
+ const char *errorDescription = NULL;
+
+ // do not log the state if we are in transition state
+ if (context->state != TEST_BEGIN
+ && context->state != TEST_SUCCEEDED
+ && context->state != TEST_CONSTRAINED_PREPARE
+ && context->state != TEST_EXPENSIVE_CONSTRAINED_PREPARE)
+ ExpensiveConstrainedSubtestProgressReport( context );
+
+ switch ( context->state ) {
+ case TEST_BEGIN:
+ {
+ ExpensiveConstrainedStopTestHandler( context );
+
+ // clear mDNSResponder cache
+ err = systemf( NULL, "killall -HUP mDNSResponder" );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed");
+
+ // initialize the global parameters
+ ExpensiveConstrainedInitializeContext( context );
+
+ // The local DNS server is set up on the local only interface.
+ gExpensiveConstrainedTest_Interface = LOOPBACK_INTERFACE_NAME;
+ strncpy( context->ifName, gExpensiveConstrainedTest_Interface, sizeof( context->ifName ) );
+
+ // The local DNS server is unscoped, so we must set our question to unscoped.
+ context->ifIndex = kDNSServiceInterfaceIndexAny;
+
+ // The question name must end with "d.test.", "tag-expensive-test.ttl-86400.d.test." for example, then the test will
+ // use the local dns server set up previously to run the test locally.
+ require_action( gExpensiveConstrainedTest_Name != NULL && expensiveConstrainedEndsWith( gExpensiveConstrainedTest_Name, "d.test." ), test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "The question name (%s) must end with \"d.test.\".\n", gExpensiveConstrainedTest_Name );
+ errorDescription = buffer );
+
+ // get the quesion name
+ context->name = gExpensiveConstrainedTest_Name;
+
+ // set the initial state for the interface
+ context->startFromExpensive = gExpensiveConstrainedTest_StartFromExpensive;
+ err = systemf( NULL, "ifconfig %s %sexpensive && ifconfig %s -constrained", context->ifName, context->startFromExpensive ? "" : "-", context->ifName );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed");
+ sleep( 5 ); // wait for 5s to allow the interface change event de delivered to others
+
+ // get question flag
+ if ( gExpensiveConstrainedTest_DenyExpensive ) context->flags |= kDNSServiceFlagsDenyExpensive;
+ if ( gExpensiveConstrainedTest_DenyConstrained ) context->flags |= kDNSServiceFlagsDenyConstrained;
+ if ( gExpensiveConstrainedTest_ProtocolIPv4 ) context->protocols |= kDNSServiceProtocol_IPv4;
+ if ( gExpensiveConstrainedTest_ProtocolIPv6 ) context->protocols |= kDNSServiceProtocol_IPv6;
+
+ // prevent mDNSResponder from doing extra path evaluation and changing the interface to others(such as Bluetooth)
+ #if( TARGET_OS_WATCH )
+ context->flags |= kDNSServiceFlagsPathEvaluationDone;
+ #endif
+
+ // start the query
+ DNSServiceGetAddrInfo( &context->opRef, context->flags, context->ifIndex, context->protocols, context->name, ExpensiveConstrainedCallback, context );
+
+ // set the initial test status
+ context->subtestReport_startTime = NanoTimeGetCurrent();
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->state = TEST_EXPENSIVE_PREPARE; // start from expensive test
+ context->isExpensiveNow = context->startFromExpensive ? true : false;
+ context->isConstrainedNow = false;
+ context->expectedOperation = context->isExpensiveNow && ( context->flags & kDNSServiceFlagsDenyExpensive ) ? NO_UPDATE : RESULT_ADD;
+ context->operation = NO_UPDATE;
+ context->subtestProgress = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks);
+ require_action( context->subtestProgress != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks);
+ require_action( context->subtestProgress != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ // set the queue where the callback will be called when there is an answer for the query
+ err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+ require_noerr( err, test_failed );
+
+ ExpensiveConstrainedStartTestHandler( context );
+ }
+ break;
+ case TEST_EXPENSIVE_PREPARE:
+ require_action( context->isConstrainedNow == false, test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "Interface %s should be unconstrained.\n", context->ifName );
+ errorDescription = buffer );
+ require_action( context->expectedOperation == context->operation, test_failed,
+ errorDescription = "Operation is not expected" );
+
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->state = TEST_EXPENSIVE; // begin to test expensive flag
+ context->counter = 0; // the number of test repetition that has passed
+ context->isExpensivePrev = context->isExpensiveNow;
+ context->isExpensiveNow = !context->isExpensiveNow; // flip the expensive status
+ context->isConstrainedPrev = false; // the interface is currently unconstrained
+ context->isConstrainedNow = false; // the interface will be unconstrained in the current test
+ if ( gExpensiveConstrainedTest_DenyExpensive )
+ context->expectedOperation = context->isExpensiveNow ? RESULT_RMV : RESULT_ADD;
+ else
+ context->expectedOperation = NO_UPDATE;
+ context->operation = NO_UPDATE; // NO_UPDATE means the call back function has not been called
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ err = systemf( NULL, "ifconfig %s %sexpensive", context->ifName, context->isExpensiveNow ? "" : "-" );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ // record the starting timestamp
+ gettimeofday( &context->updateTime, NULL );
+
+ break;
+ case TEST_EXPENSIVE:
+ // Since we are testing expensive flag, we should always turn the expensive flag on and off.
+ require_action( context->isExpensivePrev ^ context->isExpensiveNow, test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "The current expensive status should be different with the previous one: %d -> %d\n", context->isExpensivePrev, context->isExpensiveNow);
+ errorDescription = buffer );
+ // constrained flag is always turned off when testing expensive
+ require_action( context->isConstrainedNow == false, test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "The interface %s should be unconstrained when testing \"expensive\"\n", context->ifName );
+ errorDescription = buffer );
+ require_action( context->expectedOperation == context->operation, test_failed, errorDescription = "Operation is not expected" );
+
+ context->counter++; // one test repetition has passed
+ if ( context->counter == TEST_REPETITION ) // expensive test finished
+ {
+ // prepare to test constrained flag
+ context->state = TEST_CONSTRAINED_PREPARE;
+
+ // reset the interface
+ err = systemf( NULL, "ifconfig %s -expensive && ifconfig %s -constrained", context->ifName, context->ifName );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ context->isExpensiveNow = false;
+ context->isConstrainedNow = false;
+ gettimeofday( &context->updateTime, NULL );
+ }
+ else
+ {
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->isExpensivePrev = context->isExpensiveNow;
+ context->isExpensiveNow = !context->isExpensiveNow; // flip the expensive status
+ if ( gExpensiveConstrainedTest_DenyExpensive )
+ context->expectedOperation = context->isExpensiveNow ? RESULT_RMV : RESULT_ADD;
+ else
+ context->expectedOperation = NO_UPDATE;
+ context->operation = NO_UPDATE;
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ err = systemf( NULL, "ifconfig %s %sexpensive", context->ifName, context->isExpensiveNow ? "" : "-" );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ gettimeofday( &context->updateTime, NULL );
+ }
+ break;
+ case TEST_CONSTRAINED_PREPARE:
+ // The interface should be inexpensive and unconstrained when the constrained test starts
+ require_action( context->isExpensiveNow == false, test_failed, SNPrintF( buffer, sizeof( buffer ), "Interface %s should be inexpensive.", context->ifName );
+ errorDescription = buffer );
+ require_action( context->isConstrainedNow == false, test_failed, SNPrintF( buffer, sizeof( buffer ), "Interface %s should be unconstrained.\n", context->ifName );
+ errorDescription = buffer );
+
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->state = TEST_CONSTRAINED; // constrained interface is now under testing
+ context->counter = 0;
+ context->isExpensivePrev = false;
+ context->isExpensiveNow = false;
+ context->isConstrainedPrev = false;
+ context->isConstrainedNow = true; // will set constrained flag on the interface
+ if ( gExpensiveConstrainedTest_DenyConstrained )
+ context->expectedOperation = RESULT_RMV;
+ else
+ context->expectedOperation = NO_UPDATE;
+ context->operation = NO_UPDATE;
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ // change interface to the constrained one
+ err = systemf( NULL, "ifconfig %s -expensive && ifconfig %s constrained", context->ifName, context->ifName );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ gettimeofday( &context->updateTime, NULL );
+ break;
+ case TEST_CONSTRAINED:
+ // Since we are testing constrained flag, we should always turn the constrained flag on and off.
+ require_action( context->isConstrainedPrev ^ context->isConstrainedNow, test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "The current constrained status should be different with the previous one: %d -> %d\n", context->isConstrainedPrev, context->isConstrainedNow );
+ errorDescription = buffer );
+ require_action( context->isExpensiveNow == false, test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "The interface %s should be inexpensive when testing \"constrained\"\n", context->ifName );
+ errorDescription = buffer );
+ require_action( context->expectedOperation == context->operation, test_failed, errorDescription = "Operation is not expected");
+
+ context->counter++;
+ if (context->counter == TEST_REPETITION)
+ {
+ // test changing expensive and constrained flags at the same time
+ context->state = TEST_EXPENSIVE_CONSTRAINED_PREPARE;
+
+ // reset interface
+ err = systemf( NULL, "ifconfig %s -expensive && ifconfig %s -constrained", context->ifName, context->ifName );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ context->isExpensiveNow = false;
+ context->isConstrainedNow = false;
+ gettimeofday( &context->updateTime, NULL );
+ }
+ else
+ {
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->isConstrainedPrev = context->isConstrainedNow;
+ context->isConstrainedNow = !context->isConstrainedNow; // flip constrained flag
+ if ( gExpensiveConstrainedTest_DenyConstrained )
+ context->expectedOperation = context->isConstrainedNow ? RESULT_RMV : RESULT_ADD;
+ else
+ context->expectedOperation = NO_UPDATE;
+ context->operation = NO_UPDATE;
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ err = systemf( NULL, "ifconfig %s %sconstrained", context->ifName, context->isConstrainedNow ? "" : "-" );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ gettimeofday(&context->updateTime, NULL);
+ }
+ break;
+ case TEST_EXPENSIVE_CONSTRAINED_PREPARE:
+ // The interface should be inexpensive and unconstrained when the constrained test starts
+ require_action( context->isExpensiveNow == false, test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "Interface %s should be inexpensive.\n", context->ifName );
+ errorDescription = buffer );
+ require_action( context->isConstrainedNow == false, test_failed,
+ SNPrintF(buffer, sizeof( buffer ), "Interface %s should be unconstrained.\n", context->ifName );
+ errorDescription = buffer );
+
+ // now flip expensive and constrained at the same time
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->state = TEST_EXPENSIVE_CONSTRAINED;
+ context->counter = 0;
+ context->isExpensivePrev = false;
+ context->isExpensiveNow = true;
+ context->isConstrainedPrev = false;
+ context->isConstrainedNow = true;
+ if (gExpensiveConstrainedTest_DenyConstrained || gExpensiveConstrainedTest_DenyExpensive)
+ context->expectedOperation = RESULT_RMV;
+ else
+ context->expectedOperation = NO_UPDATE;
+ context->operation = NO_UPDATE;
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ err = systemf(NULL, "ifconfig %s expensive && ifconfig %s constrained", context->ifName, context->ifName );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ gettimeofday( &context->updateTime, NULL );
+ break;
+ case TEST_EXPENSIVE_CONSTRAINED:
+ // expensive and constrained flag should always be changed
+ require_action( ( context->isExpensivePrev ^ context->isExpensiveNow ) && ( context->isConstrainedPrev ^ context->isConstrainedNow ), test_failed,
+ SNPrintF( buffer, sizeof( buffer ), "Both expensive and constrained status need to be changed" );
+ errorDescription = buffer );
+ require_action( context->isExpensiveNow == context->isConstrainedNow, test_failed, errorDescription = "context->isExpensiveNow != context->isConstrainedNow" );
+ require_action( context->expectedOperation == context->operation, test_failed, errorDescription = "Operation is not expected" );
+
+ context->counter++;
+ if ( context->counter == TEST_REPETITION )
+ {
+ context->state = TEST_SUCCEEDED;
+ }
+ else
+ {
+ context->subtestProgress_startTime = NanoTimeGetCurrent();
+ context->isExpensivePrev = context->isExpensiveNow;
+ context->isExpensiveNow = !context->isExpensiveNow;
+ context->isConstrainedPrev = context->isConstrainedNow;
+ context->isConstrainedNow = !context->isConstrainedNow;
+ if (gExpensiveConstrainedTest_DenyConstrained || gExpensiveConstrainedTest_DenyExpensive)
+ context->expectedOperation = context->isExpensiveNow ? RESULT_RMV : RESULT_ADD;
+ else
+ context->expectedOperation = NO_UPDATE;
+ context->operation = NO_UPDATE;
+ context->subtestProgress_callBack = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+ err = systemf( NULL, "ifconfig %s %sexpensive && ifconfig %s %sconstrained", context->ifName, context->isExpensiveNow ? "" : "-", context->ifName, context->isConstrainedNow ? "" : "-" );
+ require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+ gettimeofday( &context->updateTime, NULL );
+ }
+ break;
+ case TEST_FAILED:
+ test_failed:
+ ExpensiveConstrainedSubtestReport( context, errorDescription );
+ ExpensiveConstrainedStopAndCleanTheTest( context );
+ if ( context->numOfRetries > 0 )
+ {
+ context->state = TEST_BEGIN;
+ context->numOfRetries--;
+ break;
+ }
+ ExpensiveConstrainedSubtestParams[context->subtestIndex++].test_passed = 0;
+ if (context->subtestIndex == (int) countof( ExpensiveConstrainedSubtestParams ))
+ {
+ ExpensiveConstrainedFinalResultReport( context, false );
+ exit( 2 );
+ }
+ if (context->timer == NULL)
+ {
+ // If timer is NULL, it means that we encounter error before we set up the test handler, which is unrecoverable.
+ ExpensiveConstrainedFinalResultReport( context, false );
+ exit( 1 );
+ }
+ context->state = TEST_BEGIN;
+ break;
+ case TEST_SUCCEEDED:
+ ExpensiveConstrainedSubtestReport( context, NULL );
+ ExpensiveConstrainedStopAndCleanTheTest( context );
+ ExpensiveConstrainedSubtestParams[context->subtestIndex++].test_passed = 1;
+ if (context->subtestIndex == (int) countof( ExpensiveConstrainedSubtestParams ))
+ {
+ // all the subtests have been run
+ Boolean hasFailed = false;
+ for ( int i = 0; i < (int) countof( ExpensiveConstrainedSubtestParams ) && !hasFailed; i++ )
+ hasFailed = ( ExpensiveConstrainedSubtestParams[i].test_passed != 1 );
+
+ ExpensiveConstrainedFinalResultReport( context, !hasFailed );
+ exit( hasFailed ? 2 : 0 );
+ }
+ context->state = TEST_BEGIN;
+ break;
+ default:
+ FPrintF( stdout, "unknown error\n" );
+ exit( 1 );
+ }
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ ExpensiveConstrainedCallback(
+ __unused DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ __unused uint32_t inTTL,
+ void * inContext )
+{
+ ExpensiveConstrainedContext * const context = (ExpensiveConstrainedContext *)inContext;
+ OSStatus err;
+ const char * addrStr;
+ char addrStrBuf[ kSockAddrStringMaxSize ];
+ char inFlagsDescription[ 128 ];
+ NanoTime64 now;
+ char nowTimestamp[ 32 ];
+
+ switch ( inError ) {
+ case kDNSServiceErr_NoError:
+ case kDNSServiceErr_NoSuchRecord:
+ break;
+
+ case kDNSServiceErr_Timeout:
+ Exit( kExitReason_Timeout );
+
+ default:
+ err = inError;
+ goto exit;
+ }
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ err = kTypeErr;
+ goto exit;
+ }
+
+ if( !inError )
+ {
+ err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
+ require_noerr( err, exit );
+ addrStr = addrStrBuf;
+ }
+ else
+ {
+ addrStr = ( inSockAddr->sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr;
+ }
+
+ now = NanoTimeGetCurrent();
+ _NanoTime64ToTimestamp( now, nowTimestamp, sizeof( nowTimestamp ) );
+ SNPrintF( inFlagsDescription, sizeof( inFlagsDescription ), "%{du:cbflags}", inFlags );
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestProgress_callBack,
+ "{"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%lli"
+ "%kO=%s"
+ "}",
+ EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_TIMESTAMP, nowTimestamp,
+ EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_NAME, inHostname,
+ EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_FLAGS, inFlagsDescription,
+ EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_INTERFACE, (int64_t) inInterfaceIndex,
+ EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_ADDRESS, addrStr
+ );
+ require_noerr_quiet( err, exit );
+
+ if ( inFlags & kDNSServiceFlagsMoreComing )
+ return;
+
+ if ( inFlags & kDNSServiceFlagsAdd )
+ context->operation = RESULT_ADD;
+ else
+ context->operation = RESULT_RMV;
+
+ gettimeofday(&context->notificationTime, NULL);
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedInitializeContext
+//===========================================================================================================================
+
+static void ExpensiveConstrainedInitializeContext( ExpensiveConstrainedContext *context )
+{
+ // clear the flags of the previous subtest
+ context->flags = 0;
+ context->protocols = 0;
+
+ // get the parameter for the current subtest
+ const ExpensiveConstrainedTestParams *param = &ExpensiveConstrainedSubtestParams[context->subtestIndex];
+ gExpensiveConstrainedTest_Name = param->qname;
+ gExpensiveConstrainedTest_DenyExpensive = param->deny_expensive;
+ gExpensiveConstrainedTest_DenyConstrained = param->deny_constrained;
+ gExpensiveConstrainedTest_StartFromExpensive = param->start_from_expensive;
+ gExpensiveConstrainedTest_ProtocolIPv4 = param->ipv4_query;
+ gExpensiveConstrainedTest_ProtocolIPv6 = param->ipv6_query;
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedStopAndCleanTheTest
+//===========================================================================================================================
+
+static void ExpensiveConstrainedStopAndCleanTheTest( ExpensiveConstrainedContext *context )
+{
+ // Stop the ongoing query
+ if ( context->opRef != NULL )
+ DNSServiceRefDeallocate( context->opRef );
+
+ context->opRef = NULL;
+ context->flags = 0;
+ context->protocols = 0;
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedSubtestProgressReport
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSubtestProgressReport( ExpensiveConstrainedContext *context )
+{
+ OSStatus err;
+ NanoTime64 now;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+ char expensive[ 32 ];
+ char constrained[ 32 ];
+
+ now = NanoTimeGetCurrent();
+ _NanoTime64ToTimestamp( context->subtestProgress_startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+ snprintf( expensive, sizeof( expensive ), "%s -> %s", context->isExpensivePrev ? "True" : "False", context->isExpensiveNow ? "True" : "False" );
+ snprintf( constrained, sizeof( constrained ), "%s -> %s", context->isConstrainedPrev ? "True" : "False", context->isConstrainedNow ? "True" : "False" );
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestProgress,
+ "{"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%O"
+ "}",
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_START_TIME, startTime,
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_END_TIME, endTime,
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_STATE, ExpensiveConstrainedStateString(context->state),
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPECT_RESULT, ExpensiveConstrainedOperationString(context->expectedOperation),
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_ACTUAL_RESULT, ExpensiveConstrainedOperationString(context->operation),
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPENSIVE_PREV_NOW, expensive,
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CONSTRAINED_PREV_NOW, constrained,
+ EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CALL_BACK, context->subtestProgress_callBack
+ );
+ require_noerr( err, exit );
+ ForgetCF( &context->subtestProgress_callBack );
+ return;
+
+exit:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedFinalSubtestReport
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSubtestReport( ExpensiveConstrainedContext *context, const char *error_description )
+{
+ OSStatus err;
+ NanoTime64 now;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+ char flagDescription[ 1024 ];
+
+ now = NanoTimeGetCurrent();
+ _NanoTime64ToTimestamp( context->subtestReport_startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+ SNPrintF( flagDescription, sizeof( flagDescription ), "%#{flags}", context->flags, kDNSServiceFlagsDescriptors );
+
+ if (error_description != NULL)
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestReport,
+ "{"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%lli"
+ "%kO=%s"
+ "%kO=%O"
+ "%kO=%s"
+ "%kO=%O"
+ "}",
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_START_TIME, startTime,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_END_TIME, endTime,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_QNAME, context->name,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_FLAGS, flagDescription,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_PROTOCOLS, ExpensiveConstrainedProtocolString( context->protocols ),
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_INDEX, (int64_t) context->ifIndex,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_NAME, context->ifName,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_RESULT, CFSTR( "Fail" ),
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_ERROR, error_description,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_TEST_PROGRESS, context->subtestProgress
+ );
+ }
+ else
+ {
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestReport,
+ "{"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%lli"
+ "%kO=%s"
+ "%kO=%O"
+ "%kO=%O"
+ "}",
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_START_TIME, startTime,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_END_TIME, endTime,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_QNAME, context->name,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_FLAGS, flagDescription,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_PROTOCOLS, ExpensiveConstrainedProtocolString( context->protocols ),
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_INDEX, (int64_t) context->ifIndex,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_NAME, context->ifName,
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_RESULT, CFSTR( "Pass" ),
+ EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_TEST_PROGRESS, context->subtestProgress
+ );
+ }
+
+ require_noerr( err, exit );
+ ForgetCF( &context->subtestProgress );
+ return;
+exit:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedFinalResultReport
+//===========================================================================================================================
+
+static void ExpensiveConstrainedFinalResultReport( ExpensiveConstrainedContext *context, Boolean allPassed )
+{
+ OSStatus err;
+ CFPropertyListRef plist;
+ NanoTime64 now;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+
+ now = NanoTimeGetCurrent();
+ _NanoTime64ToTimestamp( context->testReport_startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO=%s"
+ "%kO=%s"
+ "%kO=%b"
+ "%kO=%O"
+ "}",
+ EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_START_TIME, startTime,
+ EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_END_TIME, endTime,
+ EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_ALL_PASSED, allPassed,
+ EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_SUBTEST_RESULT, context->subtestReport
+ );
+ require_noerr( err, exit );
+ ForgetCF( &context->subtestReport );
+
+ err = OutputPropertyList( plist, context->outputFormat, context->outputFilePath );
+ CFRelease( plist );
+ require_noerr( err, exit );
+
+ return;
+exit:
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedProtocolString
+//===========================================================================================================================
+
+static const char *ExpensiveConstrainedProtocolString( DNSServiceProtocol protocol )
+{
+ const char *str = NULL;
+ switch ( protocol ) {
+ case kDNSServiceProtocol_IPv4:
+ str = "IPv4";
+ break;
+ case kDNSServiceProtocol_IPv6:
+ str = "IPv6";
+ break;
+ case kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6:
+ str = "IPv4 & IPv6";
+ break;
+ default:
+ break;
+ }
+ return str;
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedStateString
+//===========================================================================================================================
+
+static const char *ExpensiveConstrainedStateString( enum ExpensiveConstrainedTestState state )
+{
+ const char *str = NULL;
+ switch ( state ) {
+ case TEST_BEGIN:
+ str = "TEST_BEGIN";
+ break;
+ case TEST_EXPENSIVE_PREPARE:
+ str = "TEST_EXPENSIVE_PREPARE";
+ break;
+ case TEST_EXPENSIVE:
+ str = "TEST_EXPENSIVE";
+ break;
+ case TEST_CONSTRAINED_PREPARE:
+ str = "TEST_CONSTRAINED_PREPARE";
+ break;
+ case TEST_CONSTRAINED:
+ str = "TEST_CONSTRAINED";
+ break;
+ case TEST_EXPENSIVE_CONSTRAINED_PREPARE:
+ str = "TEST_EXPENSIVE_CONSTRAINED_PREPARE";
+ break;
+ case TEST_EXPENSIVE_CONSTRAINED:
+ str = "TEST_EXPENSIVE_CONSTRAINED";
+ break;
+ case TEST_FAILED:
+ str = "TEST_FAILED";
+ break;
+ case TEST_SUCCEEDED:
+ str = "TEST_SUCCEEDED";
+ break;
+ default:
+ str = "UNKNOWN";
+ break;
+ }
+
+ return str;
+}
+
+//===========================================================================================================================
+// ExpensiveConstrainedOperationString
+//===========================================================================================================================
+
+static const char *ExpensiveConstrainedOperationString( enum ExpensiveConstrainedTestOperation operation )
+{
+ const char *str = NULL;
+ switch ( operation ) {
+ case RESULT_ADD:
+ str = "RESULT_ADD";
+ break;
+ case RESULT_RMV:
+ str = "RESULT_RMV";
+ break;
+ case NO_UPDATE:
+ str = "NO_UPDATE";
+ break;
+ default:
+ str = "UNKNOWN";
+ break;
+ }
+ return str;
+}
+
+//===========================================================================================================================
+// expensiveConstrainedEndsWith
+//===========================================================================================================================
+static Boolean expensiveConstrainedEndsWith( const char *str, const char *suffix )
+{
+ if ( !str || !suffix )
+ return false;
+ size_t lenstr = strlen( str );
+ size_t lensuffix = strlen( suffix );
+ if ( lensuffix > lenstr )
+ return false;
+ return strncmp( str + lenstr - lensuffix, suffix, lensuffix ) == 0;
+}
+
+//===========================================================================================================================
+// RegistrationTestCmd
+//===========================================================================================================================
+
+typedef struct RegistrationSubtest RegistrationSubtest;
+
+typedef struct
+{
+ CFMutableArrayRef subtestReports; // Array of subtest reports.
+ dispatch_source_t timer; // Timer to enforce subtest durations.
+ dispatch_source_t sigSourceINT; // SIGINT signal handler for a clean test exit.
+ dispatch_source_t sigSourceTERM; // SIGTERM signal handler for a clean test exit.
+ RegistrationSubtest * subtest; // Current subtest.
+ char * outputFilePath; // Path of test result output file. If NULL, stdout will be used.
+ OutputFormatType outputFormat; // Format of test results output.
+ CFStringRef computerNamePrev; // Previous ComputerName.
+ CFStringRef localHostNamePrev; // Previous LocalHostName.
+ NanoTime64 startTime; // Test's start time.
+ char * computerName; // Temporary ComputerName to set during testing. (malloc'd)
+ char * localHostName; // Temporary LocalHostName to set during testing. (malloc'd)
+ CFStringEncoding computerNamePrevEncoding; // Previous ComputerName's encoding.
+ int subtestIndex; // Index of current subtest.
+ Boolean computerNameSet; // True if a temporary ComputerName was set.
+ Boolean localHostNameSet; // True if a temporary LocalHostName was set.
+ Boolean failed; // True if at least one non-skipped subtest failed.
+ Boolean forBATS; // True if the test is running in a BATS environment.
+
+} RegistrationTest;
+
+typedef enum
+{
+ kRegistrationInterfaceSet_Null = 0,
+ kRegistrationInterfaceSet_All = 1,
+ kRegistrationInterfaceSet_AllPlusAWDL = 2,
+ kRegistrationInterfaceSet_LoopbackOnly = 3,
+ kRegistrationInterfaceSet_AWDLOnly = 4
+
+} RegistrationInterfaceSet;
+
+typedef struct
+{
+ RegistrationInterfaceSet interfaceSet; // Interfaces to register the service over.
+ Boolean useDefaultName; // True if registration is to use the default service name.
+ Boolean useLODiscovery; // True if discovery is to use kDNSServiceInterfaceIndexLocalOnly.
+
+} RegistrationSubtestParams;
+
+static const RegistrationSubtestParams kRegistrationSubtestParams[] =
+{
+ { kRegistrationInterfaceSet_All, true, false },
+ { kRegistrationInterfaceSet_All, false, false },
+ { kRegistrationInterfaceSet_AllPlusAWDL, true, false },
+ { kRegistrationInterfaceSet_AllPlusAWDL, false, false },
+ { kRegistrationInterfaceSet_LoopbackOnly, true, false },
+ { kRegistrationInterfaceSet_LoopbackOnly, false, false },
+ { kRegistrationInterfaceSet_AWDLOnly, true, false },
+ { kRegistrationInterfaceSet_AWDLOnly, false, false },
+ { kRegistrationInterfaceSet_All, true, true },
+ { kRegistrationInterfaceSet_All, false, true },
+ { kRegistrationInterfaceSet_AllPlusAWDL, true, true },
+ { kRegistrationInterfaceSet_AllPlusAWDL, false, true },
+ { kRegistrationInterfaceSet_LoopbackOnly, true, true },
+ { kRegistrationInterfaceSet_LoopbackOnly, false, true },
+ { kRegistrationInterfaceSet_AWDLOnly, true, true },
+ { kRegistrationInterfaceSet_AWDLOnly, false, true }
+};
+
+typedef struct
+{
+ NanoTime64 browseResultTime; // Per-interface browse result time.
+ NanoTime64 querySRVResultTime; // Per-interface SRV record query result time.
+ NanoTime64 queryTXTResultTime; // Per-interface TXT record query result time.
+
+} RegistrationResultTimes;
+
+typedef struct
+{
+ MDNSInterfaceItem base; // Underlying MDNSInterface linked-list item.
+ RegistrationResultTimes times; // Per-interface result times.
+
+} RegistrationInterfaceItem;
+
+struct RegistrationSubtest
+{
+ DNSServiceRef registration; // DNS-SD service registration.
+ DNSServiceRef connection; // Shared DNS-SD connection.
+ DNSServiceRef browse; // DNS-SD browse for service's type.
+ DNSServiceRef querySRV; // DNS-SD query request for service's SRV record.
+ DNSServiceRef queryTXT; // DNS-SD query request for service's TXT record.
+ CFMutableArrayRef unexpected; // Array of unexpected registration, browse, and query results.
+#if( TARGET_OS_WATCH )
+ CFMutableArrayRef ignored; // Array of unexpected, but ignored, browse and query results.
+#endif
+ const char * serviceName; // Service's name.
+ char * serviceNameCustom; // Service's name if using a custom name. (malloc'd)
+ char * serviceType; // Service's service type. (malloc'd)
+ size_t serviceTypeLen; // C string length of service's service type.
+ char * serviceFQDN; // Service's FQDN, i.e., name of its SRV and TXT records.
+ uint8_t * txtPtr; // Pointer to service's TXT record data. (malloc'd)
+ size_t txtLen; // Length of service's TXT record data.
+ RegistrationInterfaceItem * ifList; // If ifIndex == 0, interfaces that service should register over.
+ RegistrationResultTimes ifTimes; // If ifIndex != 0, result times for interface with that index.
+ RegistrationTest * test; // Pointer to parent test.
+ NanoTime64 startTime; // Subtest's start time.
+ char * description; // Subtest's description. (malloc'd)
+ uint32_t ifIndex; // Interface index used for service registration.
+ uint16_t port; // Service's port number.
+ Boolean useLODiscovery; // True if discovery is to use kDNSServiceInterfaceIndexLocalOnly.
+ Boolean includeAWDL; // True if the IncludeAWDL flag was used during registration.
+ Boolean ifIsAWDL; // True if ifIndex is the index of an AWDL interface.
+ Boolean skipped; // True if this subtest is to be skipped.
+ Boolean registered; // True if the test service was successfully registered.
+ Boolean useDefaultName; // True if the service is to use the default service name.
+};
+
+static OSStatus _RegistrationTestCreate( RegistrationTest **outTest );
+static void _RegistrationTestFree( RegistrationTest *inTest );
+static void _RegistrationTestBegin( void *inContext );
+static void _RegistrationTestProceed( RegistrationTest *inTest );
+static OSStatus _RegistrationTestStart( RegistrationTest *inTest );
+static void _RegistrationTestStop( RegistrationTest *inTest );
+#define _RegistrationTestForget( X ) ForgetCustomEx( X, _RegistrationTestStop, _RegistrationTestFree )
+static OSStatus
+ _RegistrationTestStartSubtest(
+ RegistrationTest * inTest,
+ const RegistrationSubtestParams * inParams,
+ Boolean * outSkipped );
+static OSStatus _RegistrationTestEndSubtest( RegistrationTest *inTest );
+static void _RegistrationTestEnd( RegistrationTest *inTest ) ATTRIBUTE_NORETURN;
+static void _RegistrationTestExit( RegistrationTest *inTest, OSStatus inError ) ATTRIBUTE_NORETURN;
+static OSStatus _RegistrationSubtestCreate( RegistrationSubtest **outSubtest );
+static void _RegistrationSubtestStop( RegistrationSubtest *inSubtest );
+static void _RegistrationSubtestFree( RegistrationSubtest *inSubtest );
+#define _RegistrationSubtestForget( X ) ForgetCustomEx( X, _RegistrationSubtestStop, _RegistrationSubtestFree )
+static OSStatus _RegistrationTestInterfaceListCreate( Boolean inIncludeAWDL, RegistrationInterfaceItem **outList );
+static OSStatus
+ _RegistrationTestCreateRandomTXTRecord(
+ size_t inMinLen,
+ size_t inMaxLen,
+ uint8_t ** outTXTPtr,
+ size_t * outTXTLen );
+static void DNSSD_API
+ _RegistrationSubtestRegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ void * inContext );
+static void DNSSD_API
+ _RegistrationSubtestBrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inIfIndex,
+ DNSServiceErrorType inError,
+ const char * inServiceName,
+ const char * inServiceType,
+ const char * inDomain,
+ void * inContext );
+static void DNSSD_API
+ _RegistrationSubtestQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inIfIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static Boolean _RegistrationSubtestValidServiceType( const RegistrationSubtest *inSubtest, const char *inServiceType );
+static RegistrationResultTimes *
+ _RegistrationSubtestGetInterfaceResultTimes(
+ RegistrationSubtest * inSubtest,
+ uint32_t inIfIndex,
+ Boolean * outIsAWDL );
+static void _RegistrationTestTimerHandler( void *inContext );
+#if( TARGET_OS_WATCH )
+static Boolean _RegistrationTestInterfaceIsWiFi( const char *inIfName );
+#endif
+
+static void RegistrationTestCmd( void )
+{
+ OSStatus err;
+ RegistrationTest * test;
+
+ err = _RegistrationTestCreate( &test );
+ require_noerr( err, exit );
+
+ if( gRegistrationTest_BATSEnvironment ) test->forBATS = true;
+ if( gRegistrationTest_OutputFilePath )
+ {
+ test->outputFilePath = strdup( gRegistrationTest_OutputFilePath );
+ require_action( test->outputFilePath, exit, err = kNoMemoryErr );
+ }
+
+ err = OutputFormatFromArgString( gRegistrationTest_OutputFormat, &test->outputFormat );
+ require_noerr_quiet( err, exit );
+
+ dispatch_async_f( dispatch_get_main_queue(), test, _RegistrationTestBegin );
+ dispatch_main();
+
+exit:
+ if( test ) _RegistrationTestFree( test );
+ ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+
+static OSStatus _RegistrationTestCreate( RegistrationTest **outTest )
+{
+ OSStatus err;
+ RegistrationTest * obj;
+
+ obj = (RegistrationTest *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->subtestReports = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( obj->subtestReports, exit, err = kNoMemoryErr );
+
+ *outTest = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _RegistrationTestFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestFree( RegistrationTest *inTest )
+{
+ check( !inTest->timer );
+ check( !inTest->sigSourceINT );
+ check( !inTest->sigSourceTERM );
+ check( !inTest->computerNameSet );
+ check( !inTest->localHostNameSet );
+ check( !inTest->subtest );
+ ForgetCF( &inTest->subtestReports );
+ ForgetMem( &inTest->outputFilePath );
+ ForgetCF( &inTest->computerNamePrev );
+ ForgetCF( &inTest->localHostNamePrev );
+ ForgetMem( &inTest->computerName );
+ ForgetMem( &inTest->localHostName );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestBegin( void *inContext )
+{
+ _RegistrationTestProceed( (RegistrationTest *) inContext );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestProceed( RegistrationTest *inTest )
+{
+ OSStatus err;
+ Boolean skippedSubtest;
+
+ do
+ {
+ int subtestIndex;
+
+ if( !inTest->startTime )
+ {
+ err = _RegistrationTestStart( inTest );
+ require_noerr_quiet( err, exit );
+
+ inTest->startTime = NanoTimeGetCurrent();
+ }
+ else
+ {
+ err = _RegistrationTestEndSubtest( inTest );
+ require_noerr( err, exit );
+
+ ++inTest->subtestIndex;
+ }
+
+ subtestIndex = inTest->subtestIndex;
+ if( subtestIndex < (int) countof( kRegistrationSubtestParams ) )
+ {
+ err = _RegistrationTestStartSubtest( inTest, &kRegistrationSubtestParams[ subtestIndex ], &skippedSubtest );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ _RegistrationTestEnd( inTest );
+ }
+
+ } while( skippedSubtest );
+
+exit:
+ if( err ) _RegistrationTestExit( inTest, err );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestSignalHandler( void *inContext );
+
+static OSStatus _RegistrationTestStart( RegistrationTest *inTest )
+{
+ OSStatus err;
+ char tag[ 6 + 1 ];
+
+ // Save original ComputerName and LocalHostName.
+
+ check( !inTest->computerNamePrev );
+ inTest->computerNamePrev = SCDynamicStoreCopyComputerName( NULL, &inTest->computerNamePrevEncoding );
+ err = map_scerror( inTest->computerNamePrev );
+ require_noerr( err, exit );
+
+ check( !inTest->localHostNamePrev );
+ inTest->localHostNamePrev = SCDynamicStoreCopyLocalHostName( NULL );
+ err = map_scerror( inTest->localHostNamePrev );
+ require_noerr( err, exit );
+
+ // Generate a unique test ComputerName.
+
+ check( !inTest->computerName );
+ ASPrintF( &inTest->computerName, "dnssdutil-regtest-computer-name-%s",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+ require_action( inTest->computerName, exit, err = kNoMemoryErr );
+
+ // Generate a unique test LocalHostName.
+
+ check( !inTest->localHostName );
+ ASPrintF( &inTest->localHostName, "dnssdutil-regtest-local-hostname-%s",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+ require_action( inTest->localHostName, exit, err = kNoMemoryErr );
+
+ // Set up SIGINT signal handler.
+
+ signal( SIGINT, SIG_IGN );
+ check( !inTest->sigSourceINT );
+ err = DispatchSignalSourceCreate( SIGINT, _RegistrationTestSignalHandler, inTest, &inTest->sigSourceINT );
+ require_noerr( err, exit );
+ dispatch_resume( inTest->sigSourceINT );
+
+ // Set up SIGTERM signal handler.
+
+ signal( SIGTERM, SIG_IGN );
+ check( !inTest->sigSourceTERM );
+ err = DispatchSignalSourceCreate( SIGTERM, _RegistrationTestSignalHandler, inTest, &inTest->sigSourceTERM );
+ require_noerr( err, exit );
+ dispatch_resume( inTest->sigSourceTERM );
+
+ // Set test ComputerName.
+
+ check( !inTest->computerNameSet );
+ err = _SetComputerNameWithUTF8CString( inTest->computerName );
+ require_noerr( err, exit );
+ inTest->computerNameSet = true;
+
+ // Set test LocalHostName.
+
+ check( !inTest->localHostNameSet );
+ err = _SetLocalHostNameWithUTF8CString( inTest->localHostName );
+ require_noerr( err, exit );
+ inTest->localHostNameSet = true;
+
+exit:
+ if( err ) _RegistrationTestStop( inTest );
+ return( err );
+}
+
+static void _RegistrationTestSignalHandler( void *inContext )
+{
+ RegistrationTest * const test = (RegistrationTest *) inContext;
+
+ FPrintF( stderr, "Registration test got a SIGINT or SIGTERM signal, exiting..." );
+
+ _RegistrationTestExit( test, kCanceledErr );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestStop( RegistrationTest *inTest )
+{
+ OSStatus err;
+
+ dispatch_source_forget( &inTest->timer );
+ dispatch_source_forget( &inTest->sigSourceINT );
+ dispatch_source_forget( &inTest->sigSourceTERM );
+ _RegistrationSubtestForget( &inTest->subtest );
+ if( inTest->computerNameSet )
+ {
+ err = _SetComputerName( inTest->computerNamePrev, inTest->computerNamePrevEncoding );
+ check_noerr( err );
+ if( !err ) inTest->computerNameSet = false;
+ }
+ if( inTest->localHostNameSet )
+ {
+ err = _SetLocalHostName( inTest->localHostNamePrev );
+ check_noerr( err );
+ if( !err ) inTest->localHostNameSet = false;
+ }
+}
+
+//===========================================================================================================================
+
+#define kRegistrationTestSubtestDurationSecs 5
+
+static OSStatus
+ _RegistrationTestStartSubtest(
+ RegistrationTest * inTest,
+ const RegistrationSubtestParams * inParams,
+ Boolean * outSkipped )
+{
+ OSStatus err;
+ RegistrationSubtest * subtest;
+ const char * interfaceDesc;
+ DNSServiceFlags flags;
+ char tag[ 6 + 1 ];
+
+ subtest = NULL;
+ err = _RegistrationSubtestCreate( &subtest );
+ require_noerr( err, exit );
+
+ subtest->test = inTest;
+ subtest->useDefaultName = inParams->useDefaultName;
+ subtest->useLODiscovery = inParams->useLODiscovery;
+
+ // Determine registration interfaces.
+
+ switch( inParams->interfaceSet )
+ {
+ case kRegistrationInterfaceSet_All:
+ subtest->ifIndex = kDNSServiceInterfaceIndexAny;
+
+ if( !subtest->useLODiscovery )
+ {
+ err = _RegistrationTestInterfaceListCreate( false, &subtest->ifList );
+ require_noerr( err, exit );
+ }
+ interfaceDesc = "all interfaces (excluding AWDL)";
+ break;
+
+ case kRegistrationInterfaceSet_AllPlusAWDL:
+ subtest->ifIndex = kDNSServiceInterfaceIndexAny;
+ subtest->includeAWDL = true;
+
+ if( !subtest->useLODiscovery )
+ {
+ err = _RegistrationTestInterfaceListCreate( true, &subtest->ifList );
+ require_noerr( err, exit );
+ }
+ interfaceDesc = "all interfaces (including AWDL)";
+ break;
+
+ case kRegistrationInterfaceSet_LoopbackOnly:
+ subtest->ifIndex = if_nametoindex( "lo0" );
+ if( subtest->ifIndex == 0 )
+ {
+ FPrintF( stderr, "Failed to get index for loopback interface lo0.\n" );
+ err = kNoResourcesErr;
+ goto exit;
+ }
+ interfaceDesc = "loopback interface";
+ break;
+
+ case kRegistrationInterfaceSet_AWDLOnly:
+ err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_AWDL, NULL, &subtest->ifIndex );
+ if( err == kNotFoundErr )
+ {
+ FPrintF( stderr, "Warning: No mDNS-capable AWDL interface is available.\n" );
+ subtest->skipped = true;
+ err = kNoErr;
+ }
+ require_noerr( err, exit );
+
+ subtest->ifIsAWDL = true;
+ interfaceDesc = "AWDL interface";
+ break;
+
+ default:
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create description.
+
+ ASPrintF( &subtest->description, "Service registration over %s using %s service name.%s",
+ interfaceDesc, subtest->useDefaultName ? "default" : "custom",
+ subtest->useLODiscovery ? " (LocalOnly discovery)" : "" );
+ require_action( subtest->description, exit, err = kNoMemoryErr );
+
+ if( subtest->skipped )
+ {
+ subtest->startTime = NanoTimeGetCurrent();
+ }
+ else
+ {
+ // Generate a service name.
+
+ if( subtest->useDefaultName )
+ {
+ subtest->serviceName = inTest->computerName;
+ }
+ else
+ {
+ ASPrintF( &subtest->serviceNameCustom, "dnssdutil-regtest-service-name-%s",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+ require_action( subtest->serviceNameCustom, exit, err = kNoMemoryErr );
+
+ subtest->serviceName = subtest->serviceNameCustom;
+ }
+
+ // Generate a service type.
+
+ ASPrintF( &subtest->serviceType, "_regtest-%s._udp",
+ _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+ require_action( subtest->serviceType, exit, err = kNoMemoryErr );
+
+ subtest->serviceTypeLen = strlen( subtest->serviceType );
+
+ // Create SRV and TXT record name FQDN.
+
+ ASPrintF( &subtest->serviceFQDN, "%s.%s.local.", subtest->serviceName, subtest->serviceType );
+ require_action( subtest->serviceFQDN, exit, err = kNoMemoryErr );
+
+ // Generate a port number.
+
+ subtest->port = (uint16_t) RandomRange( 60000, 65535 );
+
+ // Generate TXT record data.
+
+ err = _RegistrationTestCreateRandomTXTRecord( 100, 1000, &subtest->txtPtr, &subtest->txtLen );
+ require_noerr( err, exit );
+
+ // Register service.
+
+ subtest->startTime = NanoTimeGetCurrent();
+
+ flags = kDNSServiceFlagsNoAutoRename;
+ if( subtest->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+ err = DNSServiceRegister( &subtest->registration, flags, subtest->ifIndex,
+ subtest->useDefaultName ? NULL : subtest->serviceNameCustom, subtest->serviceType, "local.",
+ NULL, htons( subtest->port ), (uint16_t) subtest->txtLen, subtest->txtPtr,
+ _RegistrationSubtestRegisterCallback, subtest );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( subtest->registration, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ // Start timer.
+
+ check( !inTest->timer );
+ err = DispatchTimerOneShotCreate( dispatch_time_seconds( kRegistrationTestSubtestDurationSecs ),
+ INT64_C_safe( kRegistrationTestSubtestDurationSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
+ _RegistrationTestTimerHandler, inTest, &inTest->timer );
+ require_noerr( err, exit );
+ dispatch_resume( inTest->timer );
+ }
+
+ *outSkipped = subtest->skipped;
+
+ check( !inTest->subtest );
+ inTest->subtest = subtest;
+ subtest = NULL;
+
+exit:
+ _RegistrationSubtestForget( &subtest );
+ return( err );
+}
+
+//===========================================================================================================================
+
+#define kRegistrationTestReportKey_ComputerName CFSTR( "computerName" ) // String
+#define kRegistrationTestReportKey_Description CFSTR( "description" ) // String
+#define kRegistrationTestReportKey_Domain CFSTR( "domain" ) // String
+#define kRegistrationTestReportKey_EndTime CFSTR( "endTime" ) // String
+#define kRegistrationTestReportKey_Error CFSTR( "error" ) // Integer
+#define kRegistrationTestReportKey_Flags CFSTR( "flags" ) // Integer
+#define kRegistrationTestReportKey_IgnoredResults CFSTR( "ignoredResults" ) // Array of dictionaries
+#define kRegistrationTestReportKey_InterfaceIndex CFSTR( "ifIndex" ) // Integer
+#define kRegistrationTestReportKey_InterfaceName CFSTR( "ifName" ) // String
+#define kRegistrationTestReportKey_LocalHostName CFSTR( "localHostName" ) // String
+#define kRegistrationTestReportKey_MissingResults CFSTR( "missingResults" ) // Array of dictionaries
+#define kRegistrationTestReportKey_Pass CFSTR( "pass" ) // Boolean
+#define kRegistrationTestReportKey_Port CFSTR( "port" ) // Integer
+#define kRegistrationTestReportKey_RDataFormatted CFSTR( "rdataFormatted" ) // String
+#define kRegistrationTestReportKey_RDataHexString CFSTR( "rdataHexString" ) // String
+#define kRegistrationTestReportKey_RecordClass CFSTR( "recordClass" ) // Integer
+#define kRegistrationTestReportKey_RecordType CFSTR( "recordType" ) // Integer
+#define kRegistrationTestReportKey_Registered CFSTR( "registered" ) // Boolean
+#define kRegistrationTestReportKey_ResultType CFSTR( "resultType" ) // String
+#define kRegistrationTestReportKey_ServiceFQDN CFSTR( "serviceFQDN" ) // String
+#define kRegistrationTestReportKey_ServiceName CFSTR( "serviceName" ) // String
+#define kRegistrationTestReportKey_ServiceType CFSTR( "serviceType" ) // String
+#define kRegistrationTestReportKey_Skipped CFSTR( "skipped" ) // Boolean
+#define kRegistrationTestReportKey_StartTime CFSTR( "startTime" ) // String
+#define kRegistrationTestReportKey_Subtests CFSTR( "subtests" ) // Array of dictionaries
+#define kRegistrationTestReportKey_Timestamp CFSTR( "timestamp" ) // String
+#define kRegistrationTestReportKey_TXT CFSTR( "txt" ) // String
+#define kRegistrationTestReportKey_UnexpectedResults CFSTR( "unexpectedResults" ) // Array of dictionaries
+#define kRegistrationTestReportKey_UsedDefaultName CFSTR( "usedDefaultName" ) // Boolean
+#define kRegistrationTestReportKey_UsedLODiscovery CFSTR( "usedLODiscovery" ) // Boolean
+
+#define kRegistrationTestResultType_Browse CFSTR( "browse" )
+#define kRegistrationTestResultType_Query CFSTR( "query" )
+#define kRegistrationTestResultType_QuerySRV CFSTR( "querySRV" )
+#define kRegistrationTestResultType_QueryTXT CFSTR( "queryTXT" )
+#define kRegistrationTestResultType_Registration CFSTR( "registration" )
+
+static OSStatus
+ _RegistrationTestAppendMissingResults(
+ CFMutableArrayRef inMissingResults,
+ const RegistrationResultTimes * inTimes,
+ uint32_t inIfIndex,
+ const char * inIfName );
+
+static OSStatus _RegistrationTestEndSubtest( RegistrationTest *inTest )
+{
+ OSStatus err;
+ RegistrationSubtest * subtest;
+ CFMutableDictionaryRef subtestReport;
+ CFMutableArrayRef missing;
+ char * txtStr;
+ NanoTime64 now;
+ Boolean subtestFailed;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+ char ifNameBuf[ IF_NAMESIZE + 1 ];
+
+ now = NanoTimeGetCurrent();
+
+ subtest = inTest->subtest;
+ inTest->subtest = NULL;
+ _RegistrationSubtestStop( subtest );
+
+ missing = NULL;
+ subtestReport = NULL;
+ txtStr = NULL;
+ if( subtest->txtPtr )
+ {
+ err = DNSRecordDataToString( subtest->txtPtr, subtest->txtLen, kDNSServiceType_TXT, NULL, 0, &txtStr );
+ require_noerr( err, exit );
+ }
+ _NanoTime64ToTimestamp( subtest->startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &subtestReport,
+ "{"
+ "%kO=%s" // description
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%s" // serviceFQDN
+ "%kO=%lli" // ifIndex
+ "%kO=%s" // ifName
+ "%kO=%lli" // port
+ "%kO=%s" // txt
+ "%kO=%b" // registered
+ "%kO=%b" // usedDefaultName
+ "%kO=%b" // usedLODiscovery
+ "}",
+ kRegistrationTestReportKey_Description, subtest->description,
+ kRegistrationTestReportKey_StartTime, startTime,
+ kRegistrationTestReportKey_EndTime, endTime,
+ kRegistrationTestReportKey_ServiceFQDN, subtest->serviceFQDN,
+ kRegistrationTestReportKey_InterfaceIndex, (int64_t) subtest->ifIndex,
+ kRegistrationTestReportKey_InterfaceName, if_indextoname( subtest->ifIndex, ifNameBuf ),
+ kRegistrationTestReportKey_Port, (int64_t) subtest->port,
+ kRegistrationTestReportKey_TXT, txtStr,
+ kRegistrationTestReportKey_Registered, (int) subtest->registered,
+ kRegistrationTestReportKey_UsedDefaultName, (int) subtest->useDefaultName,
+ kRegistrationTestReportKey_UsedLODiscovery, (int) subtest->useLODiscovery );
+ ForgetMem( &txtStr );
+ require_noerr( err, exit );
+
+ if( !subtest->skipped && subtest->registered )
+ {
+ missing = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( missing, exit, err = kNoMemoryErr );
+
+ if( subtest->ifList )
+ {
+ RegistrationInterfaceItem * item;
+
+ for( item = subtest->ifList; item; item = (RegistrationInterfaceItem *) item->base.next )
+ {
+ #if( TARGET_OS_WATCH )
+ if( inTest->forBATS && item->base.isWiFi ) continue;
+ #endif
+ err = _RegistrationTestAppendMissingResults( missing, &item->times, item->base.ifIndex, item->base.ifName );
+ require_noerr( err, exit );
+ }
+ }
+ else
+ {
+ err = _RegistrationTestAppendMissingResults( missing, &subtest->ifTimes, subtest->ifIndex, NULL );
+ require_noerr( err, exit );
+ }
+
+ subtestFailed = false;
+ if( CFArrayGetCount( missing ) > 0 )
+ {
+ subtestFailed = true;
+ CFDictionarySetValue( subtestReport, kRegistrationTestReportKey_MissingResults, missing );
+ }
+ if( CFArrayGetCount( subtest->unexpected ) > 0 )
+ {
+ subtestFailed = true;
+ CFDictionarySetValue( subtestReport, kRegistrationTestReportKey_UnexpectedResults, subtest->unexpected );
+ }
+ #if( TARGET_OS_WATCH )
+ if( CFArrayGetCount( subtest->ignored ) > 0 )
+ {
+ CFDictionarySetValue( subtestReport, kRegistrationTestReportKey_IgnoredResults, subtest->ignored );
+ }
+ #endif
+ }
+ else
+ {
+ subtestFailed = true;
+ }
+
+ CFDictionarySetBoolean( subtestReport, kRegistrationTestReportKey_Pass, subtestFailed ? false : true );
+ if( subtestFailed )
+ {
+ CFDictionarySetBoolean( subtestReport, kRegistrationTestReportKey_Skipped, subtest->skipped );
+ if( !subtest->skipped ) inTest->failed = true;
+ }
+ CFArrayAppendValue( inTest->subtestReports, subtestReport );
+
+exit:
+ CFReleaseNullSafe( missing );
+ CFReleaseNullSafe( subtestReport );
+ _RegistrationSubtestFree( subtest );
+ return( err );
+}
+
+static OSStatus
+ _RegistrationTestAppendMissingResult(
+ CFMutableArrayRef inMissingResults,
+ CFStringRef inType,
+ uint32_t inIfIndex,
+ const char * inIfName );
+
+static OSStatus
+ _RegistrationTestAppendMissingResults(
+ CFMutableArrayRef inMissingResults,
+ const RegistrationResultTimes * inTimes,
+ uint32_t inIfIndex,
+ const char * inIfName )
+{
+ OSStatus err;
+
+ if( !inTimes->browseResultTime )
+ {
+ err = _RegistrationTestAppendMissingResult( inMissingResults, kRegistrationTestResultType_Browse,
+ inIfIndex, inIfName );
+ require_noerr( err, exit );
+ }
+ if( !inTimes->querySRVResultTime )
+ {
+ err = _RegistrationTestAppendMissingResult( inMissingResults, kRegistrationTestResultType_QuerySRV,
+ inIfIndex, inIfName );
+ require_noerr( err, exit );
+ }
+ if( !inTimes->queryTXTResultTime )
+ {
+ err = _RegistrationTestAppendMissingResult( inMissingResults, kRegistrationTestResultType_QueryTXT,
+ inIfIndex, inIfName );
+ require_noerr( err, exit );
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+static OSStatus
+ _RegistrationTestAppendMissingResult(
+ CFMutableArrayRef inMissingResults,
+ CFStringRef inType,
+ uint32_t inIfIndex,
+ const char * inIfName )
+{
+ OSStatus err;
+ char ifName[ IF_NAMESIZE + 1 ];
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, inMissingResults,
+ "{"
+ "%kO=%O" // resultType
+ "%kO=%lli" // ifIndex
+ "%kO=%s" // ifName
+ "}",
+ kRegistrationTestReportKey_ResultType, inType,
+ kRegistrationTestReportKey_InterfaceIndex, (int64_t) inIfIndex,
+ kRegistrationTestReportKey_InterfaceName, inIfName ? inIfName : if_indextoname( inIfIndex, ifName ) );
+ return( err );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestEnd( RegistrationTest *inTest )
+{
+ OSStatus err;
+ NanoTime64 now;
+ CFPropertyListRef plist;
+ char startTime[ 32 ];
+ char endTime[ 32 ];
+
+ now = NanoTimeGetCurrent();
+ _NanoTime64ToTimestamp( inTest->startTime, startTime, sizeof( startTime ) );
+ _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+ "{"
+ "%kO=%s" // startTime
+ "%kO=%s" // endTime
+ "%kO=%s" // computerName
+ "%kO=%s" // localHostName
+ "%kO=%O" // subtests
+ "%kO=%b" // pass
+ "}",
+ kRegistrationTestReportKey_StartTime, startTime,
+ kRegistrationTestReportKey_EndTime, endTime,
+ kRegistrationTestReportKey_ComputerName, inTest->computerName,
+ kRegistrationTestReportKey_LocalHostName, inTest->localHostName,
+ kRegistrationTestReportKey_Subtests, inTest->subtestReports,
+ kRegistrationTestReportKey_Pass, inTest->failed ? false : true );
+ require_noerr( err, exit );
+
+ err = OutputPropertyList( plist, inTest->outputFormat, inTest->outputFilePath );
+ CFRelease( plist );
+ require_noerr( err, exit );
+
+exit:
+ _RegistrationTestExit( inTest, err );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestExit( RegistrationTest *inTest, OSStatus inError )
+{
+ int exitCode;
+
+ if( inError )
+ {
+ FPrintF( stderr, "error: %#m\n", inError );
+ exitCode = 1;
+ }
+ else
+ {
+ exitCode = inTest->failed ? 2 : 0;
+ }
+ _RegistrationTestForget( &inTest );
+ exit( exitCode );
+}
+
+//===========================================================================================================================
+
+static OSStatus _RegistrationSubtestCreate( RegistrationSubtest **outSubtest )
+{
+ OSStatus err;
+ RegistrationSubtest * obj;
+
+ obj = (RegistrationSubtest *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->unexpected = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( obj->unexpected, exit, err = kNoMemoryErr );
+
+#if( TARGET_OS_WATCH )
+ obj->ignored = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+ require_action( obj->ignored, exit, err = kNoMemoryErr );
+#endif
+
+ *outSubtest = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _RegistrationSubtestFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationSubtestFree( RegistrationSubtest *inSubtest )
+{
+ check( !inSubtest->registration );
+ check( !inSubtest->browse );
+ check( !inSubtest->querySRV );
+ check( !inSubtest->queryTXT );
+ check( !inSubtest->connection );
+ ForgetMem( &inSubtest->serviceNameCustom );
+ ForgetMem( &inSubtest->serviceType );
+ ForgetMem( &inSubtest->serviceFQDN );
+ ForgetMem( &inSubtest->txtPtr );
+ ForgetCF( &inSubtest->unexpected );
+#if( TARGET_OS_WATCH )
+ ForgetCF( &inSubtest->ignored );
+#endif
+ _MDNSInterfaceListForget( (MDNSInterfaceItem **) &inSubtest->ifList );
+ ForgetMem( &inSubtest->description );
+ free( inSubtest );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationSubtestStop( RegistrationSubtest *inSubtest )
+{
+ DNSServiceForget( &inSubtest->registration );
+ DNSServiceForget( &inSubtest->browse );
+ DNSServiceForget( &inSubtest->querySRV );
+ DNSServiceForget( &inSubtest->queryTXT );
+ DNSServiceForget( &inSubtest->connection );
+}
+
+//===========================================================================================================================
+
+static OSStatus _RegistrationTestInterfaceListCreate( Boolean inIncludeAWDL, RegistrationInterfaceItem **outList )
+{
+ OSStatus err;
+ RegistrationInterfaceItem * list;
+ const MDNSInterfaceSubset subset = inIncludeAWDL ? kMDNSInterfaceSubset_All : kMDNSInterfaceSubset_NonAWDL;
+
+ err = _MDNSInterfaceListCreate( subset, sizeof( *list ), (MDNSInterfaceItem **) &list );
+ require_noerr( err, exit );
+
+ *outList = list;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+
+static OSStatus
+ _RegistrationTestCreateRandomTXTRecord(
+ size_t inMinLen,
+ size_t inMaxLen,
+ uint8_t ** outTXTPtr,
+ size_t * outTXTLen )
+{
+ OSStatus err;
+ uint8_t * ptr;
+ const uint8_t * txtEnd;
+ uint8_t * txtPtr = NULL;
+ size_t txtLen;
+
+ require_action_quiet( inMinLen <= inMaxLen, exit, err = kSizeErr );
+
+ txtLen = RandomRange( inMinLen, inMaxLen );
+ txtPtr = (uint8_t *) malloc( txtLen + 1 );
+ require_action( txtPtr, exit, err = kNoMemoryErr );
+
+ _RandomStringExact( kAlphaNumericCharSet, sizeof_string( kAlphaNumericCharSet ), txtLen, (char *)txtPtr );
+
+ ptr = txtPtr;
+ txtEnd = &txtPtr[ txtLen ];
+ while( ptr < txtEnd )
+ {
+ size_t maxLen, len;
+
+ maxLen = ( (size_t)( txtEnd - ptr ) ) - 1;
+ len = RandomRange( 1, 255 );
+ if( len > maxLen ) len = maxLen;
+
+ *ptr = (uint8_t) len;
+ ptr += ( 1 + len );
+ }
+ check( ptr == txtEnd );
+
+ if( outTXTPtr )
+ {
+ *outTXTPtr = txtPtr;
+ txtPtr = NULL;
+ }
+ if( outTXTLen ) *outTXTLen = txtLen;
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( txtPtr );
+ return( err );
+}
+
+//===========================================================================================================================
+
+static void DNSSD_API
+ _RegistrationSubtestRegisterCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ DNSServiceErrorType inError,
+ const char * inServiceName,
+ const char * inServiceType,
+ const char * inDomain,
+ void * inContext )
+{
+ OSStatus err;
+ const NanoTime64 now = NanoTimeGetCurrent();
+ RegistrationSubtest * const subtest = (RegistrationSubtest *) inContext;
+
+ Unused( inSDRef );
+
+ if( ( inFlags & kDNSServiceFlagsAdd ) && !inError &&
+ ( strcasecmp( inServiceName, subtest->serviceName ) == 0 ) &&
+ _RegistrationSubtestValidServiceType( subtest, inServiceType ) &&
+ ( strcasecmp( inDomain, "local." ) == 0 ) )
+ {
+ if( !subtest->registered )
+ {
+ DNSServiceRef sdRef;
+ const DNSServiceFlags flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsIncludeAWDL;
+
+ subtest->registered = true;
+
+ // Create shared connection.
+
+ check( !subtest->connection );
+ err = DNSServiceCreateConnection( &subtest->connection );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( subtest->connection, dispatch_get_main_queue() );
+ require_noerr( err, exit );
+
+ // Start browse.
+
+ check( !subtest->browse );
+ sdRef = subtest->connection;
+ err = DNSServiceBrowse( &sdRef, flags,
+ subtest->useLODiscovery ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny,
+ subtest->serviceType, "local.", _RegistrationSubtestBrowseCallback, subtest );
+ require_noerr( err, exit );
+
+ subtest->browse = sdRef;
+ }
+ }
+ else
+ {
+ char timestamp[ 32 ];
+
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpected,
+ "{"
+ "%kO=%O" // resultType
+ "%kO=%s" // timestamp
+ "%kO=%lli" // flags
+ "%kO=%lli" // error
+ "%kO=%s" // serviceName
+ "%kO=%s" // serviceType
+ "%kO=%s" // domain
+ "}",
+ kRegistrationTestReportKey_ResultType, kRegistrationTestResultType_Registration,
+ kRegistrationTestReportKey_Timestamp, _NanoTime64ToTimestamp( now, timestamp, sizeof( timestamp ) ),
+ kRegistrationTestReportKey_Flags, (int64_t) inFlags,
+ kRegistrationTestReportKey_Error, (int64_t) inError,
+ kRegistrationTestReportKey_ServiceName, inServiceName,
+ kRegistrationTestReportKey_ServiceType, inServiceType,
+ kRegistrationTestReportKey_Domain, inDomain );
+ require_noerr( err, exit );
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) _RegistrationTestExit( subtest->test, err );
+}
+
+//===========================================================================================================================
+
+static void DNSSD_API
+ _RegistrationSubtestBrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inIfIndex,
+ DNSServiceErrorType inError,
+ const char * inServiceName,
+ const char * inServiceType,
+ const char * inDomain,
+ void * inContext )
+{
+ OSStatus err;
+ NanoTime64 now;
+ RegistrationSubtest * const subtest = (RegistrationSubtest *) inContext;
+ Boolean serviceIsCorrect, resultIsExpected;
+
+ Unused( inSDRef );
+
+ now = NanoTimeGetCurrent();
+ if( !inError && ( strcasecmp( inServiceName, subtest->serviceName ) == 0 ) &&
+ _RegistrationSubtestValidServiceType( subtest, inServiceType ) && ( strcasecmp( inDomain, "local." ) == 0 ) )
+ {
+ serviceIsCorrect = true;
+ }
+ else
+ {
+ serviceIsCorrect = false;
+ }
+
+ resultIsExpected = false;
+ if( serviceIsCorrect && ( inFlags & kDNSServiceFlagsAdd ) )
+ {
+ RegistrationResultTimes * times;
+
+ times = _RegistrationSubtestGetInterfaceResultTimes( subtest, inIfIndex, NULL );
+ if( times )
+ {
+ DNSServiceRef sdRef;
+ const DNSServiceFlags flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsIncludeAWDL;
+ uint32_t ifIndex;
+
+ resultIsExpected = true;
+ if( !times->browseResultTime ) times->browseResultTime = now;
+
+ ifIndex = subtest->useLODiscovery ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny;
+ if( !subtest->querySRV )
+ {
+ // Start SRV record query.
+
+ sdRef = subtest->connection;
+ err = DNSServiceQueryRecord( &sdRef, flags, ifIndex, subtest->serviceFQDN, kDNSServiceType_SRV,
+ kDNSServiceClass_IN, _RegistrationSubtestQueryCallback, subtest );
+ require_noerr( err, exit );
+
+ subtest->querySRV = sdRef;
+ }
+ if( !subtest->queryTXT )
+ {
+ // Start TXT record query.
+
+ sdRef = subtest->connection;
+ err = DNSServiceQueryRecord( &sdRef, flags, ifIndex, subtest->serviceFQDN, kDNSServiceType_TXT,
+ kDNSServiceClass_IN, _RegistrationSubtestQueryCallback, subtest );
+ require_noerr( err, exit );
+
+ subtest->queryTXT = sdRef;
+ }
+ }
+ }
+
+ if( !resultIsExpected )
+ {
+ CFMutableArrayRef resultArray;
+ char timestamp[ 32 ];
+ const char * ifNamePtr;
+ char ifNameBuf[ IF_NAMESIZE + 1 ];
+
+ ifNamePtr = if_indextoname( inIfIndex, ifNameBuf );
+ resultArray = subtest->unexpected;
+ #if( TARGET_OS_WATCH )
+ if( subtest->test->forBATS && ( subtest->ifIndex == kDNSServiceInterfaceIndexAny ) &&
+ ifNamePtr && _RegistrationTestInterfaceIsWiFi( ifNamePtr ) && serviceIsCorrect )
+ {
+ resultArray = subtest->ignored;
+ }
+ #endif
+ err = CFPropertyListAppendFormatted( kCFAllocatorDefault, resultArray,
+ "{"
+ "%kO=%O" // resultType
+ "%kO=%s" // timestamp
+ "%kO=%lli" // flags
+ "%kO=%lli" // ifIndex
+ "%kO=%s" // ifName
+ "%kO=%lli" // error
+ "%kO=%s" // serviceName
+ "%kO=%s" // serviceType
+ "%kO=%s" // domain
+ "}",
+ kRegistrationTestReportKey_ResultType, kRegistrationTestResultType_Browse,
+ kRegistrationTestReportKey_Timestamp, _NanoTime64ToTimestamp( now, timestamp, sizeof( timestamp ) ),
+ kRegistrationTestReportKey_Flags, (int64_t) inFlags,
+ kRegistrationTestReportKey_InterfaceIndex, (int64_t) inIfIndex,
+ kRegistrationTestReportKey_InterfaceName, ifNamePtr,
+ kRegistrationTestReportKey_Error, (int64_t) inError,
+ kRegistrationTestReportKey_ServiceName, inServiceName,
+ kRegistrationTestReportKey_ServiceType, inServiceType,
+ kRegistrationTestReportKey_Domain, inDomain );
+ require_noerr( err, exit );
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) _RegistrationTestExit( subtest->test, err );
+}
+
+//===========================================================================================================================
+
+static Boolean
+ _RegistrationSubtestIsSRVRecordDataValid(
+ RegistrationSubtest * inSubtest,
+ const uint8_t * inRDataPtr,
+ size_t inRDataLen,
+ Boolean inExpectRandHostname );
+
+static void DNSSD_API
+ _RegistrationSubtestQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inIfIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ NanoTime64 now;
+ RegistrationSubtest * const subtest = (RegistrationSubtest *) inContext;
+ Boolean resultIsExpected;
+
+ Unused( inSDRef );
+ Unused( inTTL );
+
+ now = NanoTimeGetCurrent();
+ resultIsExpected = false;
+ if( ( inFlags & kDNSServiceFlagsAdd ) && !inError && ( strcasecmp( inName, subtest->serviceFQDN ) == 0 ) &&
+ ( inClass == kDNSServiceClass_IN ) )
+ {
+ RegistrationResultTimes * times;
+ Boolean isAWDL;
+
+ times = _RegistrationSubtestGetInterfaceResultTimes( subtest, inIfIndex, &isAWDL );
+ if( times )
+ {
+ if( inType == kDNSServiceType_SRV )
+ {
+ Boolean expectRandHostname;
+
+ if( isAWDL || ( ( subtest->ifIndex == kDNSServiceInterfaceIndexAny ) && subtest->includeAWDL ) )
+ {
+ expectRandHostname = true;
+ }
+ else
+ {
+ expectRandHostname = false;
+ }
+ if( _RegistrationSubtestIsSRVRecordDataValid( subtest, inRDataPtr, inRDataLen, expectRandHostname ) )
+ {
+ resultIsExpected = true;
+ if( !times->querySRVResultTime ) times->querySRVResultTime = now;
+ }
+ }
+ else if( inType == kDNSServiceType_TXT )
+ {
+ if( MemEqual( inRDataPtr, inRDataLen, subtest->txtPtr, subtest->txtLen ) )
+ {
+ resultIsExpected = true;
+ if( !times->queryTXTResultTime ) times->queryTXTResultTime = now;
+ }
+ }
+ }
+ }
+
+ if( !resultIsExpected )
+ {
+ CFMutableArrayRef resultArray;
+ CFMutableDictionaryRef resultDict;
+ CFStringRef rdataKey;
+ char * rdataStr;
+ const char * ifNamePtr;
+ char timestamp[ 32 ];
+ char ifNameBuf[ IF_NAMESIZE + 1 ];
+
+ ifNamePtr = if_indextoname( inIfIndex, ifNameBuf );
+ resultArray = subtest->unexpected;
+ #if( TARGET_OS_WATCH )
+ if( subtest->test->forBATS && ( subtest->ifIndex == kDNSServiceInterfaceIndexAny ) &&
+ ifNamePtr && _RegistrationTestInterfaceIsWiFi( ifNamePtr ) && !inError &&
+ ( strcasecmp( inName, subtest->serviceFQDN ) == 0 ) )
+ {
+ if( inType == kDNSServiceType_SRV )
+ {
+ const Boolean expectRandHostname = subtest->includeAWDL ? true : false;
+
+ if( _RegistrationSubtestIsSRVRecordDataValid( subtest, inRDataPtr, inRDataLen, expectRandHostname ) )
+ {
+ resultArray = subtest->ignored;
+ }
+ }
+ else if( inType == kDNSServiceType_TXT )
+ {
+ if( MemEqual( inRDataPtr, inRDataLen, subtest->txtPtr, subtest->txtLen ) )
+ {
+ resultArray = subtest->ignored;
+ }
+ }
+ }
+ #endif
+ err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &resultDict,
+ "{"
+ "%kO=%O" // resultType
+ "%kO=%s" // timestamp
+ "%kO=%lli" // flags
+ "%kO=%lli" // ifIndex
+ "%kO=%s" // ifName
+ "%kO=%lli" // error
+ "%kO=%s" // serviceFQDN
+ "%kO=%lli" // recordType
+ "%kO=%lli" // class
+ "}",
+ kRegistrationTestReportKey_ResultType, kRegistrationTestResultType_Query,
+ kRegistrationTestReportKey_Timestamp, _NanoTime64ToTimestamp( now, timestamp, sizeof( timestamp ) ),
+ kRegistrationTestReportKey_Flags, (int64_t) inFlags,
+ kRegistrationTestReportKey_InterfaceIndex, (int64_t) inIfIndex,
+ kRegistrationTestReportKey_InterfaceName, ifNamePtr,
+ kRegistrationTestReportKey_Error, (int64_t) inError,
+ kRegistrationTestReportKey_ServiceFQDN, inName,
+ kRegistrationTestReportKey_RecordType, (int64_t) inType,
+ kRegistrationTestReportKey_RecordClass, (int64_t) inClass );
+ require_noerr( err, exit );
+
+ rdataStr = NULL;
+ DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
+ if( rdataStr )
+ {
+ rdataKey = kRegistrationTestReportKey_RDataFormatted;
+ }
+ else
+ {
+ ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, inRDataLen );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ rdataKey = kRegistrationTestReportKey_RDataHexString;
+ }
+ err = CFDictionarySetCString( resultDict, rdataKey, rdataStr, kSizeCString );
+ ForgetMem( &rdataStr );
+ if( err ) CFRelease( resultDict );
+ require_noerr( err, exit );
+
+ CFArrayAppendValue( resultArray, resultDict );
+ CFRelease( resultDict );
+ }
+ err = kNoErr;
+
+exit:
+ if( err ) _RegistrationTestExit( subtest->test, err );
+}
+
+static Boolean
+ _RegistrationSubtestIsSRVRecordDataValid(
+ RegistrationSubtest * inSubtest,
+ const uint8_t * inRDataPtr,
+ size_t inRDataLen,
+ Boolean inExpectRandHostname )
+{
+ const dns_fixed_fields_srv * fields;
+ const uint8_t * const end = &inRDataPtr[ inRDataLen ];
+ const uint8_t * label;
+ size_t len;
+ uint16_t port;
+ Boolean isValid;
+
+ isValid = false;
+ require_quiet( inRDataLen >= sizeof( dns_fixed_fields_srv ), exit );
+
+ fields = (const dns_fixed_fields_srv *) inRDataPtr;
+ port = dns_fixed_fields_srv_get_port( fields );
+ require_quiet( port == inSubtest->port, exit );
+
+ // First target label should be a UUID string for the AWDL interface.
+
+ label = (const uint8_t *) &fields[ 1 ];
+ require_quiet( ( end - label ) >= 1, exit );
+
+ len = label[ 0 ];
+ require_quiet( ( (size_t)( end - label ) ) >= ( 1 + len ), exit );
+
+ if( inExpectRandHostname )
+ {
+ if( StringToUUID( (const char *) &label[ 1 ], len, false, NULL ) != kNoErr ) goto exit;
+ }
+ else
+ {
+ if( strnicmpx( &label[ 1 ], len, inSubtest->test->localHostName ) != 0 ) goto exit;
+ }
+
+ // Second target label should be "local".
+
+ label = &label[ 1 + len ];
+ require_quiet( ( end - label ) >= 1, exit );
+
+ len = label[ 0 ];
+ require_quiet( ( (size_t)( end - label ) ) >= ( 1 + len ), exit );
+
+ if( ( len != kLocalLabel[ 0 ] ) || ( _memicmp( &label[ 1 ], &kLocalLabel[ 1 ], kLocalLabel[ 0 ] ) != 0 ) ) goto exit;
+
+ // Third target label should be the root label.
+
+ label = &label[ 1 + len ];
+ require_quiet( ( end - label ) >= 1, exit );
+
+ len = label[ 0 ];
+ if( len != 0 ) goto exit;
+
+ isValid = true;
+
+exit:
+ return( isValid );
+}
+
+//===========================================================================================================================
+
+static Boolean _RegistrationSubtestValidServiceType( const RegistrationSubtest *inSubtest, const char *inServiceType )
+{
+ if( stricmp_prefix( inServiceType, inSubtest->serviceType ) == 0 )
+ {
+ const char * const ptr = &inServiceType[ inSubtest->serviceTypeLen ];
+
+ if( ( ptr[ 0 ] == '\0' ) || ( ( ptr[ 0 ] == '.' ) && ( ptr[ 1 ] == '\0' ) ) ) return( true );
+ }
+ return( false );
+}
+
+//===========================================================================================================================
+
+static RegistrationResultTimes *
+ _RegistrationSubtestGetInterfaceResultTimes(
+ RegistrationSubtest * inSubtest,
+ uint32_t inIfIndex,
+ Boolean * outIsAWDL )
+{
+ if( inSubtest->ifList )
+ {
+ RegistrationInterfaceItem * item;
+
+ for( item = inSubtest->ifList; item; item = (RegistrationInterfaceItem *) item->base.next )
+ {
+ if( inIfIndex == item->base.ifIndex )
+ {
+ if( outIsAWDL ) *outIsAWDL = item->base.isAWDL ? true : false;
+ return( &item->times );
+ }
+ }
+ }
+ else
+ {
+ if( inIfIndex == inSubtest->ifIndex )
+ {
+ if( outIsAWDL ) *outIsAWDL = inSubtest->ifIsAWDL ? true : false;
+ return( &inSubtest->ifTimes );
+ }
+ }
+ return( NULL );
+}
+
+//===========================================================================================================================
+
+static void _RegistrationTestTimerHandler( void *inContext )
+{
+ RegistrationTest * const test = (RegistrationTest *) inContext;
+
+ dispatch_source_forget( &test->timer );
+ _RegistrationTestProceed( test );
+}
+
+//===========================================================================================================================
+
+#if( TARGET_OS_WATCH )
+static Boolean _RegistrationTestInterfaceIsWiFi( const char *inIfName )
+{
+ NetTransportType type = kNetTransportType_Undefined;
+
+ SocketGetInterfaceInfo( kInvalidSocketRef, inIfName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &type );
+ return( ( type == kNetTransportType_WiFi ) ? true : false );
+}
+#endif
+
+//===========================================================================================================================
+// SSDPDiscoverCmd
+//===========================================================================================================================
+
+#define kSSDPPort 1900
+
+typedef struct
+{
+ HTTPHeader header; // HTTP header object for sending and receiving.
+ dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
+ dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
+ int receiveSecs; // After send, the amount of time to spend receiving.
+ uint32_t ifindex; // Index of the interface over which to send the query.
+ Boolean useIPv4; // True if the query should be sent via IPv4 multicast.
+ Boolean useIPv6; // True if the query should be sent via IPv6 multicast.
+
+} SSDPDiscoverContext;
+
+static void SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext );
+static void SSDPDiscoverReadHandler( void *inContext );
+static int SocketToPortNumber( SocketRef inSock );
+static OSStatus WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST );
+
+static void SSDPDiscoverCmd( void )
+{
+ OSStatus err;
+ struct timeval now;
+ SSDPDiscoverContext * context;
+ dispatch_source_t signalSource = NULL;
+ SocketRef sockV4 = kInvalidSocketRef;
+ SocketRef sockV6 = kInvalidSocketRef;
+ ssize_t n;
+ int sendCount;
+
+ // Set up SIGINT handler.
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ // Check command parameters.
+
+ if( gSSDPDiscover_ReceiveSecs < -1 )
+ {
+ FPrintF( stdout, "Invalid receive time: %d seconds.\n", gSSDPDiscover_ReceiveSecs );
+ err = kParamErr;
+ goto exit;
+ }
+
+ // Create context.
+
+ context = (SSDPDiscoverContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->receiveSecs = gSSDPDiscover_ReceiveSecs;
+ context->useIPv4 = ( gSSDPDiscover_UseIPv4 || !gSSDPDiscover_UseIPv6 ) ? true : false;
+ context->useIPv6 = ( gSSDPDiscover_UseIPv6 || !gSSDPDiscover_UseIPv4 ) ? true : false;
+
+ err = InterfaceIndexFromArgString( gInterface, &context->ifindex );
+ require_noerr_quiet( err, exit );
+
+ // Set up IPv4 socket.
+
+ if( context->useIPv4 )
+ {
+ int port;
+ err = UDPClientSocketOpen( AF_INET, NULL, 0, -1, &port, &sockV4 );
+ require_noerr( err, exit );
+
+ err = SocketSetMulticastInterface( sockV4, NULL, context->ifindex );
+ require_noerr( err, exit );
+
+ err = setsockopt( sockV4, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
+ err = map_socket_noerr_errno( sockV4, err );
+ require_noerr( err, exit );
+ }
+
+ // Set up IPv6 socket.
+
+ if( context->useIPv6 )
+ {
+ err = UDPClientSocketOpen( AF_INET6, NULL, 0, -1, NULL, &sockV6 );
+ require_noerr( err, exit );
+
+ err = SocketSetMulticastInterface( sockV6, NULL, context->ifindex );
+ require_noerr( err, exit );
+
+ err = setsockopt( sockV6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
+ err = map_socket_noerr_errno( sockV6, err );
+ require_noerr( err, exit );
+ }
+
+ // Print prologue.
+
+ SSDPDiscoverPrintPrologue( context );
+
+ // Send mDNS query message.
+
+ sendCount = 0;
+ if( IsValidSocket( sockV4 ) )
+ {
+ struct sockaddr_in mcastAddr4;
+
+ memset( &mcastAddr4, 0, sizeof( mcastAddr4 ) );
+ SIN_LEN_SET( &mcastAddr4 );
+ mcastAddr4.sin_family = AF_INET;
+ mcastAddr4.sin_port = htons( kSSDPPort );
+ mcastAddr4.sin_addr.s_addr = htonl( 0xEFFFFFFA ); // 239.255.255.250
+
+ err = WriteSSDPSearchRequest( &context->header, &mcastAddr4, gSSDPDiscover_MX, gSSDPDiscover_ST );
+ require_noerr( err, exit );
+
+ n = sendto( sockV4, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr4,
+ (socklen_t) sizeof( mcastAddr4 ) );
+ err = map_socket_value_errno( sockV4, n == (ssize_t) context->header.len, n );
+ if( err )
+ {
+ FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
+ ForgetSocket( &sockV4 );
+ }
+ else
+ {
+ if( gSSDPDiscover_Verbose )
+ {
+ gettimeofday( &now, NULL );
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "Send time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source Port: %d\n", SocketToPortNumber( sockV4 ) );
+ FPrintF( stdout, "Destination: %##a\n", &mcastAddr4 );
+ FPrintF( stdout, "Message size: %zu\n", context->header.len );
+ FPrintF( stdout, "HTTP header:\n%1{text}", context->header.buf, context->header.len );
+ }
+ ++sendCount;
+ }
+ }
+
+ if( IsValidSocket( sockV6 ) )
+ {
+ struct sockaddr_in6 mcastAddr6;
+
+ memset( &mcastAddr6, 0, sizeof( mcastAddr6 ) );
+ SIN6_LEN_SET( &mcastAddr6 );
+ mcastAddr6.sin6_family = AF_INET6;
+ mcastAddr6.sin6_port = htons( kSSDPPort );
+ mcastAddr6.sin6_addr.s6_addr[ 0 ] = 0xFF; // SSDP IPv6 link-local multicast address FF02::C
+ mcastAddr6.sin6_addr.s6_addr[ 1 ] = 0x02;
+ mcastAddr6.sin6_addr.s6_addr[ 15 ] = 0x0C;
+
+ err = WriteSSDPSearchRequest( &context->header, &mcastAddr6, gSSDPDiscover_MX, gSSDPDiscover_ST );
+ require_noerr( err, exit );
+
+ n = sendto( sockV6, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr6,
+ (socklen_t) sizeof( mcastAddr6 ) );
+ err = map_socket_value_errno( sockV6, n == (ssize_t) context->header.len, n );
+ if( err )
+ {
+ FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
+ ForgetSocket( &sockV6 );
+ }
+ else
+ {
+ if( gSSDPDiscover_Verbose )
+ {
+ gettimeofday( &now, NULL );
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "Send time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source Port: %d\n", SocketToPortNumber( sockV6 ) );
+ FPrintF( stdout, "Destination: %##a\n", &mcastAddr6 );
+ FPrintF( stdout, "Message size: %zu\n", context->header.len );
+ FPrintF( stdout, "HTTP header:\n%1{text}", context->header.buf, context->header.len );
+ }
+ ++sendCount;
+ }
+ }
+ require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
+
+ // If there's no wait period after the send, then exit.
+
+ if( context->receiveSecs == 0 ) goto exit;
+
+ // Create dispatch read sources for socket(s).
+
+ if( IsValidSocket( sockV4 ) )
+ {
+ SocketContext * sockCtx;
+
+ err = SocketContextCreate( sockV4, context, &sockCtx );
+ require_noerr( err, exit );
+ sockV4 = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSourceV4 );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSourceV4 );
+ }
+
+ if( IsValidSocket( sockV6 ) )
+ {
+ SocketContext * sockCtx;
+
+ err = SocketContextCreate( sockV6, context, &sockCtx );
+ require_noerr( err, exit );
+ sockV6 = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
+ &context->readSourceV6 );
+ if( err ) ForgetSocketContext( &sockCtx );
+ require_noerr( err, exit );
+
+ dispatch_resume( context->readSourceV6 );
+ }
+
+ if( context->receiveSecs > 0 )
+ {
+ dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+ Exit );
+ }
+ dispatch_main();
+
+exit:
+ ForgetSocket( &sockV4 );
+ ForgetSocket( &sockV6 );
+ dispatch_source_forget( &signalSource );
+ exit( err ? 1 : 0 );
+}
+
+static int SocketToPortNumber( SocketRef inSock )
+{
+ OSStatus err;
+ sockaddr_ip sip;
+ socklen_t len;
+
+ len = (socklen_t) sizeof( sip );
+ err = getsockname( inSock, &sip.sa, &len );
+ err = map_socket_noerr_errno( inSock, err );
+ check_noerr( err );
+ return( err ? -1 : SockAddrGetPort( &sip ) );
+}
+
+static OSStatus WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST )
+{
+ OSStatus err;
+
+ err = HTTPHeader_InitRequest( inHeader, "M-SEARCH", "*", "HTTP/1.1" );
+ require_noerr( err, exit );
+
+ err = HTTPHeader_SetField( inHeader, "Host", "%##a", inHostSA );
+ require_noerr( err, exit );
+
+ err = HTTPHeader_SetField( inHeader, "ST", "%s", inST ? inST : "ssdp:all" );
+ require_noerr( err, exit );
+
+ err = HTTPHeader_SetField( inHeader, "Man", "\"ssdp:discover\"" );
+ require_noerr( err, exit );
+
+ err = HTTPHeader_SetField( inHeader, "MX", "%d", inMX );
+ require_noerr( err, exit );
+
+ err = HTTPHeader_Commit( inHeader );
+ require_noerr( err, exit );
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// SSDPDiscoverPrintPrologue
+//===========================================================================================================================
+
+static void SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext )
+{
+ const int receiveSecs = inContext->receiveSecs;
+ const char * ifName;
+ char ifNameBuf[ IF_NAMESIZE + 1 ];
+ NetTransportType ifType;
+
+ ifName = if_indextoname( inContext->ifindex, ifNameBuf );
+
+ ifType = kNetTransportType_Undefined;
+ if( ifName ) SocketGetInterfaceInfo( kInvalidSocketRef, ifName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ifType );
+
+ FPrintF( stdout, "Interface: %s/%d/%s\n",
+ ifName ? ifName : "?", inContext->ifindex, NetTransportTypeToString( ifType ) );
+ FPrintF( stdout, "IP protocols: %?s%?s%?s\n",
+ inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
+ FPrintF( stdout, "Receive duration: " );
+ if( receiveSecs >= 0 ) FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
+ else FPrintF( stdout, "∞\n" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+}
+
+//===========================================================================================================================
+// SSDPDiscoverReadHandler
+//===========================================================================================================================
+
+static Boolean _HTTPHeader_Validate( HTTPHeader *inHeader );
+
+static void SSDPDiscoverReadHandler( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ SSDPDiscoverContext * const context = (SSDPDiscoverContext *) sockCtx->userContext;
+ HTTPHeader * const header = &context->header;
+ sockaddr_ip fromAddr;
+ size_t msgLen;
+
+ gettimeofday( &now, NULL );
+
+ err = SocketRecvFrom( sockCtx->sock, header->buf, sizeof( header->buf ), &msgLen, &fromAddr, sizeof( fromAddr ),
+ NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "Receive time: %{du:time}\n", &now );
+ FPrintF( stdout, "Source: %##a\n", &fromAddr );
+ FPrintF( stdout, "Message size: %zu\n", msgLen );
+ header->len = msgLen;
+ if( _HTTPHeader_Validate( header ) )
+ {
+ FPrintF( stdout, "HTTP header:\n%1{text}", header->buf, header->len );
+ if( header->extraDataLen > 0 )
+ {
+ FPrintF( stdout, "HTTP body: %1.1H", header->extraDataPtr, (int) header->extraDataLen, INT_MAX );
+ }
+ }
+ else
+ {
+ FPrintF( stdout, "Invalid HTTP message:\n%1.1H", header->buf, (int) msgLen, INT_MAX );
+ goto exit;
+ }
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// _HTTPHeader_Validate
+//
+// Parses for the end of an HTTP header and updates the HTTPHeader structure so it's ready to parse. Returns true if valid.
+// This assumes the "buf" and "len" fields are set. The other fields are set by this function.
+//
+// Note: This was copied from CoreUtils because the HTTPHeader_Validate function is currently not exported in the framework.
+//===========================================================================================================================
+
+static Boolean _HTTPHeader_Validate( HTTPHeader *inHeader )
+{
+ const char * src;
+ const char * end;
+
+ // Check for interleaved binary data (4 byte header that begins with $). See RFC 2326 section 10.12.
+
+ require( inHeader->len < sizeof( inHeader->buf ), exit );
+ src = inHeader->buf;
+ end = src + inHeader->len;
+ if( ( ( end - src ) >= 4 ) && ( src[ 0 ] == '$' ) )
+ {
+ src += 4;
+ }
+ else
+ {
+ // Search for an empty line (HTTP-style header/body separator). CRLFCRLF, LFCRLF, or LFLF accepted.
+ // $$$ TO DO: Start from the last search location to avoid re-searching the same data over and over.
+
+ for( ;; )
+ {
+ while( ( src < end ) && ( src[ 0 ] != '\n' ) ) ++src;
+ if( src >= end ) goto exit;
+ ++src;
+ if( ( ( end - src ) >= 2 ) && ( src[ 0 ] == '\r' ) && ( src[ 1 ] == '\n' ) ) // CFLFCRLF or LFCRLF
+ {
+ src += 2;
+ break;
+ }
+ else if( ( ( end - src ) >= 1 ) && ( src[ 0 ] == '\n' ) ) // LFLF
+ {
+ src += 1;
+ break;
+ }
+ }
+ }
+ inHeader->extraDataPtr = src;
+ inHeader->extraDataLen = (size_t)( end - src );
+ inHeader->len = (size_t)( src - inHeader->buf );
+ return( true );
+
+exit:
+ return( false );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// ResQueryCmd
+//===========================================================================================================================
+
+// res_query() from libresolv is actually called res_9_query (see /usr/include/resolv.h).
+
+SOFT_LINK_LIBRARY_EX( "/usr/lib", resolv );
+SOFT_LINK_FUNCTION_EX( resolv, res_9_query,
+ int,
+ ( const char *dname, int class, int type, u_char *answer, int anslen ),
+ ( dname, class, type, answer, anslen ) );
+
+// res_query() from libinfo
+
+SOFT_LINK_LIBRARY_EX( "/usr/lib", info );
+SOFT_LINK_FUNCTION_EX( info, res_query,
+ int,
+ ( const char *dname, int class, int type, u_char *answer, int anslen ),
+ ( dname, class, type, answer, anslen ) );
+
+typedef int ( *res_query_f )( const char *dname, int class, int type, u_char *answer, int anslen );
+
+static void ResQueryCmd( void )
+{
+ OSStatus err;
+ res_query_f res_query_ptr;
+ int n;
+ uint16_t type, class;
+ uint8_t answer[ 1024 ];
+
+ // Get pointer to one of the res_query() functions.
+
+ if( gResQuery_UseLibInfo )
+ {
+ if( !SOFT_LINK_HAS_FUNCTION( info, res_query ) )
+ {
+ FPrintF( stderr, "Failed to soft link res_query from libinfo.\n" );
+ err = kNotFoundErr;
+ goto exit;
+ }
+ res_query_ptr = soft_res_query;
+ }
+ else
+ {
+ if( !SOFT_LINK_HAS_FUNCTION( resolv, res_9_query ) )
+ {
+ FPrintF( stderr, "Failed to soft link res_query from libresolv.\n" );
+ err = kNotFoundErr;
+ goto exit;
+ }
+ res_query_ptr = soft_res_9_query;
+ }
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gResQuery_Type, &type );
+ require_noerr( err, exit );
+
+ // Get record class.
+
+ if( gResQuery_Class )
+ {
+ err = RecordClassFromArgString( gResQuery_Class, &class );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ class = kDNSServiceClass_IN;
+ }
+
+ // Print prologue.
+
+ FPrintF( stdout, "Name: %s\n", gResQuery_Name );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
+ FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ // Call res_query().
+
+ n = res_query_ptr( gResQuery_Name, class, type, (u_char *) answer, (int) sizeof( answer ) );
+ if( n < 0 )
+ {
+ FPrintF( stderr, "res_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
+ err = kUnknownErr;
+ goto exit;
+ }
+
+ // Print result.
+
+ FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// ResolvDNSQueryCmd
+//===========================================================================================================================
+
+// dns_handle_t is defined as a pointer to a privately-defined struct in /usr/include/dns.h. It's defined as a void * here to
+// avoid including the header file.
+
+typedef void * dns_handle_t;
+
+SOFT_LINK_FUNCTION_EX( resolv, dns_open, dns_handle_t, ( const char *path ), ( path ) );
+SOFT_LINK_FUNCTION_VOID_RETURN_EX( resolv, dns_free, ( dns_handle_t *dns ), ( dns ) );
+SOFT_LINK_FUNCTION_EX( resolv, dns_query,
+ int32_t, (
+ dns_handle_t dns,
+ const char * name,
+ uint32_t dnsclass,
+ uint32_t dnstype,
+ char * buf,
+ uint32_t len,
+ struct sockaddr * from,
+ uint32_t * fromlen ),
+ ( dns, name, dnsclass, dnstype, buf, len, from, fromlen ) );
+
+static void ResolvDNSQueryCmd( void )
+{
+ OSStatus err;
+ int n;
+ dns_handle_t dns = NULL;
+ uint16_t type, class;
+ sockaddr_ip from;
+ uint32_t fromLen;
+ uint8_t answer[ 1024 ];
+
+ // Make sure that the required symbols are available.
+
+ if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_open ) )
+ {
+ FPrintF( stderr, "Failed to soft link dns_open from libresolv.\n" );
+ err = kNotFoundErr;
+ goto exit;
+ }
+
+ if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_free ) )
+ {
+ FPrintF( stderr, "Failed to soft link dns_free from libresolv.\n" );
+ err = kNotFoundErr;
+ goto exit;
+ }
+
+ if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_query ) )
+ {
+ FPrintF( stderr, "Failed to soft link dns_query from libresolv.\n" );
+ err = kNotFoundErr;
+ goto exit;
+ }
+
+ // Get record type.
+
+ err = RecordTypeFromArgString( gResolvDNSQuery_Type, &type );
+ require_noerr( err, exit );
+
+ // Get record class.
+
+ if( gResolvDNSQuery_Class )
+ {
+ err = RecordClassFromArgString( gResolvDNSQuery_Class, &class );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ class = kDNSServiceClass_IN;
+ }
+
+ // Get dns handle.
+
+ dns = soft_dns_open( gResolvDNSQuery_Path );
+ if( !dns )
+ {
+ FPrintF( stderr, "dns_open( %s ) failed.\n", gResolvDNSQuery_Path );
+ err = kUnknownErr;
+ goto exit;
+ }
+
+ // Print prologue.
+
+ FPrintF( stdout, "Name: %s\n", gResolvDNSQuery_Name );
+ FPrintF( stdout, "Type: %s (%u)\n", RecordTypeToString( type ), type );
+ FPrintF( stdout, "Class: %s (%u)\n", ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+ FPrintF( stdout, "Path: %s\n", gResolvDNSQuery_Path ? gResolvDNSQuery_Name : "<NULL>" );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ // Call dns_query().
+
+ memset( &from, 0, sizeof( from ) );
+ fromLen = (uint32_t) sizeof( from );
+ n = soft_dns_query( dns, gResolvDNSQuery_Name, class, type, (char *) answer, (uint32_t) sizeof( answer ), &from.sa,
+ &fromLen );
+ if( n < 0 )
+ {
+ FPrintF( stderr, "dns_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
+ err = kUnknownErr;
+ goto exit;
+ }
+
+ // Print result.
+
+ FPrintF( stdout, "From: %##a\n", &from );
+ FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
+
+exit:
+ if( dns ) soft_dns_free( dns );
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// CFHostCmd
+//===========================================================================================================================
+
+static void
+ _CFHostResolveCallback(
+ CFHostRef inHost,
+ CFHostInfoType inInfoType,
+ const CFStreamError * inError,
+ void * inInfo );
+
+static void CFHostCmd( void )
+{
+ OSStatus err;
+ CFStringRef name;
+ Boolean success;
+ CFHostRef host = NULL;
+ CFHostClientContext context;
+ CFStreamError streamErr;
+
+ name = CFStringCreateWithCString( kCFAllocatorDefault, gCFHost_Name, kCFStringEncodingUTF8 );
+ require_action( name, exit, err = kUnknownErr );
+
+ host = CFHostCreateWithName( kCFAllocatorDefault, name );
+ ForgetCF( &name );
+ require_action( host, exit, err = kUnknownErr );
+
+ memset( &context, 0, sizeof( context ) );
+ success = CFHostSetClient( host, _CFHostResolveCallback, &context );
+ require_action( success, exit, err = kUnknownErr );
+
+ CFHostScheduleWithRunLoop( host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
+
+ // Print prologue.
+
+ FPrintF( stdout, "Hostname: %s\n", gCFHost_Name );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ success = CFHostStartInfoResolution( host, kCFHostAddresses, &streamErr );
+ require_action( success, exit, err = kUnknownErr );
+ err = kNoErr;
+
+ CFRunLoopRun();
+
+exit:
+ CFReleaseNullSafe( host );
+ if( err ) exit( 1 );
+}
+
+static void _CFHostResolveCallback( CFHostRef inHost, CFHostInfoType inInfoType, const CFStreamError *inError, void *inInfo )
+{
+ OSStatus err;
+ struct timeval now;
+
+ gettimeofday( &now, NULL );
+
+ Unused( inInfoType );
+ Unused( inInfo );
+
+ if( inError && ( inError->domain != 0 ) && ( inError->error ) )
+ {
+ err = inError->error;
+ if( inError->domain == kCFStreamErrorDomainNetDB )
+ {
+ FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
+ }
+ else
+ {
+ FPrintF( stderr, "Error %#m\n", err );
+ }
+ }
+ else
+ {
+ CFArrayRef addresses;
+ CFIndex count, i;
+ CFDataRef addrData;
+ const struct sockaddr * sockAddr;
+ Boolean wasResolved = false;
+
+ addresses = CFHostGetAddressing( inHost, &wasResolved );
+ check( wasResolved );
+
+ if( addresses )
+ {
+ count = CFArrayGetCount( addresses );
+ for( i = 0; i < count; ++i )
+ {
+ addrData = CFArrayGetCFDataAtIndex( addresses, i, &err );
+ require_noerr( err, exit );
+
+ sockAddr = (const struct sockaddr *) CFDataGetBytePtr( addrData );
+ FPrintF( stdout, "%##a\n", sockAddr );
+ }
+ }
+ err = kNoErr;
+ }
+
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %{du:time}\n", &now );
+
+ if( gCFHost_WaitSecs > 0 ) sleep( (unsigned int) gCFHost_WaitSecs );
+
+exit:
+ exit( err ? 1 : 0 );
+}
+
+//===========================================================================================================================
+// DNSConfigAddCmd
+//
+// Note: Based on ajn's supplemental test tool.
+//===========================================================================================================================
+
+static void DNSConfigAddCmd( void )
+{
+ OSStatus err;
+ CFMutableDictionaryRef dict = NULL;
+ CFMutableArrayRef array = NULL;
+ size_t i;
+ SCDynamicStoreRef store = NULL;
+ CFStringRef key = NULL;
+ Boolean success;
+
+ // Create dictionary.
+
+ dict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
+ require_action( dict, exit, err = kNoMemoryErr );
+
+ // Add DNS server IP addresses.
+
+ array = CFArrayCreateMutable( NULL, (CFIndex) gDNSConfigAdd_IPAddrCount, &kCFTypeArrayCallBacks );
+ require_action( array, exit, err = kNoMemoryErr );
+
+ for( i = 0; i < gDNSConfigAdd_IPAddrCount; ++i )
+ {
+ CFStringRef addrStr;
+
+ addrStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_IPAddrArray[ i ], kCFStringEncodingUTF8 );
+ require_action( addrStr, exit, err = kUnknownErr );
+
+ CFArrayAppendValue( array, addrStr );
+ CFRelease( addrStr );
+ }
+
+ CFDictionarySetValue( dict, kSCPropNetDNSServerAddresses, array );
+ ForgetCF( &array );
+
+ // Add domains, if any.
+
+ array = CFArrayCreateMutable( NULL, (CFIndex) Min( gDNSConfigAdd_DomainCount, 1 ), &kCFTypeArrayCallBacks );
+ require_action( array, exit, err = kNoMemoryErr );
+
+ if( gDNSConfigAdd_DomainCount > 0 )
+ {
+ for( i = 0; i < gDNSConfigAdd_DomainCount; ++i )
+ {
+ CFStringRef domainStr;
+
+ domainStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_DomainArray[ i ], kCFStringEncodingUTF8 );
+ require_action( domainStr, exit, err = kUnknownErr );
+
+ CFArrayAppendValue( array, domainStr );
+ CFRelease( domainStr );
+ }
+ }
+ else
+ {
+ // There are no domains, but the domain array needs to be non-empty, so add a zero-length string to the array.
+
+ CFArrayAppendValue( array, CFSTR( "" ) );
+ }
+
+ CFDictionarySetValue( dict, kSCPropNetDNSSupplementalMatchDomains, array );
+ ForgetCF( &array );
+
+ // Add interface, if any.
+
+ if( gDNSConfigAdd_Interface )
+ {
+ err = CFDictionarySetCString( dict, kSCPropInterfaceName, gDNSConfigAdd_Interface, kSizeCString );
+ require_noerr( err, exit );
+
+ CFDictionarySetValue( dict, kSCPropNetDNSConfirmedServiceID, gDNSConfigAdd_ID );
+ }
+
+ // Set dictionary in dynamic store.
+
+ store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+ err = map_scerror( store );
+ require_noerr( err, exit );
+
+ key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigAdd_ID, kSCEntNetDNS );
+ require_action( key, exit, err = kUnknownErr );
+
+ success = SCDynamicStoreSetValue( store, key, dict );
+ require_action( success, exit, err = kUnknownErr );
+
+exit:
+ CFReleaseNullSafe( dict );
+ CFReleaseNullSafe( array );
+ CFReleaseNullSafe( store );
+ CFReleaseNullSafe( key );
+ gExitCode = err ? 1 : 0;
+}
+
+//===========================================================================================================================
+// DNSConfigRemoveCmd
+//===========================================================================================================================
+
+static void DNSConfigRemoveCmd( void )
+{
+ OSStatus err;
+ SCDynamicStoreRef store = NULL;
+ CFStringRef key = NULL;
+ Boolean success;
+
+ store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+ err = map_scerror( store );
+ require_noerr( err, exit );
+
+ key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigRemove_ID, kSCEntNetDNS );
+ require_action( key, exit, err = kUnknownErr );
+
+ success = SCDynamicStoreRemoveValue( store, key );
+ require_action( success, exit, err = kUnknownErr );
+
+exit:
+ CFReleaseNullSafe( store );
+ CFReleaseNullSafe( key );
+ gExitCode = err ? 1 : 0;
+}
+
+//===========================================================================================================================
+// XPCSendCmd
+//===========================================================================================================================
+
+static OSStatus _XPCDictionaryCreateFromString( const char *inString, xpc_object_t *outDict );
+
+static void XPCSendCmd( void )
+{
+ OSStatus err;
+ xpc_object_t msg, reply;
+
+ err = _XPCDictionaryCreateFromString( gXPCSend_MessageStr, &msg );
+ require_noerr_quiet( err, exit );
+
+ FPrintF( stdout, "Service: %s\n", gXPCSend_ServiceName );
+ FPrintF( stdout, "Message: %s\n", gXPCSend_MessageStr );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "XPC Message:\n%{xpc}\n", msg );
+
+ err = xpc_send_message_sync( gXPCSend_ServiceName, 0, 0, msg, &reply );
+ xpc_forget( &msg );
+ require_noerr_quiet( err, exit );
+
+ FPrintF( stdout, "XPC Reply:\n%{xpc}\n", reply );
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %{du:time}\n", NULL );
+ xpc_forget( &reply );
+
+exit:
+ if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+// _XPCDictionaryCreateFromString
+//===========================================================================================================================
+
+#define kXPCObjectPrefix_Bool "bool:"
+#define kXPCObjectPrefix_Data "data:"
+#define kXPCObjectPrefix_Int64 "int:"
+#define kXPCObjectPrefix_String "string:"
+#define kXPCObjectPrefix_UInt64 "uint:"
+#define kXPCObjectPrefix_UUID "uuid:"
+
+typedef struct XPCListItem XPCListItem;
+struct XPCListItem
+{
+ XPCListItem * next;
+ xpc_object_t obj;
+ char * key;
+};
+
+static OSStatus _XPCListItemCreate( xpc_object_t inObject, const char *inKey, XPCListItem **outItem );
+static void _XPCListItemFree( XPCListItem *inItem );
+static void _XPCListFree( XPCListItem *inList );
+
+static OSStatus _XPCObjectFromString( const char *inString, xpc_object_t *outObject );
+
+static OSStatus _XPCDictionaryCreateFromString( const char *inString, xpc_object_t *outDict )
+{
+ OSStatus err;
+ xpc_object_t container;
+ const char * ptr = inString;
+ const char * const end = inString + strlen( inString );
+ XPCListItem * list = NULL;
+
+ container = xpc_dictionary_create( NULL, NULL, 0 );
+ require_action( container, exit, err = kNoMemoryErr );
+
+ while( *ptr )
+ {
+ xpc_type_t containerType;
+ xpc_object_t value;
+ int c;
+ char keyStr[ 256 ];
+ char valStr[ 256 ];
+
+ // At this point, zero or more of the current container's elements have been parsed.
+ // Skip the white space leading up to the container's next element, if any, or the container's end.
+
+ while( isspace_safe( *ptr ) ) ++ptr;
+
+ // Check if we're done with the current container.
+
+ c = *ptr;
+ if( c == '\0' ) break;
+
+ containerType = xpc_get_type( container );
+ if( ( ( containerType == XPC_TYPE_DICTIONARY ) && ( c == '}' ) ) ||
+ ( ( containerType == XPC_TYPE_ARRAY ) && ( c == ']' ) ) )
+ {
+ XPCListItem * item;
+
+ item = list;
+ require_action_quiet( item, exit, err = kMalformedErr );
+
+ ++ptr;
+
+ // Add the current container to its parent container.
+
+ if( item->key )
+ {
+ xpc_dictionary_set_value( item->obj, item->key, container );
+ }
+ else
+ {
+ xpc_array_append_value( item->obj, container );
+ }
+
+ // Continue with the parent container.
+
+ xpc_release( container );
+ container = xpc_retain( item->obj );
+ list = item->next;
+ _XPCListItemFree( item );
+ continue;
+ }
+
+ // If the current container is a dictionary, parse the key string.
+
+ if( containerType == XPC_TYPE_DICTIONARY )
+ {
+ err = _ParseEscapedString( ptr, end, "={}[]" kWhiteSpaceCharSet, keyStr, sizeof( keyStr ), NULL, NULL, &ptr );
+ require_noerr_quiet( err, exit );
+
+ c = *ptr;
+ require_action_quiet( c == '=', exit, err = kMalformedErr );
+ ++ptr;
+ }
+
+ // Check if the value is a dictionary ({...}) or an array ([...]).
+
+ c = *ptr;
+ if( ( c == '{' ) || ( c == '[' ) )
+ {
+ XPCListItem * item;
+
+ ++ptr;
+
+ // Save the current container.
+
+ err = _XPCListItemCreate( container, ( containerType == XPC_TYPE_DICTIONARY ) ? keyStr : NULL, &item );
+ require_noerr( err, exit );
+
+ item->next = list;
+ list = item;
+ item = NULL;
+
+ // Create and continue with the child container.
+
+ xpc_release( container );
+ if( c == '{' )
+ {
+ container = xpc_dictionary_create( NULL, NULL, 0 );
+ require_action( container, exit, err = kNoMemoryErr );
+ }
+ else
+ {
+ container = xpc_array_create( NULL, 0 );
+ require_action( container, exit, err = kNoMemoryErr );
+ }
+ continue;
+ }
+
+ // Parse the value string.
+
+ err = _ParseEscapedString( ptr, end, "{}[]" kWhiteSpaceCharSet, valStr, sizeof( valStr ), NULL, NULL, &ptr );
+ require_noerr_quiet( err, exit );
+
+ err = _XPCObjectFromString( valStr, &value );
+ require_noerr_quiet( err, exit );
+
+ if( containerType == XPC_TYPE_DICTIONARY )
+ {
+ xpc_dictionary_set_value( container, keyStr, value );
+ }
+ else
+ {
+ xpc_array_append_value( container, value );
+ }
+ xpc_forget( &value );
+ }
+ require_action_quiet( !list, exit, err = kMalformedErr );
+
+ check( container );
+ check( xpc_get_type( container ) == XPC_TYPE_DICTIONARY );
+
+ *outDict = container;
+ container = NULL;
+ err = kNoErr;
+
+exit:
+ xpc_release_null_safe( container );
+ if( list ) _XPCListFree( list );
+ return( err );
+}
+
+static OSStatus _XPCObjectFromString( const char *inString, xpc_object_t *outObject )
+{
+ OSStatus err;
+ xpc_object_t object;
+
+ if( 0 ) {}
+
+ // Bool
+
+ else if( stricmp_prefix( inString, kXPCObjectPrefix_Bool ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kXPCObjectPrefix_Bool );
+ bool value;
+
+ if( IsTrueString( str, kSizeCString ) )
+ {
+ value = true;
+ }
+ else if( IsFalseString( str, kSizeCString ) )
+ {
+ value = false;
+ }
+ else
+ {
+ err = kValueErr;
+ goto exit;
+ }
+
+ object = xpc_bool_create( value );
+ require_action( object, exit, err = kNoMemoryErr );
+ }
+
+ // Data
+
+ else if( stricmp_prefix( inString, kXPCObjectPrefix_Data ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kXPCObjectPrefix_Data );
+ uint8_t * dataPtr;
+ size_t dataLen;
+
+ err = HexToDataCopy( str, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
+ require_noerr( err, exit );
+
+ object = xpc_data_create( dataPtr, dataLen );
+ free( dataPtr );
+ require_action( object, exit, err = kNoMemoryErr );
+ }
+
+ // Int64
+
+ else if( stricmp_prefix( inString, kXPCObjectPrefix_Int64 ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kXPCObjectPrefix_Int64 );
+ int64_t i64;
+
+ i64 = _StringToInt64( str, &err );
+ require_noerr_quiet( err, exit );
+
+ object = xpc_int64_create( i64 );
+ require_action( object, exit, err = kNoMemoryErr );
+ }
+
+ // String
+
+ else if( stricmp_prefix( inString, kXPCObjectPrefix_String ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kXPCObjectPrefix_String );
+
+ object = xpc_string_create( str );
+ require_action( object, exit, err = kNoMemoryErr );
+ }
+
+ // UInt64
+
+ else if( stricmp_prefix( inString, kXPCObjectPrefix_UInt64 ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kXPCObjectPrefix_UInt64 );
+ uint64_t u64;
+
+ u64 = _StringToUInt64( str, &err );
+ require_noerr_quiet( err, exit );
+
+ object = xpc_uint64_create( u64 );
+ require_action( object, exit, err = kNoMemoryErr );
+ }
+
+ // UUID
+
+ else if( stricmp_prefix( inString, kXPCObjectPrefix_UUID ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kXPCObjectPrefix_UUID );
+ uuid_t uuid;
+
+ err = uuid_parse( str, uuid );
+ require_noerr_action_quiet( err, exit, err = kValueErr );
+
+ object = xpc_uuid_create( uuid );
+ require_action( object, exit, err = kNoMemoryErr );
+ }
+
+ // Unsupported prefix
+
+ else
+ {
+ err = kValueErr;
+ goto exit;
+ }
+
+ *outObject = object;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+static OSStatus _XPCListItemCreate( xpc_object_t inObject, const char *inKey, XPCListItem **outItem )
+{
+ OSStatus err;
+ XPCListItem * item;
+
+ item = (XPCListItem *) calloc( 1, sizeof( *item ) );
+ require_action( item, exit, err = kNoMemoryErr );
+
+ item->obj = xpc_retain( inObject );
+ if( ( xpc_get_type( item->obj ) == XPC_TYPE_DICTIONARY ) && inKey )
+ {
+ item->key = strdup( inKey );
+ require_action( item->key, exit, err = kNoMemoryErr );
+ }
+
+ *outItem = item;
+ item = NULL;
+ err = kNoErr;
+
+exit:
+ if( item ) _XPCListItemFree( item );
+ return( err );
+}
+
+static void _XPCListItemFree( XPCListItem *inItem )
+{
+ xpc_forget( &inItem->obj );
+ ForgetMem( &inItem->key );
+ free( inItem );
+}
+
+static void _XPCListFree( XPCListItem *inList )
+{
+ XPCListItem * item;
+
+ while( ( item = inList ) != NULL )
+ {
+ inList = item->next;
+ _XPCListItemFree( item );
+ }
+}
+#endif // TARGET_OS_DARWIN
+
+#if( MDNSRESPONDER_PROJECT )
+//===========================================================================================================================
+// InterfaceMonitorCmd
+//===========================================================================================================================
+
+static void _InterfaceMonitorPrint( mdns_interface_monitor_t inMonitor );
+static void _InterfaceMonitorSignalHandler( void *inContext );
+
+static void InterfaceMonitorCmd( void )
+{
+ OSStatus err;
+ mdns_interface_monitor_t monitor;
+ dispatch_source_t signalSource = NULL;
+ uint32_t ifIndex;
+ __block int exitCode;
+
+ err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ monitor = mdns_interface_monitor_create( ifIndex );
+ require_action( monitor, exit, err = kNoResourcesErr );
+
+ exitCode = 0;
+ mdns_interface_monitor_set_queue( monitor, dispatch_get_main_queue() );
+ mdns_interface_monitor_set_event_handler( monitor,
+ ^( mdns_event_t inEvent, OSStatus inError )
+ {
+ switch( inEvent )
+ {
+ case mdns_event_error:
+ FPrintF( stderr, "error: Interface monitor failed: %#m\n", inError );
+ mdns_interface_monitor_invalidate( monitor );
+ exitCode = 1;
+ break;
+
+ case mdns_event_invalidated:
+ FPrintF( stdout, "Interface monitor invalidated.\n" );
+ mdns_release( monitor );
+ exit( exitCode );
+
+ default:
+ FPrintF( stdout, "Unhandled event '%s' (%ld)\n", mdns_event_to_string( inEvent ), (long) inEvent );
+ break;
+ }
+ } );
+ mdns_interface_monitor_set_update_handler( monitor,
+ ^( __unused mdns_interface_flags_t inChangeFlags )
+ {
+ _InterfaceMonitorPrint( monitor );
+ } );
+
+ _InterfaceMonitorPrint( monitor );
+ mdns_interface_monitor_activate( monitor );
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, _InterfaceMonitorSignalHandler, monitor, &signalSource );
+ require_noerr( err, exit );
+ dispatch_resume( signalSource );
+
+ dispatch_main();
+
+exit:
+ if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+static void _InterfaceMonitorPrint( mdns_interface_monitor_t inMonitor )
+{
+ FPrintF( stdout, "%{du:time} %@\n", NULL, inMonitor );
+}
+
+static void _InterfaceMonitorSignalHandler( void *inContext )
+{
+ mdns_interface_monitor_invalidate( (mdns_interface_monitor_t) inContext );
+}
+
+//===========================================================================================================================
+// DNSProxyCmd
+//===========================================================================================================================
+
+static void _DNSProxyCallback( DNSXConnRef inConnection, DNSXErrorType inError );
+static void _DNSProxyCmdSignalHandler( void *inContext );
+
+static void DNSProxyCmd( void )
+{
+ OSStatus err;
+ size_t i;
+ DNSXConnRef connection;
+ IfIndex inputIfIndexes[ MaxInputIf ];
+ dispatch_source_t sigIntSource = NULL;
+ dispatch_source_t sigTermSource = NULL;
+ uint32_t outputIfIndex;
+ char ifName[ kInterfaceNameBufLen ];
+
+ if( gDNSProxy_InputInterfaceCount > MaxInputIf )
+ {
+ FPrintF( stderr, "error: Invalid input interface count: %zu > %d (max).\n",
+ gDNSProxy_InputInterfaceCount, MaxInputIf );
+ err = kRangeErr;
+ goto exit;
+ }
+
+ for( i = 0; i < gDNSProxy_InputInterfaceCount; ++i )
+ {
+ uint32_t ifIndex;
+
+ err = InterfaceIndexFromArgString( gDNSProxy_InputInterfaces[ i ], &ifIndex );
+ require_noerr_quiet( err, exit );
+
+ inputIfIndexes[ i ] = ifIndex;
+ }
+ while( i < MaxInputIf ) inputIfIndexes[ i++ ] = 0; // Remaining interface indexes are required to be 0.
+
+ if( gDNSProxy_OutputInterface )
+ {
+ err = InterfaceIndexFromArgString( gDNSProxy_OutputInterface, &outputIfIndex );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ outputIfIndex = kDNSIfindexAny;
+ }
+
+ FPrintF( stdout, "Input Interfaces:" );
+ for( i = 0; i < gDNSProxy_InputInterfaceCount; ++i )
+ {
+ const uint32_t ifIndex = (uint32_t) inputIfIndexes[ i ];
+
+ FPrintF( stdout, "%s %u (%s)", ( i == 0 ) ? "" : ",", ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+ }
+ FPrintF( stdout, "\n" );
+ FPrintF( stdout, "Output Interface: %u (%s)\n", outputIfIndex, InterfaceIndexToName( outputIfIndex, ifName ) );
+ FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+ FPrintF( stdout, "---\n" );
+
+ connection = NULL;
+ err = DNSXEnableProxy( &connection, kDNSProxyEnable, inputIfIndexes, outputIfIndex, dispatch_get_main_queue(),
+ _DNSProxyCallback );
+ require_noerr_quiet( err, exit );
+
+ signal( SIGINT, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGINT, _DNSProxyCmdSignalHandler, connection, &sigIntSource );
+ require_noerr( err, exit );
+ dispatch_activate( sigIntSource );
+
+ signal( SIGTERM, SIG_IGN );
+ err = DispatchSignalSourceCreate( SIGTERM, _DNSProxyCmdSignalHandler, connection, &sigTermSource );
+ require_noerr( err, exit );
+ dispatch_activate( sigTermSource );
+
+ dispatch_main();
+
+exit:
+ if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+static void _DNSProxyCallback( DNSXConnRef inConnection, DNSXErrorType inError )
+{
+ Unused( inConnection );
+
+ if( inError ) ErrQuit( 1, "error: DNS proxy failed: %#m\n", inError );
+}
+
+static void _DNSProxyCmdSignalHandler( void *inContext )
+{
+ DNSXConnRef const connection = (DNSXConnRef) inContext;
+ struct timeval now;
+
+ gettimeofday( &now, NULL );
+
+ DNSXRefDeAlloc( connection );
+
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %{du:time}\n", &now );
+ exit( 0 );
+}
+
+#endif // MDNSRESPONDER_PROJECT
+
+//===========================================================================================================================
+// DaemonVersionCmd
+//===========================================================================================================================
+
+static void DaemonVersionCmd( void )
+{
+ OSStatus err;
+ uint32_t size, version;
+ char strBuf[ 16 ];
+
+ size = (uint32_t) sizeof( version );
+ err = DNSServiceGetProperty( kDNSServiceProperty_DaemonVersion, &version, &size );
+ require_noerr( err, exit );
+
+ FPrintF( stdout, "Daemon version: %s\n", SourceVersionToCString( version, strBuf ) );
+
+exit:
+ if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+// Exit
+//===========================================================================================================================
+
+static void Exit( void *inContext )
+{
+ const char * const reason = (const char *) inContext;
+
+ FPrintF( stdout, "---\n" );
+ FPrintF( stdout, "End time: %{du:time}\n", NULL );
+ if( reason ) FPrintF( stdout, "End reason: %s\n", reason );
+ exit( gExitCode );
+}
+
+//===========================================================================================================================
+// _PrintFExtensionTimestampHandler
+//===========================================================================================================================
+
+static int
+ _PrintFExtensionTimestampHandler(
+ PrintFContext * inContext,
+ PrintFFormat * inFormat,
+ PrintFVAList * inArgs,
+ void * inUserContext )
+{
+ struct timeval now;
+ const struct timeval * tv;
+ struct tm * localTime;
+ size_t len;
+ int n;
+ char dateTimeStr[ 32 ];
+
+ Unused( inUserContext );
+
+ tv = va_arg( inArgs->args, const struct timeval * );
+ require_action_quiet( !inFormat->suppress, exit, n = 0 );
+
+ if( !tv )
+ {
+ gettimeofday( &now, NULL );
+ tv = &now;
+ }
+ localTime = localtime( &tv->tv_sec );
+ len = strftime( dateTimeStr, sizeof( dateTimeStr ), "%Y-%m-%d %H:%M:%S", localTime );
+ if( len == 0 ) dateTimeStr[ 0 ] = '\0';
+
+ n = PrintFCore( inContext, "%s.%06u", dateTimeStr, (unsigned int) tv->tv_usec );
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// _PrintFExtensionDNSMessageHandler
+//===========================================================================================================================
+
+static int
+ _PrintFExtensionDNSMessageHandler(
+ PrintFContext * inContext,
+ PrintFFormat * inFormat,
+ PrintFVAList * inArgs,
+ void * inUserContext )
+{
+ OSStatus err;
+ const void * msgPtr;
+ size_t msgLen;
+ char * text;
+ int n;
+ Boolean isMDNS;
+ Boolean printRawRData;
+
+ Unused( inUserContext );
+
+ msgPtr = va_arg( inArgs->args, const void * );
+ msgLen = va_arg( inArgs->args, size_t );
+ require_action_quiet( !inFormat->suppress, exit, n = 0 );
+
+ isMDNS = ( inFormat->altForm > 0 ) ? true : false;
+ printRawRData = ( inFormat->precision > 0 ) ? true : false;
+ err = DNSMessageToText( msgPtr, msgLen, isMDNS, printRawRData, &text );
+ if( !err )
+ {
+ n = PrintFCore( inContext, "%*{text}", inFormat->fieldWidth, text, kSizeCString );
+ free( text );
+ }
+ else
+ {
+ n = PrintFCore( inContext, "%*.1H", inFormat->fieldWidth, msgPtr, (int) msgLen, (int) msgLen );
+ }
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// _PrintFExtensionCallbackFlagsHandler
+//===========================================================================================================================
+
+static int
+ _PrintFExtensionCallbackFlagsHandler(
+ PrintFContext * inContext,
+ PrintFFormat * inFormat,
+ PrintFVAList * inArgs,
+ void * inUserContext )
+{
+ DNSServiceFlags flags;
+ int n;
+
+ Unused( inUserContext );
+
+ flags = va_arg( inArgs->args, DNSServiceFlags );
+ require_action_quiet( !inFormat->suppress, exit, n = 0 );
+
+ n = PrintFCore( inContext, "%08X %s%c %c%c",
+ flags, DNSServiceFlagsToAddRmvStr( flags ),
+ ( flags & kDNSServiceFlagsMoreComing ) ? '+' : ' ',
+ ( flags & kDNSServiceFlagAnsweredFromCache ) ? 'C' : ' ',
+ ( flags & kDNSServiceFlagsExpiredAnswer ) ? '*' : ' ' );
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// _PrintFExtensionDNSRecordDataHandler
+//===========================================================================================================================
+
+static int
+ _PrintFExtensionDNSRecordDataHandler(
+ PrintFContext * inContext,
+ PrintFFormat * inFormat,
+ PrintFVAList * inArgs,
+ void * inUserContext )
+{
+ const void * rdataPtr;
+ unsigned int rdataLen, rdataType;
+ int n, fieldWidth;
+
+ Unused( inUserContext );
+
+ rdataType = va_arg( inArgs->args, unsigned int );
+ rdataPtr = va_arg( inArgs->args, const void * );
+ rdataLen = va_arg( inArgs->args, unsigned int );
+ require_action_quiet( !inFormat->suppress, exit, n = 0 );
+
+ check( inFormat->fieldWidth < INT_MAX );
+ fieldWidth = inFormat->leftJustify ? -( (int) inFormat->fieldWidth ) : ( (int) inFormat->fieldWidth );
+
+ if( rdataLen > 0 )
+ {
+ char * rdataStr = NULL;
+
+ DNSRecordDataToString( rdataPtr, rdataLen, rdataType, NULL, 0, &rdataStr );
+ if( rdataStr )
+ {
+ n = PrintFCore( inContext, "%*s", fieldWidth, rdataStr );
+ free( rdataStr );
+ }
+ else
+ {
+ n = PrintFCore( inContext, "%*H", fieldWidth, rdataPtr, rdataLen, rdataLen );
+ }
+ }
+ else
+ {
+ n = PrintFCore( inContext, "%*s", fieldWidth, "<< ZERO-LENGTH RDATA >>" );
+ }
+
+exit:
+ return( n );
+}
+
+//===========================================================================================================================
+// GetDNSSDFlagsFromOpts
+//===========================================================================================================================
+
+static DNSServiceFlags GetDNSSDFlagsFromOpts( void )
+{
+ DNSServiceFlags flags;
+
+ flags = (DNSServiceFlags) gDNSSDFlags;
+ if( flags & kDNSServiceFlagsShareConnection )
+ {
+ FPrintF( stderr, "*** Warning: kDNSServiceFlagsShareConnection (0x%X) is explicitly set in flag parameters.\n",
+ kDNSServiceFlagsShareConnection );
+ }
+
+ if( gDNSSDFlag_AllowExpiredAnswers ) flags |= kDNSServiceFlagsAllowExpiredAnswers;
+ if( gDNSSDFlag_BrowseDomains ) flags |= kDNSServiceFlagsBrowseDomains;
+ if( gDNSSDFlag_DenyCellular ) flags |= kDNSServiceFlagsDenyCellular;
+ if( gDNSSDFlag_DenyConstrained ) flags |= kDNSServiceFlagsDenyConstrained;
+ if( gDNSSDFlag_DenyExpensive ) flags |= kDNSServiceFlagsDenyExpensive;
+ if( gDNSSDFlag_ForceMulticast ) flags |= kDNSServiceFlagsForceMulticast;
+ if( gDNSSDFlag_IncludeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+ if( gDNSSDFlag_KnownUnique ) flags |= kDNSServiceFlagsKnownUnique;
+ if( gDNSSDFlag_NoAutoRename ) flags |= kDNSServiceFlagsNoAutoRename;
+ if( gDNSSDFlag_PathEvaluationDone ) flags |= kDNSServiceFlagsPathEvaluationDone;
+ if( gDNSSDFlag_RegistrationDomains ) flags |= kDNSServiceFlagsRegistrationDomains;
+ if( gDNSSDFlag_ReturnIntermediates ) flags |= kDNSServiceFlagsReturnIntermediates;
+ if( gDNSSDFlag_Shared ) flags |= kDNSServiceFlagsShared;
+ if( gDNSSDFlag_SuppressUnusable ) flags |= kDNSServiceFlagsSuppressUnusable;
+ if( gDNSSDFlag_Timeout ) flags |= kDNSServiceFlagsTimeout;
+ if( gDNSSDFlag_UnicastResponse ) flags |= kDNSServiceFlagsUnicastResponse;
+ if( gDNSSDFlag_Unique ) flags |= kDNSServiceFlagsUnique;
+ if( gDNSSDFlag_WakeOnResolve ) flags |= kDNSServiceFlagsWakeOnResolve;
+
+ return( flags );
+}
+
+//===========================================================================================================================
+// CreateConnectionFromArgString
+//===========================================================================================================================
+
+static OSStatus
+ CreateConnectionFromArgString(
+ const char * inString,
+ dispatch_queue_t inQueue,
+ DNSServiceRef * outSDRef,
+ ConnectionDesc * outDesc )
+{
+ OSStatus err;
+ DNSServiceRef sdRef = NULL;
+ ConnectionType type;
+ int32_t pid = -1; // Initializing because the analyzer claims pid may be used uninitialized.
+ uint8_t uuid[ 16 ];
+
+ if( strcasecmp( inString, kConnectionArg_Normal ) == 0 )
+ {
+ err = DNSServiceCreateConnection( &sdRef );
+ require_noerr( err, exit );
+ type = kConnectionType_Normal;
+ }
+ else if( stricmp_prefix( inString, kConnectionArgPrefix_PID ) == 0 )
+ {
+ const char * const pidStr = inString + sizeof_string( kConnectionArgPrefix_PID );
+
+ err = StringToInt32( pidStr, &pid );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid delegate connection PID value: %s\n", pidStr );
+ err = kParamErr;
+ goto exit;
+ }
+
+ memset( uuid, 0, sizeof( uuid ) );
+ err = DNSServiceCreateDelegateConnection( &sdRef, pid, uuid );
+ if( err )
+ {
+ FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for PID %d\n", err, pid );
+ goto exit;
+ }
+ type = kConnectionType_DelegatePID;
+ }
+ else if( stricmp_prefix( inString, kConnectionArgPrefix_UUID ) == 0 )
+ {
+ const char * const uuidStr = inString + sizeof_string( kConnectionArgPrefix_UUID );
+
+ check_compile_time_code( sizeof( uuid ) == sizeof( uuid_t ) );
+
+ err = StringToUUID( uuidStr, kSizeCString, false, uuid );
+ if( err )
+ {
+ FPrintF( stderr, "Invalid delegate connection UUID value: %s\n", uuidStr );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = DNSServiceCreateDelegateConnection( &sdRef, 0, uuid );
+ if( err )
+ {
+ FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for UUID %#U\n", err, uuid );
+ goto exit;
+ }
+ type = kConnectionType_DelegateUUID;
+ }
+ else
+ {
+ FPrintF( stderr, "Unrecognized connection string \"%s\".\n", inString );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = DNSServiceSetDispatchQueue( sdRef, inQueue );
+ require_noerr( err, exit );
+
+ *outSDRef = sdRef;
+ if( outDesc )
+ {
+ outDesc->type = type;
+ if( type == kConnectionType_DelegatePID ) outDesc->delegate.pid = pid;
+ else if( type == kConnectionType_DelegateUUID ) memcpy( outDesc->delegate.uuid, uuid, 16 );
+ }
+ sdRef = NULL;
+
+exit:
+ if( sdRef ) DNSServiceRefDeallocate( sdRef );
+ return( err );
+}
+
+//===========================================================================================================================
+// InterfaceIndexFromArgString
+//===========================================================================================================================
+
+static OSStatus InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex )
+{
+ OSStatus err;
+ uint32_t ifIndex;
+
+ if( inString )
+ {
+ ifIndex = if_nametoindex( inString );
+ if( ifIndex == 0 )
+ {
+ err = StringToUInt32( inString, &ifIndex );
+ if( err )
+ {
+ FPrintF( stderr, "error: Invalid interface value: %s\n", inString );
+ err = kParamErr;
+ goto exit;
+ }
+ }
+ }
+ else
+ {
+ ifIndex = 0;
+ }
+
+ *outIndex = ifIndex;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// RecordDataFromArgString
+//===========================================================================================================================
+
+static OSStatus RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen )
+{
+ OSStatus err;
+ uint8_t * dataPtr = NULL;
+ size_t dataLen;
+
+ if( 0 ) {}
+
+ // Domain name
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_Domain ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_Domain );
+
+ err = StringToDomainName( str, &dataPtr, &dataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // File path
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_File ) == 0 )
+ {
+ const char * const path = inString + sizeof_string( kRDataArgPrefix_File );
+
+ err = CopyFileDataByPath( path, (char **) &dataPtr, &dataLen );
+ require_noerr( err, exit );
+ require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
+ }
+
+ // Hexadecimal string
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_HexString ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_HexString );
+
+ err = HexToDataCopy( str, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
+ require_noerr( err, exit );
+ require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
+ }
+
+ // IPv4 address string
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_IPv4 ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_IPv4 );
+
+ err = StringToARecordData( str, &dataPtr, &dataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // IPv6 address string
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_IPv6 ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_IPv6 );
+
+ err = StringToAAAARecordData( str, &dataPtr, &dataLen );
+ require_noerr_quiet( err, exit );
+ }
+
+ // SRV record
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_SRV ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_SRV );
+
+ err = CreateSRVRecordDataFromString( str, &dataPtr, &dataLen );
+ require_noerr( err, exit );
+ }
+
+ // String with escaped hex and octal bytes
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_String ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_String );
+ const char * const end = str + strlen( str );
+ size_t copiedLen;
+ size_t totalLen;
+ Boolean success;
+
+ if( str < end )
+ {
+ success = _ParseQuotedEscapedString( str, end, "", NULL, 0, NULL, &totalLen, NULL );
+ require_action( success, exit, err = kParamErr );
+ require_action( totalLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
+
+ dataLen = totalLen;
+ dataPtr = (uint8_t *) malloc( dataLen );
+ require_action( dataPtr, exit, err = kNoMemoryErr );
+
+ success = _ParseQuotedEscapedString( str, end, "", (char *) dataPtr, dataLen, &copiedLen, NULL, NULL );
+ require_action( success, exit, err = kParamErr );
+ check( copiedLen == dataLen );
+ }
+ else
+ {
+ dataPtr = NULL;
+ dataLen = 0;
+ }
+ }
+
+ // TXT record
+
+ else if( stricmp_prefix( inString, kRDataArgPrefix_TXT ) == 0 )
+ {
+ const char * const str = inString + sizeof_string( kRDataArgPrefix_TXT );
+
+ err = CreateTXTRecordDataFromString( str, ',', &dataPtr, &dataLen );
+ require_noerr( err, exit );
+ }
+
+ // Unrecognized format
+
+ else
+ {
+ FPrintF( stderr, "Unrecognized record data string \"%s\".\n", inString );
+ err = kParamErr;
+ goto exit;
+ }
+
+ err = kNoErr;
+ *outDataLen = dataLen;
+ *outDataPtr = dataPtr;
+ dataPtr = NULL;
+
+exit:
+ FreeNullSafe( dataPtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// RecordTypeFromArgString
+//===========================================================================================================================
+
+typedef struct
+{
+ uint16_t value; // Record type's numeric value.
+ const char * name; // Record type's name as a string (e.g., "A", "PTR", "SRV").
+
+} RecordType;
+
+static const RecordType kRecordTypes[] =
+{
+ // Common types.
+
+ { kDNSServiceType_A, "A" },
+ { kDNSServiceType_AAAA, "AAAA" },
+ { kDNSServiceType_PTR, "PTR" },
+ { kDNSServiceType_SRV, "SRV" },
+ { kDNSServiceType_TXT, "TXT" },
+ { kDNSServiceType_CNAME, "CNAME" },
+ { kDNSServiceType_SOA, "SOA" },
+ { kDNSServiceType_NSEC, "NSEC" },
+ { kDNSServiceType_NS, "NS" },
+ { kDNSServiceType_MX, "MX" },
+ { kDNSServiceType_ANY, "ANY" },
+ { kDNSServiceType_OPT, "OPT" },
+
+ // Less common types.
+
+ { kDNSServiceType_MD, "MD" },
+ { kDNSServiceType_NS, "NS" },
+ { kDNSServiceType_MD, "MD" },
+ { kDNSServiceType_MF, "MF" },
+ { kDNSServiceType_MB, "MB" },
+ { kDNSServiceType_MG, "MG" },
+ { kDNSServiceType_MR, "MR" },
+ { kDNSServiceType_NULL, "NULL" },
+ { kDNSServiceType_WKS, "WKS" },
+ { kDNSServiceType_HINFO, "HINFO" },
+ { kDNSServiceType_MINFO, "MINFO" },
+ { kDNSServiceType_RP, "RP" },
+ { kDNSServiceType_AFSDB, "AFSDB" },
+ { kDNSServiceType_X25, "X25" },
+ { kDNSServiceType_ISDN, "ISDN" },
+ { kDNSServiceType_RT, "RT" },
+ { kDNSServiceType_NSAP, "NSAP" },
+ { kDNSServiceType_NSAP_PTR, "NSAP_PTR" },
+ { kDNSServiceType_SIG, "SIG" },
+ { kDNSServiceType_KEY, "KEY" },
+ { kDNSServiceType_PX, "PX" },
+ { kDNSServiceType_GPOS, "GPOS" },
+ { kDNSServiceType_LOC, "LOC" },
+ { kDNSServiceType_NXT, "NXT" },
+ { kDNSServiceType_EID, "EID" },
+ { kDNSServiceType_NIMLOC, "NIMLOC" },
+ { kDNSServiceType_ATMA, "ATMA" },
+ { kDNSServiceType_NAPTR, "NAPTR" },
+ { kDNSServiceType_KX, "KX" },
+ { kDNSServiceType_CERT, "CERT" },
+ { kDNSServiceType_A6, "A6" },
+ { kDNSServiceType_DNAME, "DNAME" },
+ { kDNSServiceType_SINK, "SINK" },
+ { kDNSServiceType_APL, "APL" },
+ { kDNSServiceType_DS, "DS" },
+ { kDNSServiceType_SSHFP, "SSHFP" },
+ { kDNSServiceType_IPSECKEY, "IPSECKEY" },
+ { kDNSServiceType_RRSIG, "RRSIG" },
+ { kDNSServiceType_DNSKEY, "DNSKEY" },
+ { kDNSServiceType_DHCID, "DHCID" },
+ { kDNSServiceType_NSEC3, "NSEC3" },
+ { kDNSServiceType_NSEC3PARAM, "NSEC3PARAM" },
+ { kDNSServiceType_HIP, "HIP" },
+ { kDNSServiceType_SPF, "SPF" },
+ { kDNSServiceType_UINFO, "UINFO" },
+ { kDNSServiceType_UID, "UID" },
+ { kDNSServiceType_GID, "GID" },
+ { kDNSServiceType_UNSPEC, "UNSPEC" },
+ { kDNSServiceType_TKEY, "TKEY" },
+ { kDNSServiceType_TSIG, "TSIG" },
+ { kDNSServiceType_IXFR, "IXFR" },
+ { kDNSServiceType_AXFR, "AXFR" },
+ { kDNSServiceType_MAILB, "MAILB" },
+ { kDNSServiceType_MAILA, "MAILA" }
+};
+
+static OSStatus RecordTypeFromArgString( const char *inString, uint16_t *outValue )
+{
+ OSStatus err;
+ int32_t i32;
+ const RecordType * type;
+ const RecordType * const end = kRecordTypes + countof( kRecordTypes );
+
+ for( type = kRecordTypes; type < end; ++type )
+ {
+ if( strcasecmp( type->name, inString ) == 0 )
+ {
+ *outValue = type->value;
+ return( kNoErr );
+ }
+ }
+
+ err = StringToInt32( inString, &i32 );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
+
+ *outValue = (uint16_t) i32;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// RecordClassFromArgString
+//===========================================================================================================================
+
+static OSStatus RecordClassFromArgString( const char *inString, uint16_t *outValue )
+{
+ OSStatus err;
+ int32_t i32;
+
+ if( strcasecmp( inString, "IN" ) == 0 )
+ {
+ *outValue = kDNSServiceClass_IN;
+ err = kNoErr;
+ goto exit;
+ }
+
+ err = StringToInt32( inString, &i32 );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
+
+ *outValue = (uint16_t) i32;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// InterfaceIndexToName
+//===========================================================================================================================
+
+static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] )
+{
+ switch( inIfIndex )
+ {
+ case kDNSServiceInterfaceIndexAny:
+ strlcpy( inNameBuf, "Any", kInterfaceNameBufLen );
+ break;
+
+ case kDNSServiceInterfaceIndexLocalOnly:
+ strlcpy( inNameBuf, "LocalOnly", kInterfaceNameBufLen );
+ break;
+
+ case kDNSServiceInterfaceIndexUnicast:
+ strlcpy( inNameBuf, "Unicast", kInterfaceNameBufLen );
+ break;
+
+ case kDNSServiceInterfaceIndexP2P:
+ strlcpy( inNameBuf, "P2P", kInterfaceNameBufLen );
+ break;
+
+ #if( defined( kDNSServiceInterfaceIndexBLE ) )
+ case kDNSServiceInterfaceIndexBLE:
+ strlcpy( inNameBuf, "BLE", kInterfaceNameBufLen );
+ break;
+ #endif
+
+ default:
+ {
+ const char * name;
+
+ name = if_indextoname( inIfIndex, inNameBuf );
+ if( !name ) strlcpy( inNameBuf, "NO NAME", kInterfaceNameBufLen );
+ break;
+ }
+ }
+
+ return( inNameBuf );
+}
+
+//===========================================================================================================================
+// RecordTypeToString
+//===========================================================================================================================
+
+static const char * RecordTypeToString( unsigned int inValue )
+{
+ const RecordType * type;
+ const RecordType * const end = kRecordTypes + countof( kRecordTypes );
+
+ for( type = kRecordTypes; type < end; ++type )
+ {
+ if( type->value == inValue ) return( type->name );
+ }
+ return( "???" );
+}
+
+//===========================================================================================================================
+// DNSRecordDataToString
+//===========================================================================================================================
+
+static OSStatus
+ DNSRecordDataToString(
+ const void * inRDataPtr,
+ size_t inRDataLen,
+ unsigned int inRDataType,
+ const void * inMsgPtr,
+ size_t inMsgLen,
+ char ** outString )
+{
+ OSStatus err;
+ const uint8_t * const rdataPtr = (uint8_t *) inRDataPtr;
+ const uint8_t * const rdataEnd = rdataPtr + inRDataLen;
+ char * rdataStr;
+ const uint8_t * ptr;
+ int n;
+ char domainNameStr[ kDNSServiceMaxDomainName ];
+
+ rdataStr = NULL;
+
+ // A Record
+
+ if( inRDataType == kDNSServiceType_A )
+ {
+ require_action_quiet( inRDataLen == 4, exit, err = kMalformedErr );
+
+ ASPrintF( &rdataStr, "%.4a", rdataPtr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+
+ // AAAA Record
+
+ else if( inRDataType == kDNSServiceType_AAAA )
+ {
+ require_action_quiet( inRDataLen == 16, exit, err = kMalformedErr );
+
+ ASPrintF( &rdataStr, "%.16a", rdataPtr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+
+ // PTR, CNAME, or NS Record
+
+ else if( ( inRDataType == kDNSServiceType_PTR ) ||
+ ( inRDataType == kDNSServiceType_CNAME ) ||
+ ( inRDataType == kDNSServiceType_NS ) )
+ {
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+
+ // SRV Record
+
+ else if( inRDataType == kDNSServiceType_SRV )
+ {
+ const dns_fixed_fields_srv * fields;
+ const uint8_t * target;
+ unsigned int priority, weight, port;
+
+ require_action_quiet( inRDataLen > sizeof( dns_fixed_fields_srv ), exit, err = kMalformedErr );
+
+ fields = (const dns_fixed_fields_srv *) rdataPtr;
+ priority = dns_fixed_fields_srv_get_priority( fields );
+ weight = dns_fixed_fields_srv_get_weight( fields );
+ port = dns_fixed_fields_srv_get_port( fields );
+ target = (const uint8_t *) &fields[ 1 ];
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, target, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( target, rdataEnd, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ ASPrintF( &rdataStr, "%u %u %u %s", priority, weight, port, domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+
+ // TXT Record
+
+ else if( inRDataType == kDNSServiceType_TXT )
+ {
+ require_action_quiet( inRDataLen > 0, exit, err = kMalformedErr );
+
+ if( inRDataLen == 1 )
+ {
+ ASPrintF( &rdataStr, "%#H", rdataPtr, (int) inRDataLen, INT_MAX );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ else
+ {
+ ASPrintF( &rdataStr, "%#{txt}", rdataPtr, inRDataLen );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+ }
+
+ // SOA Record
+
+ else if( inRDataType == kDNSServiceType_SOA )
+ {
+ const dns_fixed_fields_soa * fields;
+ uint32_t serial, refresh, retry, expire, minimum;
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
+ require_noerr( err, exit );
+
+ require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, ptr, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
+ require_noerr( err, exit );
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ err = DomainNameToString( ptr, rdataEnd, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+
+ require_action_quiet( ( rdataEnd - ptr ) == sizeof( dns_fixed_fields_soa ), exit, err = kMalformedErr );
+
+ fields = (const dns_fixed_fields_soa *) ptr;
+ serial = dns_fixed_fields_soa_get_serial( fields );
+ refresh = dns_fixed_fields_soa_get_refresh( fields );
+ retry = dns_fixed_fields_soa_get_retry( fields );
+ expire = dns_fixed_fields_soa_get_expire( fields );
+ minimum = dns_fixed_fields_soa_get_minimum( fields );
+
+ n = AppendPrintF( &rdataStr, " %s %u %u %u %u %u\n", domainNameStr, serial, refresh, retry, expire, minimum );
+ require_action( n > 0, exit, err = kUnknownErr );
+ }
+
+ // NSEC Record
+
+ else if( inRDataType == kDNSServiceType_NSEC )
+ {
+ unsigned int windowBlock, bitmapLen, i, recordType;
+ const uint8_t * bitmapPtr;
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
+ require_noerr( err, exit );
+ }
+
+ require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
+
+ rdataStr = strdup( domainNameStr );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+
+ for( ; ptr < rdataEnd; ptr += ( 2 + bitmapLen ) )
+ {
+ require_action_quiet( ( ptr + 2 ) < rdataEnd, exit, err = kMalformedErr );
+
+ windowBlock = ptr[ 0 ];
+ bitmapLen = ptr[ 1 ];
+ bitmapPtr = &ptr[ 2 ];
+
+ require_action_quiet( ( bitmapLen >= 1 ) && ( bitmapLen <= 32 ) , exit, err = kMalformedErr );
+ require_action_quiet( ( bitmapPtr + bitmapLen ) <= rdataEnd, exit, err = kMalformedErr );
+
+ for( i = 0; i < BitArray_MaxBits( bitmapLen ); ++i )
+ {
+ if( BitArray_GetBit( bitmapPtr, bitmapLen, i ) )
+ {
+ recordType = ( windowBlock * 256 ) + i;
+ n = AppendPrintF( &rdataStr, " %s", RecordTypeToString( recordType ) );
+ require_action( n > 0, exit, err = kUnknownErr );
+ }
+ }
+ }
+ }
+
+ // MX Record
+
+ else if( inRDataType == kDNSServiceType_MX )
+ {
+ uint16_t preference;
+ const uint8_t * exchange;
+
+ require_action_quiet( ( rdataPtr + 2 ) < rdataEnd, exit, err = kMalformedErr );
+
+ preference = ReadBig16( rdataPtr );
+ exchange = &rdataPtr[ 2 ];
+
+ if( inMsgPtr )
+ {
+ err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, exchange, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = DomainNameToString( exchange, rdataEnd, domainNameStr, NULL );
+ require_noerr( err, exit );
+ }
+
+ n = ASPrintF( &rdataStr, "%u %s", preference, domainNameStr );
+ require_action( n > 0, exit, err = kUnknownErr );
+ }
+
+ // Unhandled record type
+
+ else
+ {
+ err = kNotHandledErr;
+ goto exit;
+ }
+
+ check( rdataStr );
+ *outString = rdataStr;
+ rdataStr = NULL;
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( rdataStr );
+ return( err );
+}
+
+//===========================================================================================================================
+// DNSMessageToText
+//===========================================================================================================================
+
+#define DNSFlagsOpCodeToString( X ) ( \
+ ( (X) == kDNSOpCode_Query ) ? "Query" : \
+ ( (X) == kDNSOpCode_InverseQuery ) ? "IQuery" : \
+ ( (X) == kDNSOpCode_Status ) ? "Status" : \
+ ( (X) == kDNSOpCode_Notify ) ? "Notify" : \
+ ( (X) == kDNSOpCode_Update ) ? "Update" : \
+ "Unassigned" )
+
+#define DNSFlagsRCodeToString( X ) ( \
+ ( (X) == kDNSRCode_NoError ) ? "NoError" : \
+ ( (X) == kDNSRCode_FormatError ) ? "FormErr" : \
+ ( (X) == kDNSRCode_ServerFailure ) ? "ServFail" : \
+ ( (X) == kDNSRCode_NXDomain ) ? "NXDomain" : \
+ ( (X) == kDNSRCode_NotImplemented ) ? "NotImp" : \
+ ( (X) == kDNSRCode_Refused ) ? "Refused" : \
+ "???" )
+
+static OSStatus
+ DNSMessageToText(
+ const uint8_t * inMsgPtr,
+ size_t inMsgLen,
+ const Boolean inMDNS,
+ const Boolean inPrintRaw,
+ char ** outText )
+{
+ OSStatus err;
+ DataBuffer dataBuf;
+ size_t len;
+ const DNSHeader * hdr;
+ const uint8_t * ptr;
+ unsigned int id, flags, opcode, rcode;
+ unsigned int questionCount, answerCount, authorityCount, additionalCount, i, totalRRCount;
+ uint8_t name[ kDomainNameLengthMax ];
+ char nameStr[ kDNSServiceMaxDomainName ];
+
+ DataBuffer_Init( &dataBuf, NULL, 0, SIZE_MAX );
+ #define _Append( ... ) do { err = DataBuffer_AppendF( &dataBuf, __VA_ARGS__ ); require_noerr( err, exit ); } while( 0 )
+
+ require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+
+ hdr = (DNSHeader *) inMsgPtr;
+ id = DNSHeaderGetID( hdr );
+ flags = DNSHeaderGetFlags( hdr );
+ questionCount = DNSHeaderGetQuestionCount( hdr );
+ answerCount = DNSHeaderGetAnswerCount( hdr );
+ authorityCount = DNSHeaderGetAuthorityCount( hdr );
+ additionalCount = DNSHeaderGetAdditionalCount( hdr );
+ opcode = DNSFlagsGetOpCode( flags );
+ rcode = DNSFlagsGetRCode( flags );
+
+ _Append( "ID: 0x%04X (%u)\n", id, id );
+ _Append( "Flags: 0x%04X %c/%s %cAA%cTC%cRD%cRA%?s%?s %s\n",
+ flags,
+ ( flags & kDNSHeaderFlag_Response ) ? 'R' : 'Q', DNSFlagsOpCodeToString( opcode ),
+ ( flags & kDNSHeaderFlag_AuthAnswer ) ? ' ' : '!',
+ ( flags & kDNSHeaderFlag_Truncation ) ? ' ' : '!',
+ ( flags & kDNSHeaderFlag_RecursionDesired ) ? ' ' : '!',
+ ( flags & kDNSHeaderFlag_RecursionAvailable ) ? ' ' : '!',
+ !inMDNS, ( flags & kDNSHeaderFlag_AuthenticData ) ? " AD" : "!AD",
+ !inMDNS, ( flags & kDNSHeaderFlag_CheckingDisabled ) ? " CD" : "!CD",
+ DNSFlagsRCodeToString( rcode ) );
+ _Append( "Question count: %u\n", questionCount );
+ _Append( "Answer count: %u\n", answerCount );
+ _Append( "Authority count: %u\n", authorityCount );
+ _Append( "Additional count: %u\n", additionalCount );
+
+ ptr = (const uint8_t *) &hdr[ 1 ];
+ for( i = 0; i < questionCount; ++i )
+ {
+ uint16_t qtype, qclass;
+ Boolean isQU;
+
+ err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, name, &qtype, &qclass, &ptr );
+ require_noerr( err, exit );
+
+ err = DomainNameToString( name, NULL, nameStr, NULL );
+ require_noerr( err, exit );
+
+ isQU = ( inMDNS && ( qclass & kQClassUnicastResponseBit ) ) ? true : false;
+ if( inMDNS ) qclass &= ~kQClassUnicastResponseBit;
+
+ if( i == 0 ) _Append( "\nQUESTION SECTION\n" );
+
+ _Append( "%-30s %2s %?2s%?2u %-5s\n",
+ nameStr, inMDNS ? ( isQU ? "QU" : "QM" ) : "",
+ ( qclass == kDNSServiceClass_IN ), "IN", ( qclass != kDNSServiceClass_IN ), qclass, RecordTypeToString( qtype ) );
+ }
+
+ totalRRCount = answerCount + authorityCount + additionalCount;
+ for( i = 0; i < totalRRCount; ++i )
+ {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ const uint8_t * rdataPtr;
+ size_t rdataLen;
+ char * rdataStr;
+ Boolean cacheFlush;
+
+ err = DNSMessageExtractRecord( inMsgPtr, inMsgLen, ptr, name, &type, &class, &ttl, &rdataPtr, &rdataLen, &ptr );
+ require_noerr( err, exit );
+
+ err = DomainNameToString( name, NULL, nameStr, NULL );
+ require_noerr( err, exit );
+
+ cacheFlush = ( inMDNS && ( class & kRRClassCacheFlushBit ) ) ? true : false;
+ if( inMDNS ) class &= ~kRRClassCacheFlushBit;
+
+ rdataStr = NULL;
+ if( !inPrintRaw ) DNSRecordDataToString( rdataPtr, rdataLen, type, inMsgPtr, inMsgLen, &rdataStr );
+ if( !rdataStr )
+ {
+ ASPrintF( &rdataStr, "%#H", rdataPtr, (int) rdataLen, (int) rdataLen );
+ require_action( rdataStr, exit, err = kNoMemoryErr );
+ }
+
+ if( answerCount && ( i == 0 ) ) _Append( "\nANSWER SECTION\n" );
+ else if( authorityCount && ( i == answerCount ) ) _Append( "\nAUTHORITY SECTION\n" );
+ else if( additionalCount && ( i == ( answerCount + authorityCount ) ) ) _Append( "\nADDITIONAL SECTION\n" );
+
+ _Append( "%-42s %6u %2s %?2s%?2u %-5s %s\n",
+ nameStr, ttl, cacheFlush ? "CF" : "",
+ ( class == kDNSServiceClass_IN ), "IN", ( class != kDNSServiceClass_IN ), class,
+ RecordTypeToString( type ), rdataStr );
+ free( rdataStr );
+ }
+ _Append( "\n" );
+
+ err = DataBuffer_Append( &dataBuf, "", 1 );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &dataBuf, (uint8_t **) outText, &len );
+ require_noerr( err, exit );
+
+exit:
+ DataBuffer_Free( &dataBuf );
+ return( err );
+}
+
+//===========================================================================================================================
+// WriteDNSQueryMessage
+//===========================================================================================================================
+
+static OSStatus
+ WriteDNSQueryMessage(
+ uint8_t inMsg[ kDNSQueryMessageMaxLen ],
+ uint16_t inMsgID,
+ uint16_t inFlags,
+ const char * inQName,
+ uint16_t inQType,
+ uint16_t inQClass,
+ size_t * outMsgLen )
+{
+ OSStatus err;
+ uint8_t qname[ kDomainNameLengthMax ];
+
+ err = DomainNameFromString( qname, inQName, NULL );
+ require_noerr_quiet( err, exit );
+
+ err = DNSMessageWriteQuery( inMsgID, inFlags, qname, inQType, inQClass, inMsg, outMsgLen );
+ require_noerr_quiet( err, exit );
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchSignalSourceCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchSignalSourceCreate(
+ int inSignal,
+ DispatchHandler inEventHandler,
+ void * inContext,
+ dispatch_source_t * outSource )
+{
+ OSStatus err;
+ dispatch_source_t source;
+
+ source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, dispatch_get_main_queue() );
+ require_action( source, exit, err = kUnknownErr );
+
+ dispatch_set_context( source, inContext );
+ dispatch_source_set_event_handler_f( source, inEventHandler );
+
+ *outSource = source;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchSocketSourceCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchSocketSourceCreate(
+ SocketRef inSock,
+ dispatch_source_type_t inType,
+ dispatch_queue_t inQueue,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outSource )
+{
+ OSStatus err;
+ dispatch_source_t source;
+
+ source = dispatch_source_create( inType, (uintptr_t) inSock, 0, inQueue ? inQueue : dispatch_get_main_queue() );
+ require_action( source, exit, err = kUnknownErr );
+
+ dispatch_set_context( source, inContext );
+ dispatch_source_set_event_handler_f( source, inEventHandler );
+ dispatch_source_set_cancel_handler_f( source, inCancelHandler );
+
+ *outSource = source;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchTimerCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchTimerCreate(
+ dispatch_time_t inStart,
+ uint64_t inIntervalNs,
+ uint64_t inLeewayNs,
+ dispatch_queue_t inQueue,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outTimer )
+{
+ OSStatus err;
+ dispatch_source_t timer;
+
+ timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, inQueue ? inQueue : dispatch_get_main_queue() );
+ require_action( timer, exit, err = kUnknownErr );
+
+ dispatch_source_set_timer( timer, inStart, inIntervalNs, inLeewayNs );
+ dispatch_set_context( timer, inContext );
+ dispatch_source_set_event_handler_f( timer, inEventHandler );
+ dispatch_source_set_cancel_handler_f( timer, inCancelHandler );
+
+ *outTimer = timer;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// DispatchProcessMonitorCreate
+//===========================================================================================================================
+
+static OSStatus
+ DispatchProcessMonitorCreate(
+ pid_t inPID,
+ unsigned long inFlags,
+ dispatch_queue_t inQueue,
+ DispatchHandler inEventHandler,
+ DispatchHandler inCancelHandler,
+ void * inContext,
+ dispatch_source_t * outMonitor )
+{
+ OSStatus err;
+ dispatch_source_t monitor;
+
+ monitor = dispatch_source_create( DISPATCH_SOURCE_TYPE_PROC, (uintptr_t) inPID, inFlags,
+ inQueue ? inQueue : dispatch_get_main_queue() );
+ require_action( monitor, exit, err = kUnknownErr );
+
+ dispatch_set_context( monitor, inContext );
+ dispatch_source_set_event_handler_f( monitor, inEventHandler );
+ dispatch_source_set_cancel_handler_f( monitor, inCancelHandler );
+
+ *outMonitor = monitor;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// ServiceTypeDescription
+//===========================================================================================================================
+
+typedef struct
+{
+ const char * name; // Name of the service type in two-label "_service._proto" format.
+ const char * description; // Description of the service type.
+
+} ServiceType;
+
+// A Non-comprehensive table of DNS-SD service types
+
+static const ServiceType kServiceTypes[] =
+{
+ { "_acp-sync._tcp", "AirPort Base Station Sync" },
+ { "_adisk._tcp", "Automatic Disk Discovery" },
+ { "_afpovertcp._tcp", "Apple File Sharing" },
+ { "_airdrop._tcp", "AirDrop" },
+ { "_airplay._tcp", "AirPlay" },
+ { "_airport._tcp", "AirPort Base Station" },
+ { "_daap._tcp", "Digital Audio Access Protocol (iTunes)" },
+ { "_eppc._tcp", "Remote AppleEvents" },
+ { "_ftp._tcp", "File Transfer Protocol" },
+ { "_home-sharing._tcp", "Home Sharing" },
+ { "_homekit._tcp", "HomeKit" },
+ { "_http._tcp", "World Wide Web HTML-over-HTTP" },
+ { "_https._tcp", "HTTP over SSL/TLS" },
+ { "_ipp._tcp", "Internet Printing Protocol" },
+ { "_ldap._tcp", "Lightweight Directory Access Protocol" },
+ { "_mediaremotetv._tcp", "Media Remote" },
+ { "_net-assistant._tcp", "Apple Remote Desktop" },
+ { "_od-master._tcp", "OpenDirectory Master" },
+ { "_nfs._tcp", "Network File System" },
+ { "_presence._tcp", "Peer-to-peer messaging / Link-Local Messaging" },
+ { "_pdl-datastream._tcp", "Printer Page Description Language Data Stream" },
+ { "_raop._tcp", "Remote Audio Output Protocol" },
+ { "_rfb._tcp", "Remote Frame Buffer" },
+ { "_scanner._tcp", "Bonjour Scanning" },
+ { "_smb._tcp", "Server Message Block over TCP/IP" },
+ { "_sftp-ssh._tcp", "Secure File Transfer Protocol over SSH" },
+ { "_sleep-proxy._udp", "Sleep Proxy Server" },
+ { "_ssh._tcp", "SSH Remote Login Protocol" },
+ { "_teleport._tcp", "teleport" },
+ { "_tftp._tcp", "Trivial File Transfer Protocol" },
+ { "_workstation._tcp", "Workgroup Manager" },
+ { "_webdav._tcp", "World Wide Web Distributed Authoring and Versioning (WebDAV)" },
+ { "_webdavs._tcp", "WebDAV over SSL/TLS" }
+};
+
+static const char * ServiceTypeDescription( const char *inName )
+{
+ const ServiceType * serviceType;
+ const ServiceType * const end = kServiceTypes + countof( kServiceTypes );
+
+ for( serviceType = kServiceTypes; serviceType < end; ++serviceType )
+ {
+ if( ( stricmp_prefix( inName, serviceType->name ) == 0 ) )
+ {
+ const char * const ptr = &inName[ strlen( serviceType->name ) ];
+
+ if( ( ptr[ 0 ] == '\0' ) || ( ( ptr[ 0 ] == '.' ) && ( ptr[ 1 ] == '\0' ) ) )
+ {
+ return( serviceType->description );
+ }
+ }
+ }
+ return( NULL );
+}
+
+//===========================================================================================================================
+// SocketContextCreate
+//===========================================================================================================================
+
+static OSStatus SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext )
+{
+ OSStatus err;
+ SocketContext * context;
+
+ context = (SocketContext *) calloc( 1, sizeof( *context ) );
+ require_action( context, exit, err = kNoMemoryErr );
+
+ context->refCount = 1;
+ context->sock = inSock;
+ context->userContext = inUserContext;
+
+ *outContext = context;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// SocketContextRetain
+//===========================================================================================================================
+
+static SocketContext * SocketContextRetain( SocketContext *inContext )
+{
+ ++inContext->refCount;
+ return( inContext );
+}
+
+//===========================================================================================================================
+// SocketContextRelease
+//===========================================================================================================================
+
+static void SocketContextRelease( SocketContext *inContext )
+{
+ if( --inContext->refCount == 0 )
+ {
+ ForgetSocket( &inContext->sock );
+ free( inContext );
+ }
+}
+
+//===========================================================================================================================
+// SocketContextCancelHandler
+//===========================================================================================================================
+
+static void SocketContextCancelHandler( void *inContext )
+{
+ SocketContextRelease( (SocketContext *) inContext );
+}
+
+//===========================================================================================================================
+// StringToInt32
+//===========================================================================================================================
+
+static OSStatus StringToInt32( const char *inString, int32_t *outValue )
+{
+ OSStatus err;
+ long value;
+ char * endPtr;
+
+ value = strtol( inString, &endPtr, 0 );
+ require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
+ require_action_quiet( ( value >= INT32_MIN ) && ( value <= INT32_MAX ), exit, err = kRangeErr );
+
+ *outValue = (int32_t) value;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// StringToUInt32
+//===========================================================================================================================
+
+static OSStatus StringToUInt32( const char *inString, uint32_t *outValue )
+{
+ OSStatus err;
+ uint32_t value;
+ char * endPtr;
+
+ value = (uint32_t) strtol( inString, &endPtr, 0 );
+ require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
+
+ *outValue = value;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// _StringToInt64
+//===========================================================================================================================
+
+static int64_t _StringToInt64( const char *inString, OSStatus *outError )
+{
+ OSStatus err;
+ long long val;
+ char * end;
+ int errnoVal;
+
+ set_errno_compat( 0 );
+ val = strtoll( inString, &end, 0 );
+ errnoVal = errno_compat();
+
+ require_action_quiet( ( *end == '\0' ) && ( end != inString ), exit, err = kMalformedErr );
+ require_action_quiet( ( ( val != LLONG_MIN ) && ( val != LLONG_MAX ) ) || ( errnoVal != ERANGE ), exit, err = kRangeErr );
+ require_action_quiet( ( val >= INT64_MIN ) && ( val <= INT64_MAX ), exit, err = kRangeErr );
+ err = kNoErr;
+
+exit:
+ if( outError ) *outError = err;
+ return( (int64_t)val );
+}
+
+//===========================================================================================================================
+// _StringToUInt64
+//===========================================================================================================================
+
+static uint64_t _StringToUInt64( const char *inString, OSStatus *outError )
+{
+ OSStatus err;
+ unsigned long long val;
+ char * end;
+ int errnoVal;
+
+ set_errno_compat( 0 );
+ val = strtoull( inString, &end, 0 );
+ errnoVal = errno_compat();
+
+ require_action_quiet( ( *end == '\0' ) && ( end != inString ), exit, err = kMalformedErr );
+ require_action_quiet( ( val != ULLONG_MAX ) || ( errnoVal != ERANGE ), exit, err = kRangeErr );
+ require_action_quiet( val <= UINT64_MAX, exit, err = kRangeErr );
+ err = kNoErr;
+
+exit:
+ if( outError ) *outError = err;
+ return( (uint64_t)val );
+}
+
+//===========================================================================================================================
+// _StringToPID
+//===========================================================================================================================
+
+static pid_t _StringToPID( const char *inString, OSStatus *outError )
+{
+ OSStatus err;
+ int64_t val;
+
+ val = _StringToInt64( inString, &err );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( val == (pid_t) val, exit, err = kRangeErr );
+ err = kNoErr;
+
+exit:
+ if( outError ) *outError = err;
+ return( (pid_t) val );
+}
+
+//===========================================================================================================================
+// _ParseEscapedString
+//
+// Note: Similar to ParseEscapedString() from CoreUtils except that _ParseEscapedString() takes an optional C string
+// containing delimiter characters instead of being limited to one delimiter character. Also, when the function returns
+// due to a delimiter, the output pointer is set to the delimiter character instead of the character after the delimiter.
+//===========================================================================================================================
+
+static OSStatus
+ _ParseEscapedString(
+ const char * inSrc,
+ const char * inEnd,
+ const char * inDelimiters,
+ char * inBufPtr,
+ size_t inBufLen,
+ size_t * outCopiedLen,
+ size_t * outActualLen,
+ const char ** outPtr )
+{
+ OSStatus err;
+ const char * ptr;
+ char * dst = inBufPtr;
+ const char * const lim = ( inBufLen > 0 ) ? &inBufPtr[ inBufLen - 1 ] : inBufPtr;
+ size_t len;
+
+ len = 0;
+ ptr = inSrc;
+ if( !inDelimiters ) inDelimiters = "";
+ while( ptr < inEnd )
+ {
+ int c;
+ const char * del;
+
+ c = *ptr;
+ for( del = inDelimiters; ( *del != '\0' ) && ( c != *del ); ++del ) {}
+ if( *del != '\0' ) break;
+ ++ptr;
+ if( c == '\\' )
+ {
+ require_action_quiet( ptr < inEnd, exit, err = kUnderrunErr );
+ c = *ptr++;
+ }
+ ++len;
+ if( dst < lim ) *dst++ = (char) c;
+ }
+ if( inBufLen > 0 ) *dst = '\0';
+
+ if( outCopiedLen ) *outCopiedLen = (size_t)( dst - inBufPtr );
+ if( outActualLen ) *outActualLen = len;
+ if( outPtr ) *outPtr = ptr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+#endif
+
+//===========================================================================================================================
+// StringToARecordData
+//===========================================================================================================================
+
+static OSStatus StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+ OSStatus err;
+ uint32_t * addrPtr;
+ const size_t addrLen = sizeof( *addrPtr );
+ const char * end;
+
+ addrPtr = (uint32_t *) malloc( addrLen );
+ require_action( addrPtr, exit, err = kNoMemoryErr );
+
+ err = _StringToIPv4Address( inString, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix, addrPtr,
+ NULL, NULL, NULL, &end );
+ if( !err && ( *end != '\0' ) ) err = kMalformedErr;
+ require_noerr_quiet( err, exit );
+
+ *addrPtr = HostToBig32( *addrPtr );
+
+ *outPtr = (uint8_t *) addrPtr;
+ addrPtr = NULL;
+ *outLen = addrLen;
+
+exit:
+ FreeNullSafe( addrPtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// StringToAAAARecordData
+//===========================================================================================================================
+
+static OSStatus StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+ OSStatus err;
+ uint8_t * addrPtr;
+ const size_t addrLen = 16;
+ const char * end;
+
+ addrPtr = (uint8_t *) malloc( addrLen );
+ require_action( addrPtr, exit, err = kNoMemoryErr );
+
+ err = _StringToIPv6Address( inString,
+ kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
+ addrPtr, NULL, NULL, NULL, &end );
+ if( !err && ( *end != '\0' ) ) err = kMalformedErr;
+ require_noerr_quiet( err, exit );
+
+ *outPtr = addrPtr;
+ addrPtr = NULL;
+ *outLen = addrLen;
+
+exit:
+ FreeNullSafe( addrPtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// StringToDomainName
+//===========================================================================================================================
+
+static OSStatus StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+ OSStatus err;
+ uint8_t * namePtr;
+ size_t nameLen;
+ uint8_t * end;
+ uint8_t nameBuf[ kDomainNameLengthMax ];
+
+ err = DomainNameFromString( nameBuf, inString, &end );
+ require_noerr_quiet( err, exit );
+
+ nameLen = (size_t)( end - nameBuf );
+ namePtr = _memdup( nameBuf, nameLen );
+ require_action( namePtr, exit, err = kNoMemoryErr );
+
+ *outPtr = namePtr;
+ namePtr = NULL;
+ if( outLen ) *outLen = nameLen;
+
+exit:
+ return( err );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+// GetDefaultDNSServer
+//===========================================================================================================================
+
+static OSStatus GetDefaultDNSServer( sockaddr_ip *outAddr )
+{
+ OSStatus err;
+ dns_config_t * config;
+ struct sockaddr * addr;
+ int32_t i;
+
+ config = dns_configuration_copy();
+ require_action( config, exit, err = kUnknownErr );
+
+ addr = NULL;
+ for( i = 0; i < config->n_resolver; ++i )
+ {
+ const dns_resolver_t * const resolver = config->resolver[ i ];
+
+ if( !resolver->domain && ( resolver->n_nameserver > 0 ) )
+ {
+ addr = resolver->nameserver[ 0 ];
+ break;
+ }
+ }
+ require_action_quiet( addr, exit, err = kNotFoundErr );
+
+ SockAddrCopy( addr, outAddr );
+ err = kNoErr;
+
+exit:
+ if( config ) dns_configuration_free( config );
+ return( err );
+}
+#endif
+
+//===========================================================================================================================
+// GetMDNSMulticastAddrV4
+//===========================================================================================================================
+
+static void _MDNSMulticastAddrV4Init( void *inContext );
+
+static const struct sockaddr * GetMDNSMulticastAddrV4( void )
+{
+ static struct sockaddr_in sMDNSMulticastAddrV4;
+ static dispatch_once_t sMDNSMulticastAddrV4InitOnce = 0;
+
+ dispatch_once_f( &sMDNSMulticastAddrV4InitOnce, &sMDNSMulticastAddrV4, _MDNSMulticastAddrV4Init );
+ return( (const struct sockaddr *) &sMDNSMulticastAddrV4 );
+}
+
+static void _MDNSMulticastAddrV4Init( void *inContext )
+{
+ struct sockaddr_in * const addr = (struct sockaddr_in *) inContext;
+
+ memset( addr, 0, sizeof( *addr ) );
+ SIN_LEN_SET( addr );
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons( kMDNSPort );
+ addr->sin_addr.s_addr = htonl( 0xE00000FB ); // The mDNS IPv4 multicast address is 224.0.0.251
+}
+
+//===========================================================================================================================
+// GetMDNSMulticastAddrV6
+//===========================================================================================================================
+
+static void _MDNSMulticastAddrV6Init( void *inContext );
+
+static const struct sockaddr * GetMDNSMulticastAddrV6( void )
+{
+ static struct sockaddr_in6 sMDNSMulticastAddrV6;
+ static dispatch_once_t sMDNSMulticastAddrV6InitOnce = 0;
+
+ dispatch_once_f( &sMDNSMulticastAddrV6InitOnce, &sMDNSMulticastAddrV6, _MDNSMulticastAddrV6Init );
+ return( (const struct sockaddr *) &sMDNSMulticastAddrV6 );
+}
+
+static void _MDNSMulticastAddrV6Init( void *inContext )
+{
+ struct sockaddr_in6 * const addr = (struct sockaddr_in6 *) inContext;
+
+ memset( addr, 0, sizeof( *addr ) );
+ SIN6_LEN_SET( addr );
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons( kMDNSPort );
+ addr->sin6_addr.s6_addr[ 0 ] = 0xFF; // The mDNS IPv6 multicast address is FF02::FB.
+ addr->sin6_addr.s6_addr[ 1 ] = 0x02;
+ addr->sin6_addr.s6_addr[ 15 ] = 0xFB;
+}
+
+//===========================================================================================================================
+// CreateMulticastSocket
+//===========================================================================================================================
+
+static OSStatus
+ CreateMulticastSocket(
+ const struct sockaddr * inAddr,
+ int inPort,
+ const char * inIfName,
+ uint32_t inIfIndex,
+ Boolean inJoin,
+ int * outPort,
+ SocketRef * outSock )
+{
+ OSStatus err;
+ SocketRef sock = kInvalidSocketRef;
+ const int family = inAddr->sa_family;
+ int port;
+
+ require_action_quiet( ( family == AF_INET ) ||( family == AF_INET6 ), exit, err = kUnsupportedErr );
+
+ err = ServerSocketOpen( family, SOCK_DGRAM, IPPROTO_UDP, inPort, &port, kSocketBufferSize_DontSet, &sock );
+ require_noerr_quiet( err, exit );
+
+ err = SocketSetMulticastInterface( sock, inIfName, inIfIndex );
+ require_noerr_quiet( err, exit );
+
+ if( family == AF_INET )
+ {
+ err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
+ err = map_socket_noerr_errno( sock, err );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
+ err = map_socket_noerr_errno( sock, err );
+ require_noerr_quiet( err, exit );
+ }
+
+ if( inJoin )
+ {
+ err = SocketJoinMulticast( sock, inAddr, inIfName, inIfIndex );
+ require_noerr_quiet( err, exit );
+ }
+
+ if( outPort ) *outPort = port;
+ *outSock = sock;
+ sock = kInvalidSocketRef;
+
+exit:
+ ForgetSocket( &sock );
+ return( err );
+}
+
+//===========================================================================================================================
+// DecimalTextToUInt32
+//===========================================================================================================================
+
+static OSStatus DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr )
+{
+ OSStatus err;
+ uint64_t value;
+ const char * ptr = inSrc;
+
+ require_action_quiet( ( ptr < inEnd ) && isdigit_safe( *ptr ), exit, err = kMalformedErr );
+
+ value = (uint64_t)( *ptr++ - '0' );
+ if( value == 0 )
+ {
+ if( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
+ {
+ err = kMalformedErr;
+ goto exit;
+ }
+ }
+ else
+ {
+ while( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
+ {
+ value = ( value * 10 ) + (uint64_t)( *ptr++ - '0' );
+ require_action_quiet( value <= UINT32_MAX, exit, err = kRangeErr );
+ }
+ }
+
+ *outValue = (uint32_t) value;
+ if( outPtr ) *outPtr = ptr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// CheckIntegerArgument
+//===========================================================================================================================
+
+static OSStatus CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax )
+{
+ if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
+
+ FPrintF( stderr, "error: Invalid %s: %d. Valid range is [%d, %d].\n", inArgName, inArgValue, inMin, inMax );
+ return( kRangeErr );
+}
+
+//===========================================================================================================================
+// CheckDoubleArgument
+//===========================================================================================================================
+
+static OSStatus CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax )
+{
+ if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
+
+ FPrintF( stderr, "error: Invalid %s: %.1f. Valid range is [%.1f, %.1f].\n", inArgName, inArgValue, inMin, inMax );
+ return( kRangeErr );
+}
+
+//===========================================================================================================================
+// CheckRootUser
+//===========================================================================================================================
+
+static OSStatus CheckRootUser( void )
+{
+ if( geteuid() == 0 ) return( kNoErr );
+
+ FPrintF( stderr, "error: This command must to be run as root.\n" );
+ return( kPermissionErr );
+}
+
+//===========================================================================================================================
+// SpawnCommand
+//
+// Note: Based on systemf() from CoreUtils framework.
+//===========================================================================================================================
+
+extern char ** environ;
+
+static OSStatus SpawnCommand( pid_t *outPID, const char *inFormat, ... )
+{
+ OSStatus err;
+ va_list args;
+ char * command;
+ char * argv[ 4 ];
+ pid_t pid;
+
+ command = NULL;
+ va_start( args, inFormat );
+ VASPrintF( &command, inFormat, args );
+ va_end( args );
+ require_action( command, exit, err = kUnknownErr );
+
+ argv[ 0 ] = "/bin/sh";
+ argv[ 1 ] = "-c";
+ argv[ 2 ] = command;
+ argv[ 3 ] = NULL;
+ err = posix_spawn( &pid, argv[ 0 ], NULL, NULL, argv, environ );
+ free( command );
+ require_noerr_quiet( err, exit );
+
+ if( outPID ) *outPID = pid;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// OutputFormatFromArgString
+//===========================================================================================================================
+
+static OSStatus OutputFormatFromArgString( const char *inArgString, OutputFormatType *outFormat )
+{
+ OSStatus err;
+ OutputFormatType format;
+
+ format = (OutputFormatType) CLIArgToValue( "format", inArgString, &err,
+ kOutputFormatStr_JSON, kOutputFormatType_JSON,
+ kOutputFormatStr_XML, kOutputFormatType_XML,
+ kOutputFormatStr_Binary, kOutputFormatType_Binary,
+ NULL );
+ if( outFormat ) *outFormat = format;
+ return( err );
+}
+
+//===========================================================================================================================
+// OutputPropertyList
+//===========================================================================================================================
+
+static OSStatus OutputPropertyList( CFPropertyListRef inPList, OutputFormatType inType, const char *inOutputFilePath )
+{
+ OSStatus err;
+ CFDataRef results = NULL;
+ FILE * file = NULL;
+
+ // Convert plist to a specific format.
+
+ switch( inType )
+ {
+ case kOutputFormatType_JSON:
+ results = CFCreateJSONData( inPList, kJSONFlags_None, NULL );
+ require_action( results, exit, err = kUnknownErr );
+ break;
+
+ case kOutputFormatType_XML:
+ results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListXMLFormat_v1_0, 0, NULL );
+ require_action( results, exit, err = kUnknownErr );
+ break;
+
+ case kOutputFormatType_Binary:
+ results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListBinaryFormat_v1_0, 0, NULL );
+ require_action( results, exit, err = kUnknownErr );
+ break;
+
+ default:
+ err = kTypeErr;
+ goto exit;
+ }
+
+ // Write formatted results to file or stdout.
+
+ if( inOutputFilePath )
+ {
+ file = fopen( inOutputFilePath, "wb" );
+ err = map_global_value_errno( file, file );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ file = stdout;
+ }
+
+ err = WriteANSIFile( file, CFDataGetBytePtr( results ), (size_t) CFDataGetLength( results ) );
+ require_noerr_quiet( err, exit );
+
+ // Write a trailing newline for JSON-formatted results.
+
+ if( inType == kOutputFormatType_JSON )
+ {
+ err = WriteANSIFile( file, "\n", 1 );
+ require_noerr_quiet( err, exit );
+ }
+
+exit:
+ if( file && ( file != stdout ) ) fclose( file );
+ CFReleaseNullSafe( results );
+ return( err );
+}
+
+//===========================================================================================================================
+// CreateSRVRecordDataFromString
+//===========================================================================================================================
+
+static OSStatus CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+ OSStatus err;
+ DataBuffer dataBuf;
+ const char * ptr;
+ int i;
+ uint8_t * end;
+ uint8_t target[ kDomainNameLengthMax ];
+
+ DataBuffer_Init( &dataBuf, NULL, 0, ( 3 * 2 ) + kDomainNameLengthMax );
+
+ // Parse and set the priority, weight, and port values (all three are unsigned 16-bit values).
+
+ ptr = inString;
+ for( i = 0; i < 3; ++i )
+ {
+ char * next;
+ long value;
+ uint8_t buf[ 2 ];
+
+ value = strtol( ptr, &next, 0 );
+ require_action_quiet( ( next != ptr ) && ( *next == ',' ), exit, err = kMalformedErr );
+ require_action_quiet( ( value >= 0 ) && ( value <= UINT16_MAX ), exit, err = kRangeErr );
+ ptr = next + 1;
+
+ WriteBig16( buf, value );
+
+ err = DataBuffer_Append( &dataBuf, buf, sizeof( buf ) );
+ require_noerr( err, exit );
+ }
+
+ // Set the target domain name.
+
+ err = DomainNameFromString( target, ptr, &end );
+ require_noerr_quiet( err, exit );
+
+ err = DataBuffer_Append( &dataBuf, target, (size_t)( end - target ) );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
+ require_noerr( err, exit );
+
+exit:
+ DataBuffer_Free( &dataBuf );
+ return( err );
+}
+
+//===========================================================================================================================
+// CreateTXTRecordDataFromString
+//===========================================================================================================================
+
+static OSStatus CreateTXTRecordDataFromString(const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen )
+{
+ OSStatus err;
+ DataBuffer dataBuf;
+ const char * src;
+ uint8_t txtStr[ 256 ]; // Buffer for single TXT string: 1 length byte + up to 255 bytes of data.
+
+ DataBuffer_Init( &dataBuf, NULL, 0, kDNSRecordDataLengthMax );
+
+ src = inString;
+ for( ;; )
+ {
+ uint8_t * dst = &txtStr[ 1 ];
+ const uint8_t * const lim = &txtStr[ 256 ];
+ int c;
+
+ while( *src && ( *src != inDelimiter ) )
+ {
+ if( ( c = *src++ ) == '\\' )
+ {
+ require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
+ c = *src++;
+ }
+ require_action_quiet( dst < lim, exit, err = kOverrunErr );
+ *dst++ = (uint8_t) c;
+ }
+ txtStr[ 0 ] = (uint8_t)( dst - &txtStr[ 1 ] );
+ err = DataBuffer_Append( &dataBuf, txtStr, 1 + txtStr[ 0 ] );
+ require_noerr( err, exit );
+
+ if( *src == '\0' ) break;
+ ++src;
+ }
+
+ err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
+ require_noerr( err, exit );
+
+exit:
+ DataBuffer_Free( &dataBuf );
+ return( err );
+}
+
+//===========================================================================================================================
+// CreateNSECRecordData
+//===========================================================================================================================
+
+DECLARE_QSORT_NUMERIC_COMPARATOR( _QSortCmpUnsigned );
+DEFINE_QSORT_NUMERIC_COMPARATOR( unsigned int, _QSortCmpUnsigned )
+
+#define kNSECBitmapMaxLength 32 // 32 bytes (256 bits). See <https://tools.ietf.org/html/rfc4034#section-4.1.2>.
+
+static OSStatus
+ CreateNSECRecordData(
+ const uint8_t * inNextDomainName,
+ uint8_t ** outPtr,
+ size_t * outLen,
+ unsigned int inTypeCount,
+ ... )
+{
+ OSStatus err;
+ va_list args;
+ DataBuffer rdataDB;
+ unsigned int * array = NULL;
+ unsigned int i, type, maxBit, currBlock, bitmapLen;
+ uint8_t fields[ 2 + kNSECBitmapMaxLength ];
+ uint8_t * const bitmap = &fields[ 2 ];
+
+ va_start( args, inTypeCount );
+ DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
+
+ // Append Next Domain Name.
+
+ err = DataBuffer_Append( &rdataDB, inNextDomainName, DomainNameLength( inNextDomainName ) );
+ require_noerr( err, exit );
+
+ // Append Type Bit Maps.
+
+ maxBit = 0;
+ memset( bitmap, 0, kNSECBitmapMaxLength );
+ if( inTypeCount > 0 )
+ {
+ array = (unsigned int *) malloc( inTypeCount * sizeof_element( array ) );
+ require_action( array, exit, err = kNoMemoryErr );
+
+ for( i = 0; i < inTypeCount; ++i )
+ {
+ type = va_arg( args, unsigned int );
+ require_action_quiet( type <= UINT16_MAX, exit, err = kRangeErr );
+ array[ i ] = type;
+ }
+ qsort( array, inTypeCount, sizeof_element( array ), _QSortCmpUnsigned );
+
+ currBlock = array[ 0 ] / 256;
+ for( i = 0; i < inTypeCount; ++i )
+ {
+ const unsigned int block = array[ i ] / 256;
+ const unsigned int bit = array[ i ] % 256;
+
+ if( block != currBlock )
+ {
+ bitmapLen = BitArray_MaxBytes( maxBit + 1 );
+ fields[ 0 ] = (uint8_t) currBlock;
+ fields[ 1 ] = (uint8_t) bitmapLen;
+
+ err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
+ require_noerr( err, exit );
+
+ maxBit = 0;
+ currBlock = block;
+ memset( bitmap, 0, bitmapLen );
+ }
+ BitArray_SetBit( bitmap, bit );
+ if( bit > maxBit ) maxBit = bit;
+ }
+ }
+ else
+ {
+ currBlock = 0;
+ }
+
+ bitmapLen = BitArray_MaxBytes( maxBit + 1 );
+ fields[ 0 ] = (uint8_t) currBlock;
+ fields[ 1 ] = (uint8_t) bitmapLen;
+
+ err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
+ require_noerr( err, exit );
+
+exit:
+ va_end( args );
+ DataBuffer_Free( &rdataDB );
+ FreeNullSafe( array );
+ return( err );
+}
+
+//===========================================================================================================================
+// AppendSOARecord
+//===========================================================================================================================
+
+static OSStatus
+ _AppendSOARecordData(
+ DataBuffer * inDB,
+ const uint8_t * inMName,
+ const uint8_t * inRName,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimumTTL,
+ size_t * outLen );
+
+static OSStatus
+ AppendSOARecord(
+ DataBuffer * inDB,
+ const uint8_t * inNamePtr,
+ size_t inNameLen,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ const uint8_t * inMName,
+ const uint8_t * inRName,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimumTTL,
+ size_t * outLen )
+{
+ OSStatus err;
+ size_t rdataLen;
+ size_t rdlengthOffset = 0;
+ uint8_t * rdlengthPtr;
+
+ if( inDB )
+ {
+ err = _DataBuffer_AppendDNSRecord( inDB, inNamePtr, inNameLen, inType, inClass, inTTL, NULL, 0 );
+ require_noerr( err, exit );
+
+ rdlengthOffset = DataBuffer_GetLen( inDB ) - 2;
+ }
+
+ err = _AppendSOARecordData( inDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, &rdataLen );
+ require_noerr( err, exit );
+
+ if( inDB )
+ {
+ rdlengthPtr = DataBuffer_GetPtr( inDB ) + rdlengthOffset;
+ WriteBig16( rdlengthPtr, rdataLen );
+ }
+
+ if( outLen ) *outLen = inNameLen + sizeof( dns_fixed_fields_record ) + rdataLen;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+static OSStatus
+ _AppendSOARecordData(
+ DataBuffer * inDB,
+ const uint8_t * inMName,
+ const uint8_t * inRName,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimumTTL,
+ size_t * outLen )
+{
+ OSStatus err;
+ dns_fixed_fields_soa fields;
+ const size_t mnameLen = DomainNameLength( inMName );
+ const size_t rnameLen = DomainNameLength( inRName );
+
+ if( inDB )
+ {
+ err = DataBuffer_Append( inDB, inMName, mnameLen );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Append( inDB, inRName, rnameLen );
+ require_noerr( err, exit );
+
+ dns_fixed_fields_soa_init( &fields, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL );
+ err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+ }
+ if( outLen ) *outLen = mnameLen + rnameLen + sizeof( fields );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// CreateSOARecordData
+//===========================================================================================================================
+
+static OSStatus
+ CreateSOARecordData(
+ const uint8_t * inMName,
+ const uint8_t * inRName,
+ uint32_t inSerial,
+ uint32_t inRefresh,
+ uint32_t inRetry,
+ uint32_t inExpire,
+ uint32_t inMinimumTTL,
+ uint8_t ** outPtr,
+ size_t * outLen )
+{
+ OSStatus err;
+ DataBuffer rdataDB;
+
+ DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
+
+ err = _AppendSOARecordData( &rdataDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, NULL );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
+ require_noerr( err, exit );
+
+exit:
+ DataBuffer_Free( &rdataDB );
+ return( err );
+}
+
+//===========================================================================================================================
+// _DataBuffer_AppendDNSQuestion
+//===========================================================================================================================
+
+static OSStatus
+ _DataBuffer_AppendDNSQuestion(
+ DataBuffer * inDB,
+ const uint8_t * inNamePtr,
+ size_t inNameLen,
+ uint16_t inType,
+ uint16_t inClass )
+{
+ OSStatus err;
+ dns_fixed_fields_question fields;
+
+ err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
+ require_noerr( err, exit );
+
+ dns_fixed_fields_question_init( &fields, inType, inClass );
+ err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _DataBuffer_AppendDNSRecord
+//===========================================================================================================================
+
+static OSStatus
+ _DataBuffer_AppendDNSRecord(
+ DataBuffer * inDB,
+ const uint8_t * inNamePtr,
+ size_t inNameLen,
+ uint16_t inType,
+ uint16_t inClass,
+ uint32_t inTTL,
+ const uint8_t * inRDataPtr,
+ size_t inRDataLen )
+{
+ OSStatus err;
+ dns_fixed_fields_record fields;
+
+ require_action_quiet( inRDataLen < kDNSRecordDataLengthMax, exit, err = kSizeErr );
+
+ err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
+ require_noerr( err, exit );
+
+ dns_fixed_fields_record_init( &fields, inType, inClass, inTTL, (uint16_t) inRDataLen );
+ err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+ require_noerr( err, exit );
+
+ if( inRDataPtr )
+ {
+ err = DataBuffer_Append( inDB, inRDataPtr, inRDataLen );
+ require_noerr( err, exit );
+ }
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _NanoTime64ToTimestamp
+//===========================================================================================================================
+
+static char * _NanoTime64ToTimestamp( NanoTime64 inTime, char *inBuf, size_t inMaxLen )
+{
+ struct timeval tv;
+
+ NanoTimeToTimeVal( inTime, &tv );
+ return( MakeFractionalDateString( &tv, inBuf, inMaxLen ) );
+}
+
+//===========================================================================================================================
+// _MDNSInterfaceListCreate
+//===========================================================================================================================
+
+static Boolean _MDNSInterfaceIsBlacklisted( SocketRef inInfoSock, const char *inIfName );
+
+static OSStatus _MDNSInterfaceListCreate( MDNSInterfaceSubset inSubset, size_t inItemSize, MDNSInterfaceItem **outList )
+{
+ OSStatus err;
+ struct ifaddrs * ifaList;
+ const struct ifaddrs * ifa;
+ MDNSInterfaceItem * interfaceList;
+ MDNSInterfaceItem ** ptr;
+ SocketRef infoSock;
+
+ ifaList = NULL;
+ interfaceList = NULL;
+ infoSock = kInvalidSocketRef;
+ if( inItemSize == 0 ) inItemSize = sizeof( MDNSInterfaceItem );
+ require_action_quiet( inItemSize >= sizeof( MDNSInterfaceItem ), exit, err = kSizeErr );
+
+ infoSock = socket( AF_INET, SOCK_DGRAM, 0 );
+ err = map_socket_creation_errno( infoSock );
+ require_noerr( err, exit );
+
+ err = getifaddrs( &ifaList );
+ err = map_global_noerr_errno( err );
+ require_noerr( err, exit );
+
+ ptr = &interfaceList;
+ for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
+ {
+ MDNSInterfaceItem * item;
+ int family;
+ const unsigned int flagsMask = IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT;
+ const unsigned int flagsNeeded = IFF_UP | IFF_MULTICAST;
+
+ if( ( ifa->ifa_flags & flagsMask ) != flagsNeeded ) continue;
+ if( !ifa->ifa_addr || !ifa->ifa_name ) continue;
+ family = ifa->ifa_addr->sa_family;
+ if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
+
+ for( item = interfaceList; item && ( strcmp( item->ifName, ifa->ifa_name ) != 0 ); item = item->next ) {}
+ if( !item )
+ {
+ NetTransportType type;
+ uint32_t ifIndex;
+ const char * const ifName = ifa->ifa_name;
+
+ if( _MDNSInterfaceIsBlacklisted( infoSock, ifName ) ) continue;
+ err = SocketGetInterfaceInfo( infoSock, ifName, NULL, &ifIndex, NULL, NULL, NULL, NULL, NULL, &type );
+ require_noerr( err, exit );
+
+ if( ifIndex == 0 ) continue;
+ if( type == kNetTransportType_AWDL )
+ {
+ if( inSubset == kMDNSInterfaceSubset_NonAWDL ) continue;
+ }
+ else
+ {
+ if( inSubset == kMDNSInterfaceSubset_AWDL ) continue;
+ }
+ item = (MDNSInterfaceItem *) calloc( 1, inItemSize );
+ require_action( item, exit, err = kNoMemoryErr );
+
+ *ptr = item;
+ ptr = &item->next;
+
+ item->ifName = strdup( ifName );
+ require_action( item->ifName, exit, err = kNoMemoryErr );
+
+ item->ifIndex = ifIndex;
+ if( type == kNetTransportType_AWDL ) item->isAWDL = true;
+ else if( type == kNetTransportType_WiFi ) item->isWiFi = true;
+ }
+ if( family == AF_INET ) item->hasIPv4 = true;
+ else item->hasIPv6 = true;
+ }
+ require_action_quiet( interfaceList, exit, err = kNotFoundErr );
+
+ if( outList )
+ {
+ *outList = interfaceList;
+ interfaceList = NULL;
+ }
+
+exit:
+ if( ifaList ) freeifaddrs( ifaList );
+ _MDNSInterfaceListFree( interfaceList );
+ ForgetSocket( &infoSock );
+ return( err );
+}
+
+static Boolean _MDNSInterfaceIsBlacklisted( SocketRef inInfoSock, const char *inIfName )
+{
+ OSStatus err;
+ int i;
+ static const char * const kMDNSInterfacePrefixBlacklist[] = { "llw" };
+ struct ifreq ifr;
+
+ // Check if the interface name's prefix matches the prefix blacklist.
+
+ for( i = 0; i < (int) countof( kMDNSInterfacePrefixBlacklist ); ++i )
+ {
+ const char * const prefix = kMDNSInterfacePrefixBlacklist[ i ];
+
+ if( strcmp_prefix( inIfName, prefix ) == 0 )
+ {
+ const char * ptr = &inIfName[ strlen( prefix ) ];
+
+ while( isdigit_safe( *ptr ) ) ++ptr;
+ if( *ptr == '\0' ) return( true );
+ }
+ }
+
+ // Check if the interface is used for inter-(co)processor networking.
+
+ memset( &ifr, 0, sizeof( ifr ) );
+ strlcpy( ifr.ifr_name, inIfName, sizeof( ifr.ifr_name ) );
+ err = ioctl( inInfoSock, SIOCGIFFUNCTIONALTYPE, &ifr );
+ err = map_global_value_errno( err != -1, err );
+ if( !err && ( ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC ) ) return( true );
+
+ return( false );
+}
+
+//===========================================================================================================================
+// _MDNSInterfaceListFree
+//===========================================================================================================================
+
+static void _MDNSInterfaceListFree( MDNSInterfaceItem *inList )
+{
+ MDNSInterfaceItem * item;
+
+ while( ( item = inList ) != NULL )
+ {
+ inList = item->next;
+ FreeNullSafe( item->ifName );
+ free( item );
+ }
+}
+
+//===========================================================================================================================
+// _MDNSInterfaceGetAny
+//===========================================================================================================================
+
+static OSStatus _MDNSInterfaceGetAny( MDNSInterfaceSubset inSubset, char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex )
+{
+ OSStatus err;
+ MDNSInterfaceItem * list;
+ const MDNSInterfaceItem * item;
+
+ list = NULL;
+ err = _MDNSInterfaceListCreate( inSubset, 0, &list );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( list, exit, err = kNotFoundErr );
+
+ for( item = list; item; item = item->next )
+ {
+ if( item->hasIPv4 && item->hasIPv6 ) break;
+ }
+ if( !item ) item = list;
+ if( inNameBuf ) strlcpy( inNameBuf, item->ifName, IF_NAMESIZE + 1 );
+ if( outIndex ) *outIndex = item->ifIndex;
+
+exit:
+ _MDNSInterfaceListFree( list );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SetComputerName
+//===========================================================================================================================
+
+static OSStatus _SetComputerName( CFStringRef inComputerName, CFStringEncoding inEncoding )
+{
+ OSStatus err;
+ SCPreferencesRef prefs;
+ Boolean ok;
+
+ prefs = SCPreferencesCreateWithAuthorization( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+ err = map_scerror( prefs );
+ require_noerr_quiet( err, exit );
+
+ ok = SCPreferencesSetComputerName( prefs, inComputerName, inEncoding );
+ err = map_scerror( ok );
+ require_noerr_quiet( err, exit );
+
+ ok = SCPreferencesCommitChanges( prefs );
+ err = map_scerror( ok );
+ require_noerr_quiet( err, exit );
+
+ ok = SCPreferencesApplyChanges( prefs );
+ err = map_scerror( ok );
+ require_noerr_quiet( err, exit );
+
+exit:
+ CFReleaseNullSafe( prefs );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SetComputerNameWithUTF8CString
+//===========================================================================================================================
+
+static OSStatus _SetComputerNameWithUTF8CString( const char *inComputerName )
+{
+ OSStatus err;
+ CFStringRef computerName;
+
+ computerName = CFStringCreateWithCString( NULL, inComputerName, kCFStringEncodingUTF8 );
+ require_action( computerName, exit, err = kNoMemoryErr );
+
+ err = _SetComputerName( computerName, kCFStringEncodingUTF8 );
+ require_noerr_quiet( err, exit );
+
+exit:
+ CFReleaseNullSafe( computerName );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SetLocalHostName
+//===========================================================================================================================
+
+static OSStatus _SetLocalHostName( CFStringRef inLocalHostName )
+{
+ OSStatus err;
+ SCPreferencesRef prefs;
+ Boolean ok;
+
+ prefs = SCPreferencesCreateWithAuthorization( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+ err = map_scerror( prefs );
+ require_noerr_quiet( err, exit );
+
+ ok = SCPreferencesSetLocalHostName( prefs, inLocalHostName );
+ err = map_scerror( ok );
+ require_noerr_quiet( err, exit );
+
+ ok = SCPreferencesCommitChanges( prefs );
+ err = map_scerror( ok );
+ require_noerr_quiet( err, exit );
+
+ ok = SCPreferencesApplyChanges( prefs );
+ err = map_scerror( ok );
+ require_noerr_quiet( err, exit );
+
+exit:
+ CFReleaseNullSafe( prefs );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SetLocalHostNameWithUTF8CString
+//===========================================================================================================================
+
+static OSStatus _SetLocalHostNameWithUTF8CString( const char *inLocalHostName )
+{
+ OSStatus err;
+ CFStringRef localHostName;
+
+ localHostName = CFStringCreateWithCString( NULL, inLocalHostName, kCFStringEncodingUTF8 );
+ require_action( localHostName, exit, err = kNoMemoryErr );
+
+ err = _SetLocalHostName( localHostName );
+ require_noerr_quiet( err, exit );
+
+exit:
+ CFReleaseNullSafe( localHostName );
+ return( err );
+}
+
+//===========================================================================================================================
+// MDNSColliderCreate
+//===========================================================================================================================
+
+typedef enum
+{
+ kMDNSColliderOpCode_Invalid = 0,
+ kMDNSColliderOpCode_Send = 1,
+ kMDNSColliderOpCode_Wait = 2,
+ kMDNSColliderOpCode_SetProbeActions = 3,
+ kMDNSColliderOpCode_LoopPush = 4,
+ kMDNSColliderOpCode_LoopPop = 5,
+ kMDNSColliderOpCode_Exit = 6
+
+} MDNSColliderOpCode;
+
+typedef struct
+{
+ MDNSColliderOpCode opcode;
+ uint32_t operand;
+
+} MDNSCInstruction;
+
+#define kMaxLoopDepth 16
+
+struct MDNSColliderPrivate
+{
+ CFRuntimeBase base; // CF object base.
+ dispatch_queue_t queue; // Queue for collider's events.
+ dispatch_source_t readSourceV4; // Read dispatch source for IPv4 socket.
+ dispatch_source_t readSourceV6; // Read dispatch source for IPv6 socket.
+ SocketRef sockV4; // IPv4 UDP socket for mDNS.
+ SocketRef sockV6; // IPv6 UDP socket for mDNS.
+ uint8_t * target; // Record name being targeted. (malloced)
+ uint8_t * responsePtr; // Response message pointer. (malloced)
+ size_t responseLen; // Response message length.
+ uint8_t * probePtr; // Probe query message pointer. (malloced)
+ size_t probeLen; // Probe query message length.
+ unsigned int probeCount; // Count of probe queries received for collider's record.
+ uint32_t probeActionMap; // Bitmap of actions to take for
+ MDNSCInstruction * program; // Program to execute.
+ uint32_t pc; // Program's program counter.
+ uint32_t loopCounts[ kMaxLoopDepth ]; // Stack of loop counters.
+ uint32_t loopDepth; // Current loop depth.
+ dispatch_source_t waitTimer; // Timer for program's wait commands.
+ uint32_t interfaceIndex; // Interface over which to send and receive mDNS msgs.
+ MDNSColliderStopHandler_f stopHandler; // User's stop handler.
+ void * stopContext; // User's stop handler context.
+ MDNSColliderProtocols protocols; // Protocols to use, i.e., IPv4, IPv6.
+ Boolean stopped; // True if the collider has been stopped.
+ uint8_t msgBuf[ kMDNSMessageSizeMax ]; // mDNS message buffer.
+};
+
+static void _MDNSColliderStop( MDNSColliderRef inCollider, OSStatus inError );
+static void _MDNSColliderReadHandler( void *inContext );
+static void _MDNSColliderExecuteProgram( void *inContext );
+static OSStatus _MDNSColliderSendResponse( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
+static OSStatus _MDNSColliderSendProbe( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
+
+CF_CLASS_DEFINE( MDNSCollider );
+
+ulog_define_ex( kDNSSDUtilIdentifier, MDNSCollider, kLogLevelInfo, kLogFlags_None, "MDNSCollider", NULL );
+#define mc_ulog( LEVEL, ... ) ulog( &log_category_from_name( MDNSCollider ), (LEVEL), __VA_ARGS__ )
+
+static OSStatus MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider )
+{
+ OSStatus err;
+ MDNSColliderRef obj = NULL;
+
+ CF_OBJECT_CREATE( MDNSCollider, obj, err, exit );
+
+ ReplaceDispatchQueue( &obj->queue, inQueue );
+ obj->sockV4 = kInvalidSocketRef;
+ obj->sockV6 = kInvalidSocketRef;
+
+ *outCollider = obj;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSColliderFinalize
+//===========================================================================================================================
+
+static void _MDNSColliderFinalize( CFTypeRef inObj )
+{
+ MDNSColliderRef const me = (MDNSColliderRef) inObj;
+
+ check( !me->waitTimer );
+ check( !me->readSourceV4 );
+ check( !me->readSourceV6 );
+ check( !IsValidSocket( me->sockV4 ) );
+ check( !IsValidSocket( me->sockV6 ) );
+ ForgetMem( &me->target );
+ ForgetMem( &me->responsePtr );
+ ForgetMem( &me->probePtr );
+ ForgetMem( &me->program );
+ dispatch_forget( &me->queue );
+}
+
+//===========================================================================================================================
+// MDNSColliderStart
+//===========================================================================================================================
+
+static void _MDNSColliderStart( void *inContext );
+
+static OSStatus MDNSColliderStart( MDNSColliderRef me )
+{
+ OSStatus err;
+
+ require_action_quiet( me->target, exit, err = kNotPreparedErr );
+ require_action_quiet( me->responsePtr, exit, err = kNotPreparedErr );
+ require_action_quiet( me->probePtr, exit, err = kNotPreparedErr );
+ require_action_quiet( me->program, exit, err = kNotPreparedErr );
+ require_action_quiet( me->interfaceIndex, exit, err = kNotPreparedErr );
+ require_action_quiet( me->protocols, exit, err = kNotPreparedErr );
+
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _MDNSColliderStart );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+static void _MDNSColliderStart( void *inContext )
+{
+ OSStatus err;
+ MDNSColliderRef const me = (MDNSColliderRef) inContext;
+ SocketRef sock = kInvalidSocketRef;
+ SocketContext * sockCtx = NULL;
+
+ if( me->protocols & kMDNSColliderProtocol_IPv4 )
+ {
+ err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
+ require_noerr( err, exit );
+
+ err = SocketContextCreate( sock, me, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
+ sockCtx, &me->readSourceV4 );
+ require_noerr( err, exit );
+ me->sockV4 = sockCtx->sock;
+ sockCtx = NULL;
+
+ dispatch_resume( me->readSourceV4 );
+ }
+
+ if( me->protocols & kMDNSColliderProtocol_IPv6 )
+ {
+ err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
+ require_noerr( err, exit );
+
+ err = SocketContextCreate( sock, me, &sockCtx );
+ require_noerr( err, exit );
+ sock = kInvalidSocketRef;
+
+ err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
+ sockCtx, &me->readSourceV6 );
+ require_noerr( err, exit );
+ me->sockV6 = sockCtx->sock;
+ sockCtx = NULL;
+
+ dispatch_resume( me->readSourceV6 );
+ }
+
+ _MDNSColliderExecuteProgram( me );
+ err = kNoErr;
+
+exit:
+ ForgetSocket( &sock );
+ ForgetSocketContext( &sockCtx );
+ if( err ) _MDNSColliderStop( me, err );
+}
+
+//===========================================================================================================================
+// MDNSColliderStop
+//===========================================================================================================================
+
+static void _MDNSColliderUserStop( void *inContext );
+
+static void MDNSColliderStop( MDNSColliderRef me )
+{
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _MDNSColliderUserStop );
+}
+
+static void _MDNSColliderUserStop( void *inContext )
+{
+ MDNSColliderRef const me = (MDNSColliderRef) inContext;
+
+ _MDNSColliderStop( me, kCanceledErr );
+ CFRelease( me );
+}
+
+//===========================================================================================================================
+// MDNSColliderSetProtocols
+//===========================================================================================================================
+
+static void MDNSColliderSetProtocols( MDNSColliderRef me, MDNSColliderProtocols inProtocols )
+{
+ me->protocols = inProtocols;
+}
+
+//===========================================================================================================================
+// MDNSColliderSetInterfaceIndex
+//===========================================================================================================================
+
+static void MDNSColliderSetInterfaceIndex( MDNSColliderRef me, uint32_t inInterfaceIndex )
+{
+ me->interfaceIndex = inInterfaceIndex;
+}
+
+//===========================================================================================================================
+// MDNSColliderSetProgram
+//===========================================================================================================================
+
+#define kMDNSColliderProgCmd_Done "done"
+#define kMDNSColliderProgCmd_Loop "loop"
+#define kMDNSColliderProgCmd_Send "send"
+#define kMDNSColliderProgCmd_Probes "probes"
+#define kMDNSColliderProgCmd_Wait "wait"
+
+typedef uint32_t MDNSColliderProbeAction;
+
+#define kMDNSColliderProbeAction_None 0
+#define kMDNSColliderProbeAction_Respond 1
+#define kMDNSColliderProbeAction_RespondUnicast 2
+#define kMDNSColliderProbeAction_RespondMulticast 3
+#define kMDNSColliderProbeAction_Probe 4
+#define kMDNSColliderProbeAction_MaxValue kMDNSColliderProbeAction_Probe
+
+#define kMDNSColliderProbeActionBits_Count 3
+#define kMDNSColliderProbeActionBits_Mask ( ( 1U << kMDNSColliderProbeActionBits_Count ) - 1 )
+#define kMDNSColliderProbeActionMaxProbeCount ( 32 / kMDNSColliderProbeActionBits_Count )
+
+check_compile_time( kMDNSColliderProbeAction_MaxValue <= kMDNSColliderProbeActionBits_Mask );
+
+static OSStatus _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap );
+
+static OSStatus MDNSColliderSetProgram( MDNSColliderRef me, const char *inProgramStr )
+{
+ OSStatus err;
+ uint32_t insCount;
+ unsigned int loopDepth;
+ const char * cmd;
+ const char * end;
+ const char * next;
+ MDNSCInstruction * program = NULL;
+ uint32_t loopStart[ kMaxLoopDepth ];
+
+ insCount = 0;
+ for( cmd = inProgramStr; *cmd; cmd = next )
+ {
+ for( end = cmd; *end && ( *end != ';' ); ++end ) {}
+ require_action_quiet( end != cmd, exit, err = kMalformedErr );
+ next = ( *end == ';' ) ? ( end + 1 ) : end;
+ ++insCount;
+ }
+
+ program = (MDNSCInstruction *) calloc( insCount + 1, sizeof( *program ) );
+ require_action( program, exit, err = kNoMemoryErr );
+
+ insCount = 0;
+ loopDepth = 0;
+ for( cmd = inProgramStr; *cmd; cmd = next )
+ {
+ size_t cmdLen;
+ const char * ptr;
+ const char * arg;
+ size_t argLen;
+ uint32_t value;
+ MDNSCInstruction * const ins = &program[ insCount ];
+
+ while( isspace_safe( *cmd ) ) ++cmd;
+ for( end = cmd; *end && ( *end != ';' ); ++end ) {}
+ next = ( *end == ';' ) ? ( end + 1 ) : end;
+
+ for( ptr = cmd; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
+ cmdLen = (size_t)( ptr - cmd );
+
+ // Done statement
+
+ if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Done ) == 0 )
+ {
+ while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+ require_action_quiet( ptr == end, exit, err = kMalformedErr );
+
+ require_action_quiet( loopDepth > 0, exit, err = kMalformedErr );
+
+ ins->opcode = kMDNSColliderOpCode_LoopPop;
+ ins->operand = loopStart[ --loopDepth ];
+ }
+
+ // Loop command
+
+ else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Loop ) == 0 )
+ {
+ for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
+ err = DecimalTextToUInt32( arg, end, &value, &ptr );
+ require_noerr_quiet( err, exit );
+ require_action_quiet( value > 0, exit, err = kValueErr );
+
+ while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+ require_action_quiet( ptr == end, exit, err = kMalformedErr );
+
+ ins->opcode = kMDNSColliderOpCode_LoopPush;
+ ins->operand = value;
+
+ require_action_quiet( loopDepth < kMaxLoopDepth, exit, err = kNoSpaceErr );
+ loopStart[ loopDepth++ ] = insCount + 1;
+ }
+
+ // Probes command
+
+ else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Probes ) == 0 )
+ {
+ for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
+ for( ptr = arg; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
+ argLen = (size_t)( ptr - arg );
+ if( argLen > 0 )
+ {
+ err = _MDNSColliderParseProbeActionString( arg, argLen, &value );
+ require_noerr_quiet( err, exit );
+ }
+ else
+ {
+ value = 0;
+ }
+
+ while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+ require_action_quiet( ptr == end, exit, err = kMalformedErr );
+
+ ins->opcode = kMDNSColliderOpCode_SetProbeActions;
+ ins->operand = value;
+ }
+
+ // Send command
+
+ else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Send ) == 0 )
+ {
+ while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+ require_action_quiet( ptr == end, exit, err = kMalformedErr );
+
+ ins->opcode = kMDNSColliderOpCode_Send;
+ }
+
+ // Wait command
+
+ else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Wait ) == 0 )
+ {
+ for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
+ err = DecimalTextToUInt32( arg, end, &value, &ptr );
+ require_noerr_quiet( err, exit );
+
+ while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+ require_action_quiet( ptr == end, exit, err = kMalformedErr );
+
+ ins->opcode = kMDNSColliderOpCode_Wait;
+ ins->operand = value;
+ }
+
+ // Unrecognized command
+
+ else
+ {
+ err = kCommandErr;
+ goto exit;
+ }
+ ++insCount;
+ }
+ require_action_quiet( loopDepth == 0, exit, err = kMalformedErr );
+
+ program[ insCount ].opcode = kMDNSColliderOpCode_Exit;
+
+ FreeNullSafe( me->program );
+ me->program = program;
+ program = NULL;
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( program );
+ return( err );
+}
+
+static OSStatus _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap )
+{
+ OSStatus err;
+ const char * ptr;
+ const char * const end = &inString[ inLen ];
+ uint32_t bitmap;
+ int index;
+
+ bitmap = 0;
+ index = 0;
+ ptr = inString;
+ while( ptr < end )
+ {
+ int c, count;
+ MDNSColliderProbeAction action;
+
+ c = *ptr++;
+ if( isdigit_safe( c ) )
+ {
+ count = 0;
+ do
+ {
+ count = ( count * 10 ) + ( c - '0' );
+ require_action_quiet( count <= ( kMDNSColliderProbeActionMaxProbeCount - index ), exit, err = kCountErr );
+ require_action_quiet( ptr < end, exit, err = kUnderrunErr );
+ c = *ptr++;
+
+ } while( isdigit_safe( c ) );
+ require_action_quiet( count > 0, exit, err = kCountErr );
+ }
+ else
+ {
+ require_action_quiet( index < kMDNSColliderProbeActionMaxProbeCount, exit, err = kMalformedErr );
+ count = 1;
+ }
+
+ switch( c )
+ {
+ case 'n': action = kMDNSColliderProbeAction_None; break;
+ case 'r': action = kMDNSColliderProbeAction_Respond; break;
+ case 'u': action = kMDNSColliderProbeAction_RespondUnicast; break;
+ case 'm': action = kMDNSColliderProbeAction_RespondMulticast; break;
+ case 'p': action = kMDNSColliderProbeAction_Probe; break;
+ default: err = kMalformedErr; goto exit;
+ }
+ if( ptr < end )
+ {
+ c = *ptr++;
+ require_action_quiet( ( c == '-' ) && ( ptr < end ), exit, err = kMalformedErr );
+ }
+ while( count-- > 0 )
+ {
+ bitmap |= ( action << ( index * kMDNSColliderProbeActionBits_Count ) );
+ ++index;
+ }
+ }
+
+ *outBitmap = bitmap;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// MDNSColliderSetStopHandler
+//===========================================================================================================================
+
+static void MDNSColliderSetStopHandler( MDNSColliderRef me, MDNSColliderStopHandler_f inStopHandler, void *inStopContext )
+{
+ me->stopHandler = inStopHandler;
+ me->stopContext = inStopContext;
+}
+
+//===========================================================================================================================
+// MDNSColliderSetRecord
+//===========================================================================================================================
+
+#define kMDNSColliderDummyStr "\x16" "mdnscollider-sent-this" "\x05" "local"
+#define kMDNSColliderDummyName ( (const uint8_t *) kMDNSColliderDummyStr )
+#define kMDNSColliderDummyNameLen sizeof( kMDNSColliderDummyStr )
+
+static OSStatus
+ MDNSColliderSetRecord(
+ MDNSColliderRef me,
+ const uint8_t * inName,
+ uint16_t inType,
+ const void * inRDataPtr,
+ size_t inRDataLen )
+{
+ OSStatus err;
+ DataBuffer msgDB;
+ DNSHeader header;
+ uint8_t * targetPtr = NULL;
+ size_t targetLen;
+ uint8_t * responsePtr = NULL;
+ size_t responseLen;
+ uint8_t * probePtr = NULL;
+ size_t probeLen;
+
+ DataBuffer_Init( &msgDB, NULL, 0, kMDNSMessageSizeMax );
+
+ err = DomainNameDup( inName, &targetPtr, &targetLen );
+ require_noerr_quiet( err, exit );
+
+ // Create response message.
+
+ memset( &header, 0, sizeof( header ) );
+ DNSHeaderSetFlags( &header, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
+ DNSHeaderSetAnswerCount( &header, 1 );
+
+ err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
+ require_noerr( err, exit );
+
+ err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN | kRRClassCacheFlushBit,
+ 1976, inRDataPtr, inRDataLen );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &msgDB, &responsePtr, &responseLen );
+ require_noerr( err, exit );
+
+ // Create probe message.
+
+ memset( &header, 0, sizeof( header ) );
+ DNSHeaderSetQuestionCount( &header, 2 );
+ DNSHeaderSetAuthorityCount( &header, 1 );
+
+ err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
+ require_noerr( err, exit );
+
+ err = _DataBuffer_AppendDNSQuestion( &msgDB, targetPtr, targetLen, kDNSServiceType_ANY, kDNSServiceClass_IN );
+ require_noerr( err, exit );
+
+ err = _DataBuffer_AppendDNSQuestion( &msgDB, kMDNSColliderDummyName, kMDNSColliderDummyNameLen,
+ kDNSServiceType_NULL, kDNSServiceClass_IN );
+ require_noerr( err, exit );
+
+ err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN,
+ 1976, inRDataPtr, inRDataLen );
+ require_noerr( err, exit );
+
+ err = DataBuffer_Detach( &msgDB, &probePtr, &probeLen );
+ require_noerr( err, exit );
+
+ FreeNullSafe( me->target );
+ me->target = targetPtr;
+ targetPtr = NULL;
+
+ FreeNullSafe( me->responsePtr );
+ me->responsePtr = responsePtr;
+ me->responseLen = responseLen;
+ responsePtr = NULL;
+
+ FreeNullSafe( me->probePtr );
+ me->probePtr = probePtr;
+ me->probeLen = probeLen;
+ probePtr = NULL;
+
+exit:
+ DataBuffer_Free( &msgDB );
+ FreeNullSafe( targetPtr );
+ FreeNullSafe( responsePtr );
+ FreeNullSafe( probePtr );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSColliderStop
+//===========================================================================================================================
+
+static void _MDNSColliderStop( MDNSColliderRef me, OSStatus inError )
+{
+ dispatch_source_forget( &me->waitTimer );
+ dispatch_source_forget( &me->readSourceV4 );
+ dispatch_source_forget( &me->readSourceV6 );
+ me->sockV4 = kInvalidSocketRef;
+ me->sockV6 = kInvalidSocketRef;
+
+ if( !me->stopped )
+ {
+ me->stopped = true;
+ if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
+ CFRelease( me );
+ }
+}
+
+//===========================================================================================================================
+// _MDNSColliderReadHandler
+//===========================================================================================================================
+
+static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber );
+static const char * _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction );
+
+static void _MDNSColliderReadHandler( void *inContext )
+{
+ OSStatus err;
+ struct timeval now;
+ SocketContext * const sockCtx = (SocketContext *) inContext;
+ MDNSColliderRef const me = (MDNSColliderRef) sockCtx->userContext;
+ size_t msgLen;
+ sockaddr_ip sender;
+ const DNSHeader * hdr;
+ const uint8_t * ptr;
+ const struct sockaddr * dest;
+ int probeFound, probeIsQU;
+ unsigned int qCount, i;
+ MDNSColliderProbeAction action;
+
+ gettimeofday( &now, NULL );
+
+ err = SocketRecvFrom( sockCtx->sock, me->msgBuf, sizeof( me->msgBuf ), &msgLen, &sender, sizeof( sender ),
+ NULL, NULL, NULL, NULL );
+ require_noerr( err, exit );
+
+ require_quiet( msgLen >= kDNSHeaderLength, exit );
+ hdr = (const DNSHeader *) me->msgBuf;
+
+ probeFound = false;
+ probeIsQU = false;
+ qCount = DNSHeaderGetQuestionCount( hdr );
+ ptr = (const uint8_t *) &hdr[ 1 ];
+ for( i = 0; i < qCount; ++i )
+ {
+ uint16_t qtype, qclass;
+ uint8_t qname[ kDomainNameLengthMax ];
+
+ err = DNSMessageExtractQuestion( me->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
+ require_noerr_quiet( err, exit );
+
+ if( ( qtype == kDNSServiceType_NULL ) && ( qclass == kDNSServiceClass_IN ) &&
+ DomainNameEqual( qname, kMDNSColliderDummyName ) )
+ {
+ probeFound = false;
+ break;
+ }
+
+ if( qtype != kDNSServiceType_ANY ) continue;
+ if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
+ if( !DomainNameEqual( qname, me->target ) ) continue;
+
+ if( !probeFound )
+ {
+ probeFound = true;
+ probeIsQU = ( qclass & kQClassUnicastResponseBit ) ? true : false;
+ }
+ }
+ require_quiet( probeFound, exit );
+
+ ++me->probeCount;
+ action = _MDNSColliderGetProbeAction( me->probeActionMap, me->probeCount );
+
+ mc_ulog( kLogLevelInfo, "Received probe from %##a at %{du:time} (action: %s):\n\n%#1{du:dnsmsg}",
+ &sender, &now, _MDNSColliderProbeActionToString( action ), me->msgBuf, msgLen );
+
+ if( ( action == kMDNSColliderProbeAction_Respond ) ||
+ ( action == kMDNSColliderProbeAction_RespondUnicast ) ||
+ ( action == kMDNSColliderProbeAction_RespondMulticast ) )
+ {
+ if( ( ( action == kMDNSColliderProbeAction_Respond ) && probeIsQU ) ||
+ ( action == kMDNSColliderProbeAction_RespondUnicast ) )
+ {
+ dest = &sender.sa;
+ }
+ else if( ( ( action == kMDNSColliderProbeAction_Respond ) && !probeIsQU ) ||
+ ( action == kMDNSColliderProbeAction_RespondMulticast ) )
+ {
+ dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
+ }
+
+ err = _MDNSColliderSendResponse( me, sockCtx->sock, dest );
+ require_noerr( err, exit );
+ }
+ else if( action == kMDNSColliderProbeAction_Probe )
+ {
+ dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
+
+ err = _MDNSColliderSendProbe( me, sockCtx->sock, dest );
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber )
+{
+ MDNSColliderProbeAction action;
+
+ if( ( inProbeNumber >= 1 ) && ( inProbeNumber <= kMDNSColliderProbeActionMaxProbeCount ) )
+ {
+ action = ( inBitmap >> ( ( inProbeNumber - 1 ) * kMDNSColliderProbeActionBits_Count ) ) &
+ kMDNSColliderProbeActionBits_Mask;
+ }
+ else
+ {
+ action = kMDNSColliderProbeAction_None;
+ }
+ return( action );
+}
+
+static const char * _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction )
+{
+ switch( inAction )
+ {
+ case kMDNSColliderProbeAction_None: return( "None" );
+ case kMDNSColliderProbeAction_Respond: return( "Respond" );
+ case kMDNSColliderProbeAction_RespondUnicast: return( "Respond (unicast)" );
+ case kMDNSColliderProbeAction_RespondMulticast: return( "Respond (multicast)" );
+ case kMDNSColliderProbeAction_Probe: return( "Probe" );
+ default: return( "???" );
+ }
+}
+
+//===========================================================================================================================
+// _MDNSColliderExecuteProgram
+//===========================================================================================================================
+
+static void _MDNSColliderExecuteProgram( void *inContext )
+{
+ OSStatus err;
+ MDNSColliderRef const me = (MDNSColliderRef) inContext;
+ int stop;
+
+ dispatch_forget( &me->waitTimer );
+
+ stop = false;
+ for( ;; )
+ {
+ const MDNSCInstruction * const ins = &me->program[ me->pc++ ];
+ uint32_t waitMs;
+
+ switch( ins->opcode )
+ {
+ case kMDNSColliderOpCode_Send:
+ if( IsValidSocket( me->sockV4 ) )
+ {
+ err = _MDNSColliderSendResponse( me, me->sockV4, GetMDNSMulticastAddrV4() );
+ require_noerr( err, exit );
+ }
+ if( IsValidSocket( me->sockV6 ) )
+ {
+ err = _MDNSColliderSendResponse( me, me->sockV6, GetMDNSMulticastAddrV6() );
+ require_noerr( err, exit );
+ }
+ break;
+
+ case kMDNSColliderOpCode_Wait:
+ waitMs = ins->operand;
+ if( waitMs > 0 )
+ {
+ err = DispatchTimerOneShotCreate( dispatch_time_milliseconds( waitMs ), 1, me->queue,
+ _MDNSColliderExecuteProgram, me, &me->waitTimer );
+ require_noerr( err, exit );
+ dispatch_resume( me->waitTimer );
+ goto exit;
+ }
+ break;
+
+ case kMDNSColliderOpCode_SetProbeActions:
+ me->probeCount = 0;
+ me->probeActionMap = ins->operand;
+ break;
+
+ case kMDNSColliderOpCode_LoopPush:
+ check( me->loopDepth < kMaxLoopDepth );
+ me->loopCounts[ me->loopDepth++ ] = ins->operand;
+ break;
+
+ case kMDNSColliderOpCode_LoopPop:
+ check( me->loopDepth > 0 );
+ if( --me->loopCounts[ me->loopDepth - 1 ] > 0 )
+ {
+ me->pc = ins->operand;
+ }
+ else
+ {
+ --me->loopDepth;
+ }
+ break;
+
+ case kMDNSColliderOpCode_Exit:
+ stop = true;
+ err = kNoErr;
+ goto exit;
+
+ default:
+ dlogassert( "Unhandled opcode %u\n", ins->opcode );
+ err = kCommandErr;
+ goto exit;
+ }
+ }
+
+exit:
+ if( err || stop ) _MDNSColliderStop( me, err );
+}
+
+//===========================================================================================================================
+// _MDNSColliderSendResponse
+//===========================================================================================================================
+
+static OSStatus _MDNSColliderSendResponse( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
+{
+ OSStatus err;
+ ssize_t n;
+
+ n = sendto( inSock, (char *) me->responsePtr, me->responseLen, 0, inDest, SockAddrGetSize( inDest ) );
+ err = map_socket_value_errno( inSock, n == (ssize_t) me->responseLen, n );
+ return( err );
+}
+
+//===========================================================================================================================
+// _MDNSColliderSendProbe
+//===========================================================================================================================
+
+static OSStatus _MDNSColliderSendProbe( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
+{
+ OSStatus err;
+ ssize_t n;
+
+ n = sendto( inSock, (char *) me->probePtr, me->probeLen, 0, inDest, SockAddrGetSize( inDest ) );
+ err = map_socket_value_errno( inSock, n == (ssize_t) me->probeLen, n );
+ return( err );
+}
+
+//===========================================================================================================================
+// ServiceBrowserCreate
+//===========================================================================================================================
+
+typedef struct SBDomain SBDomain;
+typedef struct SBServiceType SBServiceType;
+typedef struct SBServiceBrowse SBServiceBrowse;
+typedef struct SBServiceInstance SBServiceInstance;
+typedef struct SBIPAddress SBIPAddress;
+
+struct ServiceBrowserPrivate
+{
+ CFRuntimeBase base; // CF object base.
+ dispatch_queue_t queue; // Queue for service browser's events.
+ DNSServiceRef connection; // Shared connection for DNS-SD ops.
+ DNSServiceRef domainsQuery; // Query for recommended browsing domains.
+ char * domain; // If non-null, then browsing is limited to this domain.
+ StringListItem * serviceTypeList; // If non-null, then browsing is limited to these service types.
+ ServiceBrowserCallback_f userCallback; // User's callback. Called when browsing stops.
+ void * userContext; // User's callback context.
+ SBDomain * domainList; // List of domains and their browse results.
+ dispatch_source_t stopTimer; // Timer to stop browsing after browseTimeSecs.
+ uint32_t ifIndex; // If non-zero, then browsing is limited to this interface.
+ unsigned int browseTimeSecs; // Amount of time to spend browsing in seconds.
+ Boolean includeAWDL; // True if the IncludeAWDL flag should be used for DNS-SD ops that
+ // use the "any" interface.
+};
+
+struct SBDomain
+{
+ SBDomain * next; // Next domain object in list.
+ ServiceBrowserRef browser; // Pointer to parent service browser.
+ char * name; // Name of the domain.
+ DNSServiceRef servicesQuery; // Query for services (_services._dns-sd._udp.<domain> PTR record) in domain.
+ SBServiceType * typeList; // List of service types to browse for in this domain.
+};
+
+struct SBServiceType
+{
+ SBServiceType * next; // Next service type object in list.
+ char * name; // Name of the service type.
+ SBServiceBrowse * browseList; // List of browses for this service type.
+};
+
+struct SBServiceBrowse
+{
+ SBServiceBrowse * next; // Next browse object in list.
+ ServiceBrowserRef browser; // Pointer to parent service browser.
+ DNSServiceRef browse; // Reference to DNSServiceBrowse op.
+ SBServiceInstance * instanceList; // List of service instances that were discovered by this browse.
+ uint64_t startTicks; // Value of UpTicks() when the browse op began.
+ uint32_t ifIndex; // If non-zero, then the browse is limited to this interface.
+};
+
+struct SBServiceInstance
+{
+ SBServiceInstance * next; // Next service instance object in list.
+ ServiceBrowserRef browser; // Pointer to parent service browser.
+ char * name; // Name of the service instance.
+ char * fqdn; // Fully qualified domain name of service instance (for logging/debugging).
+ uint32_t ifIndex; // Index of interface over which this service instance was discovered.
+ uint64_t discoverTimeUs; // Time it took to discover this service instance in microseconds.
+ DNSServiceRef resolve; // Reference to DNSServiceResolve op for this service instance.
+ uint64_t resolveStartTicks; // Value of UpTicks() when the DNSServiceResolve op began.
+ uint64_t resolveTimeUs; // Time it took to resolve this service instance.
+ char * hostname; // Service instance's hostname. Result of DNSServiceResolve.
+ uint16_t port; // Service instance's port number. Result of DNSServiceResolve.
+ uint8_t * txtPtr; // Service instance's TXT record data. Result of DNSServiceResolve.
+ size_t txtLen; // Length of service instance's TXT record data.
+ DNSServiceRef getAddrInfo; // Reference to DNSServiceGetAddrInfo op for service instance's hostname.
+ uint64_t gaiStartTicks; // Value of UpTicks() when the DNSServiceGetAddrInfo op began.
+ SBIPAddress * ipaddrList; // List of IP addresses that the hostname resolved to.
+};
+
+struct SBIPAddress
+{
+ SBIPAddress * next; // Next IP address object in list.
+ sockaddr_ip sip; // IPv4 or IPv6 address.
+ uint64_t resolveTimeUs; // Time it took to resolve this IP address in microseconds.
+};
+
+typedef struct
+{
+ SBRDomain * domainList; // List of domains in which services were found.
+ int32_t refCount; // This object's reference count.
+
+} ServiceBrowserResultsPrivate;
+
+static void _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError );
+static OSStatus _ServiceBrowserAddDomain( ServiceBrowserRef inBrowser, const char *inDomain );
+static OSStatus _ServiceBrowserRemoveDomain( ServiceBrowserRef inBrowser, const char *inName );
+static void _ServiceBrowserTimerHandler( void *inContext );
+static void DNSSD_API
+ _ServiceBrowserDomainsQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ _ServiceBrowserServicesQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext );
+static void DNSSD_API
+ _ServiceBrowserBrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext );
+static void DNSSD_API
+ _ServiceBrowserResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext );
+static void DNSSD_API
+ _ServiceBrowserGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext );
+static OSStatus
+ _ServiceBrowserAddServiceType(
+ ServiceBrowserRef inBrowser,
+ SBDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex );
+static OSStatus
+ _ServiceBrowserRemoveServiceType(
+ ServiceBrowserRef inBrowser,
+ SBDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex );
+static OSStatus
+ _ServiceBrowserAddServiceInstance(
+ ServiceBrowserRef inBrowser,
+ SBServiceBrowse * inBrowse,
+ uint32_t inIfIndex,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ uint64_t inDiscoverTimeUs );
+static OSStatus
+ _ServiceBrowserRemoveServiceInstance(
+ ServiceBrowserRef inBrowser,
+ SBServiceBrowse * inBrowse,
+ const char * inName,
+ uint32_t inIfIndex );
+static OSStatus
+ _ServiceBrowserAddIPAddress(
+ ServiceBrowserRef inBrowser,
+ SBServiceInstance * inInstance,
+ const struct sockaddr * inSockAddr,
+ uint64_t inResolveTimeUs );
+static OSStatus
+ _ServiceBrowserRemoveIPAddress(
+ ServiceBrowserRef inBrowser,
+ SBServiceInstance * inInstance,
+ const struct sockaddr * inSockAddr );
+static OSStatus _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults );
+static OSStatus _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain );
+static void _SBDomainFree( SBDomain *inDomain );
+static OSStatus _SBServiceTypeCreate( const char *inName, SBServiceType **outType );
+static void _SBServiceTypeFree( SBServiceType *inType );
+static OSStatus _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse );
+static void _SBServiceBrowseFree( SBServiceBrowse *inBrowse );
+static OSStatus
+ _SBServiceInstanceCreate(
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ uint32_t inIfIndex,
+ uint64_t inDiscoverTimeUs,
+ ServiceBrowserRef inBrowser,
+ SBServiceInstance ** outInstance );
+static void _SBServiceInstanceFree( SBServiceInstance *inInstance );
+static OSStatus
+ _SBIPAddressCreate(
+ const struct sockaddr * inSockAddr,
+ uint64_t inResolveTimeUs,
+ SBIPAddress ** outIPAddress );
+static void _SBIPAddressFree( SBIPAddress *inIPAddress );
+static void _SBIPAddressFreeList( SBIPAddress *inList );
+static OSStatus _SBRDomainCreate( const char *inName, SBRDomain **outDomain );
+static void _SBRDomainFree( SBRDomain *inDomain );
+static OSStatus _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType );
+static void _SBRServiceTypeFree( SBRServiceType *inType );
+static OSStatus
+ _SBRServiceInstanceCreate(
+ const char * inName,
+ uint32_t inInterfaceIndex,
+ const char * inHostname,
+ uint16_t inPort,
+ const uint8_t * inTXTPtr,
+ size_t inTXTLen,
+ uint64_t inDiscoverTimeUs,
+ uint64_t inResolveTimeUs,
+ SBRServiceInstance ** outInstance );
+static void _SBRServiceInstanceFree( SBRServiceInstance *inInstance );
+static OSStatus
+ _SBRIPAddressCreate(
+ const struct sockaddr * inSockAddr,
+ uint64_t inResolveTimeUs,
+ SBRIPAddress ** outIPAddress );
+static void _SBRIPAddressFree( SBRIPAddress *inIPAddress );
+
+#define ForgetSBIPAddressList( X ) ForgetCustom( X, _SBIPAddressFreeList )
+
+CF_CLASS_DEFINE( ServiceBrowser );
+
+ulog_define_ex( kDNSSDUtilIdentifier, ServiceBrowser, kLogLevelTrace, kLogFlags_None, "ServiceBrowser", NULL );
+#define sb_ulog( LEVEL, ... ) ulog( &log_category_from_name( ServiceBrowser ), (LEVEL), __VA_ARGS__ )
+
+static OSStatus
+ ServiceBrowserCreate(
+ dispatch_queue_t inQueue,
+ uint32_t inInterfaceIndex,
+ const char * inDomain,
+ unsigned int inBrowseTimeSecs,
+ Boolean inIncludeAWDL,
+ ServiceBrowserRef * outBrowser )
+{
+ OSStatus err;
+ ServiceBrowserRef obj;
+
+ CF_OBJECT_CREATE( ServiceBrowser, obj, err, exit );
+
+ ReplaceDispatchQueue( &obj->queue, inQueue );
+ obj->ifIndex = inInterfaceIndex;
+ if( inDomain )
+ {
+ obj->domain = strdup( inDomain );
+ require_action( obj->domain, exit, err = kNoMemoryErr );
+ }
+ obj->browseTimeSecs = inBrowseTimeSecs;
+ obj->includeAWDL = inIncludeAWDL;
+
+ *outBrowser = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ CFReleaseNullSafe( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserFinalize
+//===========================================================================================================================
+
+static void _ServiceBrowserFinalize( CFTypeRef inObj )
+{
+ ServiceBrowserRef const me = (ServiceBrowserRef) inObj;
+ StringListItem * serviceType;
+
+ dispatch_forget( &me->queue );
+ check( !me->connection );
+ check( !me->domainsQuery );
+ ForgetMem( &me->domain );
+ while( ( serviceType = me->serviceTypeList ) != NULL )
+ {
+ me->serviceTypeList = serviceType->next;
+ ForgetMem( &serviceType->str );
+ free( serviceType );
+ }
+ check( !me->domainList );
+ check( !me->stopTimer );
+}
+
+//===========================================================================================================================
+// ServiceBrowserStart
+//===========================================================================================================================
+
+static void _ServiceBrowserStart( void *inContext );
+
+static void ServiceBrowserStart( ServiceBrowserRef me )
+{
+ CFRetain( me );
+ dispatch_async_f( me->queue, me, _ServiceBrowserStart );
+}
+
+static void _ServiceBrowserStart( void *inContext )
+{
+ OSStatus err;
+ ServiceBrowserRef const me = (ServiceBrowserRef) inContext;
+
+ err = DNSServiceCreateConnection( &me->connection );
+ require_noerr( err, exit );
+
+ err = DNSServiceSetDispatchQueue( me->connection, me->queue );
+ require_noerr( err, exit );
+
+ if( me->domain )
+ {
+ err = _ServiceBrowserAddDomain( me, me->domain );
+ require_noerr( err, exit );
+ }
+ else
+ {
+ DNSServiceRef sdRef;
+ const char * const recordName = "b._dns-sd._udp.local.";
+ const uint32_t ifIndex = kDNSServiceInterfaceIndexLocalOnly;
+
+ // Perform PTR meta-query for "b._dns-sd._udp.local." to enumerate recommended browsing domains.
+ // See <https://tools.ietf.org/html/rfc6763#section-11>.
+
+ sb_ulog( kLogLevelTrace, "Starting PTR QueryRecord on interface %d for %s", (int32_t) ifIndex, recordName );
+
+ sdRef = me->connection;
+ err = DNSServiceQueryRecord( &sdRef, kDNSServiceFlagsShareConnection, ifIndex, recordName,
+ kDNSServiceType_PTR, kDNSServiceClass_IN, _ServiceBrowserDomainsQueryCallback, me );
+ require_noerr( err, exit );
+
+ me->domainsQuery = sdRef;
+ }
+
+ err = DispatchTimerCreate( dispatch_time_seconds( me->browseTimeSecs ), DISPATCH_TIME_FOREVER,
+ 100 * kNanosecondsPerMillisecond, me->queue, _ServiceBrowserTimerHandler, NULL, me, &me->stopTimer );
+ require_noerr( err, exit );
+ dispatch_resume( me->stopTimer );
+
+exit:
+ if( err ) _ServiceBrowserStop( me, err );
+}
+
+//===========================================================================================================================
+// ServiceBrowserAddServiceType
+//===========================================================================================================================
+
+static OSStatus ServiceBrowserAddServiceType( ServiceBrowserRef me, const char *inServiceType )
+{
+ OSStatus err;
+ StringListItem * item;
+ StringListItem ** itemPtr;
+ StringListItem * newItem = NULL;
+
+ for( itemPtr = &me->serviceTypeList; ( item = *itemPtr ) != NULL; itemPtr = &item->next )
+ {
+ if( strcmp( item->str, inServiceType ) == 0 ) break;
+ }
+ if( !item )
+ {
+ newItem = (StringListItem *) calloc( 1, sizeof( *newItem ) );
+ require_action( newItem, exit, err = kNoMemoryErr );
+
+ newItem->str = strdup( inServiceType );
+ require_action( newItem->str, exit, err = kNoMemoryErr );
+
+ *itemPtr = newItem;
+ newItem = NULL;
+ }
+ err = kNoErr;
+
+exit:
+ FreeNullSafe( newItem );
+ return( err );
+}
+
+//===========================================================================================================================
+// ServiceBrowserSetCallback
+//===========================================================================================================================
+
+static void ServiceBrowserSetCallback( ServiceBrowserRef me, ServiceBrowserCallback_f inCallback, void *inContext )
+{
+ me->userCallback = inCallback;
+ me->userContext = inContext;
+}
+
+//===========================================================================================================================
+// ServiceBrowserResultsRetain
+//===========================================================================================================================
+
+static void ServiceBrowserResultsRetain( ServiceBrowserResults *inResults )
+{
+ ServiceBrowserResultsPrivate * const results = (ServiceBrowserResultsPrivate *) inResults;
+
+ atomic_add_32( &results->refCount, 1 );
+}
+
+//===========================================================================================================================
+// ServiceBrowserResultsRelease
+//===========================================================================================================================
+
+static void ServiceBrowserResultsRelease( ServiceBrowserResults *inResults )
+{
+ ServiceBrowserResultsPrivate * const results = (ServiceBrowserResultsPrivate *) inResults;
+ SBRDomain * domain;
+
+ if( atomic_add_and_fetch_32( &results->refCount, -1 ) == 0 )
+ {
+ while( ( domain = inResults->domainList ) != NULL )
+ {
+ inResults->domainList = domain->next;
+ _SBRDomainFree( domain );
+ }
+ free( inResults );
+ }
+}
+
+//===========================================================================================================================
+// _ServiceBrowserStop
+//===========================================================================================================================
+
+static void _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError )
+{
+ OSStatus err;
+ SBDomain * d;
+ SBServiceType * t;
+ SBServiceBrowse * b;
+ SBServiceInstance * i;
+
+ dispatch_source_forget( &me->stopTimer );
+ DNSServiceForget( &me->domainsQuery );
+ for( d = me->domainList; d; d = d->next )
+ {
+ DNSServiceForget( &d->servicesQuery );
+ for( t = d->typeList; t; t = t->next )
+ {
+ for( b = t->browseList; b; b = b->next )
+ {
+ DNSServiceForget( &b->browse );
+ for( i = b->instanceList; i; i = i->next )
+ {
+ DNSServiceForget( &i->resolve );
+ DNSServiceForget( &i->getAddrInfo );
+ }
+ }
+ }
+ }
+ DNSServiceForget( &me->connection );
+
+ if( me->userCallback )
+ {
+ ServiceBrowserResults * results = NULL;
+
+ err = _ServiceBrowserCreateResults( me, &results );
+ if( !err ) err = inError;
+
+ me->userCallback( results, err, me->userContext );
+ me->userCallback = NULL;
+ me->userContext = NULL;
+ if( results ) ServiceBrowserResultsRelease( results );
+ }
+
+ while( ( d = me->domainList ) != NULL )
+ {
+ me->domainList = d->next;
+ _SBDomainFree( d );
+ }
+ CFRelease( me );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserAddDomain
+//===========================================================================================================================
+
+static OSStatus _ServiceBrowserAddDomain( ServiceBrowserRef me, const char *inDomain )
+{
+ OSStatus err;
+ SBDomain * domain;
+ SBDomain ** domainPtr;
+ SBDomain * newDomain = NULL;
+
+ for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
+ {
+ if( strcasecmp( domain->name, inDomain ) == 0 ) break;
+ }
+ require_action_quiet( !domain, exit, err = kDuplicateErr );
+
+ err = _SBDomainCreate( inDomain, me, &newDomain );
+ require_noerr_quiet( err, exit );
+
+ if( me->serviceTypeList )
+ {
+ const StringListItem * item;
+
+ for( item = me->serviceTypeList; item; item = item->next )
+ {
+ err = _ServiceBrowserAddServiceType( me, newDomain, item->str, me->ifIndex );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ }
+ else
+ {
+ char * recordName;
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+
+ // Perform PTR meta-query for _services._dns-sd._udp.<domain> to enumerate service types in domain.
+ // See <https://tools.ietf.org/html/rfc6763#section-9>.
+
+ ASPrintF( &recordName, "_services._dns-sd._udp.%s", newDomain->name );
+ require_action( recordName, exit, err = kNoMemoryErr );
+
+ flags = kDNSServiceFlagsShareConnection;
+ if( ( me->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+
+ sb_ulog( kLogLevelTrace, "Starting PTR QueryRecord on interface %d for %s", (int32_t) me->ifIndex, recordName );
+
+ sdRef = newDomain->browser->connection;
+ err = DNSServiceQueryRecord( &sdRef, flags, me->ifIndex, recordName, kDNSServiceType_PTR, kDNSServiceClass_IN,
+ _ServiceBrowserServicesQueryCallback, newDomain );
+ free( recordName );
+ require_noerr( err, exit );
+
+ newDomain->servicesQuery = sdRef;
+ }
+
+ *domainPtr = newDomain;
+ newDomain = NULL;
+ err = kNoErr;
+
+exit:
+ if( newDomain ) _SBDomainFree( newDomain );
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserRemoveDomain
+//===========================================================================================================================
+
+static OSStatus _ServiceBrowserRemoveDomain( ServiceBrowserRef me, const char *inName )
+{
+ OSStatus err;
+ SBDomain * domain;
+ SBDomain ** domainPtr;
+
+ for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
+ {
+ if( strcasecmp( domain->name, inName ) == 0 ) break;
+ }
+
+ if( domain )
+ {
+ *domainPtr = domain->next;
+ _SBDomainFree( domain );
+ err = kNoErr;
+ }
+ else
+ {
+ err = kNotFoundErr;
+ }
+
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserTimerHandler
+//===========================================================================================================================
+
+static void _ServiceBrowserTimerHandler( void *inContext )
+{
+ ServiceBrowserRef const me = (ServiceBrowserRef) inContext;
+
+ _ServiceBrowserStop( me, kNoErr );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserDomainsQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _ServiceBrowserDomainsQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ ServiceBrowserRef const me = (ServiceBrowserRef) inContext;
+ OSStatus err;
+ char domainStr[ kDNSServiceMaxDomainName ];
+
+ Unused( inSDRef );
+ Unused( inClass );
+ Unused( inTTL );
+
+ sb_ulog( kLogLevelTrace, "QueryRecord result: %s on interface %d for %s -> %{du:rdata}%?{end} (error: %#m)",
+ DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, inFullName, inType, inRDataPtr, inRDataLen,
+ !inError, inError );
+
+ require_noerr( inError, exit );
+
+ err = DomainNameToString( inRDataPtr, ( (const uint8_t *) inRDataPtr ) + inRDataLen, domainStr, NULL );
+ require_noerr( err, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = _ServiceBrowserAddDomain( me, domainStr );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = _ServiceBrowserRemoveDomain( me, domainStr );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _ServiceBrowserServicesQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _ServiceBrowserServicesQueryCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ uint16_t inType,
+ uint16_t inClass,
+ uint16_t inRDataLen,
+ const void * inRDataPtr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ SBDomain * const domain = (SBDomain *) inContext;
+ ServiceBrowserRef const me = domain->browser;
+ const uint8_t * src;
+ const uint8_t * end;
+ uint8_t * dst;
+ int i;
+ uint8_t serviceType[ 2 * ( 1 + kDomainLabelLengthMax ) + 1 ];
+ char serviceTypeStr[ kDNSServiceMaxDomainName ];
+
+ Unused( inSDRef );
+ Unused( inTTL );
+ Unused( inClass );
+
+ sb_ulog( kLogLevelTrace, "QueryRecord result: %s on interface %d for %s -> %{du:rdata}%?{end} (error: %#m)",
+ DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, inFullName, inType, inRDataPtr, inRDataLen,
+ !inError, inError );
+
+ require_noerr( inError, exit );
+
+ check( inType == kDNSServiceType_PTR );
+ check( inClass == kDNSServiceClass_IN );
+
+ // The first two labels of the domain name in the RDATA describe a service type.
+ // See <https://tools.ietf.org/html/rfc6763#section-9>.
+
+ src = (const uint8_t *) inRDataPtr;
+ end = src + inRDataLen;
+ dst = serviceType;
+ for( i = 0; i < 2; ++i )
+ {
+ size_t labelLen;
+
+ require_action_quiet( ( end - src ) > 0, exit, err = kUnderrunErr );
+
+ labelLen = *src;
+ require_action_quiet( ( labelLen > 0 ) && ( labelLen <= kDomainLabelLengthMax ), exit, err = kMalformedErr );
+ require_action_quiet( ( (size_t)( end - src ) ) >= ( 1 + labelLen ), exit, err = kUnderrunErr );
+
+ memcpy( dst, src, 1 + labelLen );
+ src += 1 + labelLen;
+ dst += 1 + labelLen;
+ }
+ *dst = 0;
+
+ err = DomainNameToString( serviceType, NULL, serviceTypeStr, NULL );
+ require_noerr( err, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = _ServiceBrowserAddServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = _ServiceBrowserRemoveServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _ServiceBrowserBrowseCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _ServiceBrowserBrowseCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ void * inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ SBServiceBrowse * const browse = (SBServiceBrowse *) inContext;
+ ServiceBrowserRef const me = (ServiceBrowserRef) browse->browser;
+
+ Unused( inSDRef );
+
+ sb_ulog( kLogLevelTrace, "Browse result: %s on interface %d for %s.%s%s%?{end} (error: %#m)",
+ DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, inName, inRegType, inDomain, !inError, inError );
+
+ require_noerr( inError, exit );
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = _ServiceBrowserAddServiceInstance( me, browse, inInterfaceIndex, inName, inRegType, inDomain,
+ UpTicksToMicroseconds( nowTicks - browse->startTicks ) );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = _ServiceBrowserRemoveServiceInstance( me, browse, inName, inInterfaceIndex );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _ServiceBrowserResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _ServiceBrowserResolveCallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inFullName,
+ const char * inHostname,
+ uint16_t inPort,
+ uint16_t inTXTLen,
+ const unsigned char * inTXTPtr,
+ void * inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ SBServiceInstance * const instance = (SBServiceInstance *) inContext;
+ ServiceBrowserRef const me = (ServiceBrowserRef) instance->browser;
+
+ Unused( inSDRef );
+ Unused( inFlags );
+
+ sb_ulog( kLogLevelTrace, "Resolve result on interface %d for %s -> %s:%u %#{txt}%?{end} (error %#m)",
+ (int32_t) inInterfaceIndex, inFullName, inHostname, inPort, inTXTPtr, (size_t) inTXTLen, !inError, inError );
+
+ require_noerr( inError, exit );
+
+ if( !MemEqual( instance->txtPtr, instance->txtLen, inTXTPtr, inTXTLen ) )
+ {
+ FreeNullSafe( instance->txtPtr );
+ instance->txtPtr = _memdup( inTXTPtr, inTXTLen );
+ require_action( instance->txtPtr, exit, err = kNoMemoryErr );
+
+ instance->txtLen = inTXTLen;
+ }
+
+ instance->port = ntohs( inPort );
+
+ if( !instance->hostname || ( strcasecmp( instance->hostname, inHostname ) != 0 ) )
+ {
+ DNSServiceRef sdRef;
+
+ if( !instance->hostname ) instance->resolveTimeUs = UpTicksToMicroseconds( nowTicks - instance->resolveStartTicks );
+
+ err = ReplaceString( &instance->hostname, NULL, inHostname, kSizeCString );
+ require_noerr( err, exit );
+
+ DNSServiceForget( &instance->getAddrInfo );
+ ForgetSBIPAddressList( &instance->ipaddrList );
+
+ sb_ulog( kLogLevelTrace, "Starting GetAddrInfo on interface %d for %s",
+ (int32_t) instance->ifIndex, instance->hostname );
+
+ sdRef = me->connection;
+ instance->gaiStartTicks = UpTicks();
+ err = DNSServiceGetAddrInfo( &sdRef, kDNSServiceFlagsShareConnection, instance->ifIndex,
+ kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, instance->hostname, _ServiceBrowserGAICallback, instance );
+ require_noerr( err, exit );
+
+ instance->getAddrInfo = sdRef;
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _ServiceBrowserGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+ _ServiceBrowserGAICallback(
+ DNSServiceRef inSDRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceErrorType inError,
+ const char * inHostname,
+ const struct sockaddr * inSockAddr,
+ uint32_t inTTL,
+ void * inContext )
+{
+ OSStatus err;
+ const uint64_t nowTicks = UpTicks();
+ SBServiceInstance * const instance = (SBServiceInstance *) inContext;
+ ServiceBrowserRef const me = (ServiceBrowserRef) instance->browser;
+
+ Unused( inSDRef );
+ Unused( inTTL );
+
+ sb_ulog( kLogLevelTrace, "GetAddrInfo result: %s on interface %d for (%s ->) %s -> %##a%?{end} (error: %#m)",
+ DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, instance->fqdn, inHostname, inSockAddr,
+ !inError, inError );
+
+ require_noerr( inError, exit );
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ goto exit;
+ }
+
+ if( inFlags & kDNSServiceFlagsAdd )
+ {
+ err = _ServiceBrowserAddIPAddress( me, instance, inSockAddr,
+ UpTicksToMicroseconds( nowTicks - instance->gaiStartTicks ) );
+ if( err == kDuplicateErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+ else
+ {
+ err = _ServiceBrowserRemoveIPAddress( me, instance, inSockAddr );
+ if( err == kNotFoundErr ) err = kNoErr;
+ require_noerr( err, exit );
+ }
+
+exit:
+ return;
+}
+
+//===========================================================================================================================
+// _ServiceBrowserAddServiceType
+//===========================================================================================================================
+
+static OSStatus
+ _ServiceBrowserAddServiceType(
+ ServiceBrowserRef me,
+ SBDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex )
+{
+ OSStatus err;
+ SBServiceType * type;
+ SBServiceType ** typePtr;
+ SBServiceType * newType = NULL;
+ SBServiceBrowse * browse;
+ SBServiceBrowse ** browsePtr;
+ SBServiceBrowse * newBrowse = NULL;
+ DNSServiceRef sdRef;
+ DNSServiceFlags flags;
+
+ for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
+ {
+ if( strcasecmp( type->name, inName ) == 0 ) break;
+ }
+ if( !type )
+ {
+ err = _SBServiceTypeCreate( inName, &newType );
+ require_noerr_quiet( err, exit );
+
+ type = newType;
+ }
+
+ for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
+ {
+ if( browse->ifIndex == inIfIndex ) break;
+ }
+ require_action_quiet( !browse, exit, err = kDuplicateErr );
+
+ err = _SBServiceBrowseCreate( inIfIndex, me, &newBrowse );
+ require_noerr_quiet( err, exit );
+
+ flags = kDNSServiceFlagsShareConnection;
+ if( ( newBrowse->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+
+ sb_ulog( kLogLevelTrace, "Starting Browse on interface %d for %s%s",
+ (int32_t) newBrowse->ifIndex, type->name, inDomain->name );
+
+ sdRef = me->connection;
+ newBrowse->startTicks = UpTicks();
+ err = DNSServiceBrowse( &sdRef, flags, newBrowse->ifIndex, type->name, inDomain->name, _ServiceBrowserBrowseCallback,
+ newBrowse );
+ require_noerr( err, exit );
+
+ newBrowse->browse = sdRef;
+ *browsePtr = newBrowse;
+ newBrowse = NULL;
+
+ if( newType )
+ {
+ *typePtr = newType;
+ newType = NULL;
+ }
+
+exit:
+ if( newBrowse ) _SBServiceBrowseFree( newBrowse );
+ if( newType ) _SBServiceTypeFree( newType );
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserRemoveServiceType
+//===========================================================================================================================
+
+static OSStatus
+ _ServiceBrowserRemoveServiceType(
+ ServiceBrowserRef me,
+ SBDomain * inDomain,
+ const char * inName,
+ uint32_t inIfIndex )
+{
+ OSStatus err;
+ SBServiceType * type;
+ SBServiceType ** typePtr;
+ SBServiceBrowse * browse;
+ SBServiceBrowse ** browsePtr;
+
+ Unused( me );
+
+ for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
+ {
+ if( strcasecmp( type->name, inName ) == 0 ) break;
+ }
+ require_action_quiet( type, exit, err = kNotFoundErr );
+
+ for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
+ {
+ if( browse->ifIndex == inIfIndex ) break;
+ }
+ require_action_quiet( browse, exit, err = kNotFoundErr );
+
+ *browsePtr = browse->next;
+ _SBServiceBrowseFree( browse );
+ if( !type->browseList )
+ {
+ *typePtr = type->next;
+ _SBServiceTypeFree( type );
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserAddServiceInstance
+//===========================================================================================================================
+
+static OSStatus
+ _ServiceBrowserAddServiceInstance(
+ ServiceBrowserRef me,
+ SBServiceBrowse * inBrowse,
+ uint32_t inIfIndex,
+ const char * inName,
+ const char * inRegType,
+ const char * inDomain,
+ uint64_t inDiscoverTimeUs )
+{
+ OSStatus err;
+ DNSServiceRef sdRef;
+ SBServiceInstance * instance;
+ SBServiceInstance ** instancePtr;
+ SBServiceInstance * newInstance = NULL;
+
+ for( instancePtr = &inBrowse->instanceList; ( instance = *instancePtr ) != NULL; instancePtr = &instance->next )
+ {
+ if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
+ }
+ require_action_quiet( !instance, exit, err = kDuplicateErr );
+
+ err = _SBServiceInstanceCreate( inName, inRegType, inDomain, inIfIndex, inDiscoverTimeUs, me, &newInstance );
+ require_noerr_quiet( err, exit );
+
+ sb_ulog( kLogLevelTrace, "Starting Resolve on interface %d for %s.%s%s",
+ (int32_t) newInstance->ifIndex, inName, inRegType, inDomain );
+
+ sdRef = me->connection;
+ newInstance->resolveStartTicks = UpTicks();
+ err = DNSServiceResolve( &sdRef, kDNSServiceFlagsShareConnection, newInstance->ifIndex, inName, inRegType, inDomain,
+ _ServiceBrowserResolveCallback, newInstance );
+ require_noerr( err, exit );
+
+ newInstance->resolve = sdRef;
+ *instancePtr = newInstance;
+ newInstance = NULL;
+
+exit:
+ if( newInstance ) _SBServiceInstanceFree( newInstance );
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserRemoveServiceInstance
+//===========================================================================================================================
+
+static OSStatus
+ _ServiceBrowserRemoveServiceInstance(
+ ServiceBrowserRef me,
+ SBServiceBrowse * inBrowse,
+ const char * inName,
+ uint32_t inIfIndex )
+{
+ OSStatus err;
+ SBServiceInstance * instance;
+ SBServiceInstance ** ptr;
+
+ Unused( me );
+
+ for( ptr = &inBrowse->instanceList; ( instance = *ptr ) != NULL; ptr = &instance->next )
+ {
+ if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
+ }
+ require_action_quiet( instance, exit, err = kNotFoundErr );
+
+ *ptr = instance->next;
+ _SBServiceInstanceFree( instance );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserAddIPAddress
+//===========================================================================================================================
+
+static OSStatus
+ _ServiceBrowserAddIPAddress(
+ ServiceBrowserRef me,
+ SBServiceInstance * inInstance,
+ const struct sockaddr * inSockAddr,
+ uint64_t inResolveTimeUs )
+{
+ OSStatus err;
+ SBIPAddress * ipaddr;
+ SBIPAddress ** ipaddrPtr;
+ SBIPAddress * newIPAddr = NULL;
+
+ Unused( me );
+
+ if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+ {
+ dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+ err = kTypeErr;
+ goto exit;
+ }
+
+ for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
+ {
+ if( SockAddrCompareAddr( &ipaddr->sip, inSockAddr ) == 0 ) break;
+ }
+ require_action_quiet( !ipaddr, exit, err = kDuplicateErr );
+
+ err = _SBIPAddressCreate( inSockAddr, inResolveTimeUs, &newIPAddr );
+ require_noerr_quiet( err, exit );
+
+ *ipaddrPtr = newIPAddr;
+ newIPAddr = NULL;
+ err = kNoErr;
+
+exit:
+ if( newIPAddr ) _SBIPAddressFree( newIPAddr );
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserRemoveIPAddress
+//===========================================================================================================================
+
+static OSStatus
+ _ServiceBrowserRemoveIPAddress(
+ ServiceBrowserRef me,
+ SBServiceInstance * inInstance,
+ const struct sockaddr * inSockAddr )
+{
+ OSStatus err;
+ SBIPAddress * ipaddr;
+ SBIPAddress ** ipaddrPtr;
+
+ Unused( me );
+
+ for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
+ {
+ if( SockAddrCompareAddr( &ipaddr->sip.sa, inSockAddr ) == 0 ) break;
+ }
+ require_action_quiet( ipaddr, exit, err = kNotFoundErr );
+
+ *ipaddrPtr = ipaddr->next;
+ _SBIPAddressFree( ipaddr );
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ServiceBrowserCreateResults
+//===========================================================================================================================
+
+static OSStatus _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults )
+{
+ OSStatus err;
+ SBDomain * d;
+ SBServiceType * t;
+ SBServiceBrowse * b;
+ SBServiceInstance * i;
+ SBIPAddress * a;
+ ServiceBrowserResultsPrivate * results;
+ SBRDomain ** domainPtr;
+
+ results = (ServiceBrowserResultsPrivate *) calloc( 1, sizeof( *results ) );
+ require_action( results, exit, err = kNoMemoryErr );
+
+ results->refCount = 1;
+
+ domainPtr = &results->domainList;
+ for( d = me->domainList; d; d = d->next )
+ {
+ SBRDomain * domain;
+ SBRServiceType ** typePtr;
+
+ err = _SBRDomainCreate( d->name, &domain );
+ require_noerr_quiet( err, exit );
+ *domainPtr = domain;
+ domainPtr = &domain->next;
+
+ typePtr = &domain->typeList;
+ for( t = d->typeList; t; t = t->next )
+ {
+ SBRServiceType * type;
+ SBRServiceInstance ** instancePtr;
+
+ err = _SBRServiceTypeCreate( t->name, &type );
+ require_noerr_quiet( err, exit );
+ *typePtr = type;
+ typePtr = &type->next;
+
+ instancePtr = &type->instanceList;
+ for( b = t->browseList; b; b = b->next )
+ {
+ for( i = b->instanceList; i; i = i->next )
+ {
+ SBRServiceInstance * instance;
+ SBRIPAddress ** ipaddrPtr;
+
+ err = _SBRServiceInstanceCreate( i->name, i->ifIndex, i->hostname, i->port, i->txtPtr, i->txtLen,
+ i->discoverTimeUs, i->resolveTimeUs, &instance );
+ require_noerr_quiet( err, exit );
+ *instancePtr = instance;
+ instancePtr = &instance->next;
+
+ ipaddrPtr = &instance->ipaddrList;
+ for( a = i->ipaddrList; a; a = a->next )
+ {
+ SBRIPAddress * ipaddr;
+
+ err = _SBRIPAddressCreate( &a->sip.sa, a->resolveTimeUs, &ipaddr );
+ require_noerr_quiet( err, exit );
+
+ *ipaddrPtr = ipaddr;
+ ipaddrPtr = &ipaddr->next;
+ }
+ }
+ }
+ }
+ }
+
+ *outResults = (ServiceBrowserResults *) results;
+ results = NULL;
+ err = kNoErr;
+
+exit:
+ if( results ) ServiceBrowserResultsRelease( (ServiceBrowserResults *) results );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBDomainCreate
+//===========================================================================================================================
+
+static OSStatus _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain )
+{
+ OSStatus err;
+ SBDomain * obj;
+
+ obj = (SBDomain *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ obj->browser = inBrowser;
+
+ *outDomain = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _SBDomainFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBDomainFree
+//===========================================================================================================================
+
+static void _SBDomainFree( SBDomain *inDomain )
+{
+ SBServiceType * type;
+
+ ForgetMem( &inDomain->name );
+ DNSServiceForget( &inDomain->servicesQuery );
+ while( ( type = inDomain->typeList ) != NULL )
+ {
+ inDomain->typeList = type->next;
+ _SBServiceTypeFree( type );
+ }
+ free( inDomain );
+}
+
+//===========================================================================================================================
+// _SBServiceTypeCreate
+//===========================================================================================================================
+
+static OSStatus _SBServiceTypeCreate( const char *inName, SBServiceType **outType )
+{
+ OSStatus err;
+ SBServiceType * obj;
+
+ obj = (SBServiceType *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ *outType = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _SBServiceTypeFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBServiceTypeFree
+//===========================================================================================================================
+
+static void _SBServiceTypeFree( SBServiceType *inType )
+{
+ SBServiceBrowse * browse;
+
+ ForgetMem( &inType->name );
+ while( ( browse = inType->browseList ) != NULL )
+ {
+ inType->browseList = browse->next;
+ _SBServiceBrowseFree( browse );
+ }
+ free( inType );
+}
+
+//===========================================================================================================================
+// _SBServiceBrowseCreate
+//===========================================================================================================================
+
+static OSStatus _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse )
+{
+ OSStatus err;
+ SBServiceBrowse * obj;
+
+ obj = (SBServiceBrowse *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->ifIndex = inIfIndex;
+ obj->browser = inBrowser;
+ *outBrowse = obj;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBServiceBrowseFree
+//===========================================================================================================================
+
+static void _SBServiceBrowseFree( SBServiceBrowse *inBrowse )
+{
+ SBServiceInstance * instance;
+
+ DNSServiceForget( &inBrowse->browse );
+ while( ( instance = inBrowse->instanceList ) != NULL )
+ {
+ inBrowse->instanceList = instance->next;
+ _SBServiceInstanceFree( instance );
+ }
+ free( inBrowse );
+}
+
+//===========================================================================================================================
+// _SBServiceInstanceCreate
+//===========================================================================================================================
+
+static OSStatus
+ _SBServiceInstanceCreate(
+ const char * inName,
+ const char * inType,
+ const char * inDomain,
+ uint32_t inIfIndex,
+ uint64_t inDiscoverTimeUs,
+ ServiceBrowserRef inBrowser,
+ SBServiceInstance ** outInstance )
+{
+ OSStatus err;
+ SBServiceInstance * obj;
+
+ obj = (SBServiceInstance *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ ASPrintF( &obj->fqdn, "%s.%s%s", obj->name, inType, inDomain );
+ require_action( obj->fqdn, exit, err = kNoMemoryErr );
+
+ obj->ifIndex = inIfIndex;
+ obj->discoverTimeUs = inDiscoverTimeUs;
+ obj->browser = inBrowser;
+
+ *outInstance = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _SBServiceInstanceFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBServiceInstanceFree
+//===========================================================================================================================
+
+static void _SBServiceInstanceFree( SBServiceInstance *inInstance )
+{
+ ForgetMem( &inInstance->name );
+ ForgetMem( &inInstance->fqdn );
+ DNSServiceForget( &inInstance->resolve );
+ ForgetMem( &inInstance->hostname );
+ ForgetMem( &inInstance->txtPtr );
+ DNSServiceForget( &inInstance->getAddrInfo );
+ ForgetSBIPAddressList( &inInstance->ipaddrList );
+ free( inInstance );
+}
+
+//===========================================================================================================================
+// _SBIPAddressCreate
+//===========================================================================================================================
+
+static OSStatus _SBIPAddressCreate( const struct sockaddr *inSockAddr, uint64_t inResolveTimeUs, SBIPAddress **outIPAddress )
+{
+ OSStatus err;
+ SBIPAddress * obj;
+
+ obj = (SBIPAddress *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ SockAddrCopy( inSockAddr, &obj->sip );
+ obj->resolveTimeUs = inResolveTimeUs;
+
+ *outIPAddress = obj;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBIPAddressFree
+//===========================================================================================================================
+
+static void _SBIPAddressFree( SBIPAddress *inIPAddress )
+{
+ free( inIPAddress );
+}
+
+//===========================================================================================================================
+// _SBIPAddressFreeList
+//===========================================================================================================================
+
+static void _SBIPAddressFreeList( SBIPAddress *inList )
+{
+ SBIPAddress * ipaddr;
+
+ while( ( ipaddr = inList ) != NULL )
+ {
+ inList = ipaddr->next;
+ _SBIPAddressFree( ipaddr );
+ }
+}
+
+//===========================================================================================================================
+// _SBRDomainCreate
+//===========================================================================================================================
+
+static OSStatus _SBRDomainCreate( const char *inName, SBRDomain **outDomain )
+{
+ OSStatus err;
+ SBRDomain * obj;
+
+ obj = (SBRDomain *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ *outDomain = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _SBRDomainFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBRDomainFree
+//===========================================================================================================================
+
+static void _SBRDomainFree( SBRDomain *inDomain )
+{
+ SBRServiceType * type;
+
+ ForgetMem( &inDomain->name );
+ while( ( type = inDomain->typeList ) != NULL )
+ {
+ inDomain->typeList = type->next;
+ _SBRServiceTypeFree( type );
+ }
+ free( inDomain );
+}
+
+//===========================================================================================================================
+// _SBRServiceTypeCreate
+//===========================================================================================================================
+
+static OSStatus _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType )
+{
+ OSStatus err;
+ SBRServiceType * obj;
+
+ obj = (SBRServiceType *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ *outType = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _SBRServiceTypeFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBRServiceTypeFree
+//===========================================================================================================================
+
+static void _SBRServiceTypeFree( SBRServiceType *inType )
+{
+ SBRServiceInstance * instance;
+
+ ForgetMem( &inType->name );
+ while( ( instance = inType->instanceList ) != NULL )
+ {
+ inType->instanceList = instance->next;
+ _SBRServiceInstanceFree( instance );
+ }
+ free( inType );
+}
+
+//===========================================================================================================================
+// _SBRServiceInstanceCreate
+//===========================================================================================================================
+
+static OSStatus
+ _SBRServiceInstanceCreate(
+ const char * inName,
+ uint32_t inInterfaceIndex,
+ const char * inHostname,
+ uint16_t inPort,
+ const uint8_t * inTXTPtr,
+ size_t inTXTLen,
+ uint64_t inDiscoverTimeUs,
+ uint64_t inResolveTimeUs,
+ SBRServiceInstance ** outInstance )
+{
+ OSStatus err;
+ SBRServiceInstance * obj;
+
+ obj = (SBRServiceInstance *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ obj->name = strdup( inName );
+ require_action( obj->name, exit, err = kNoMemoryErr );
+
+ if( inHostname )
+ {
+ obj->hostname = strdup( inHostname );
+ require_action( obj->hostname, exit, err = kNoMemoryErr );
+ }
+ if( inTXTLen > 0 )
+ {
+ obj->txtPtr = (uint8_t *) _memdup( inTXTPtr, inTXTLen );
+ require_action( obj->txtPtr, exit, err = kNoMemoryErr );
+ obj->txtLen = inTXTLen;
+ }
+ obj->discoverTimeUs = inDiscoverTimeUs;
+ obj->resolveTimeUs = inResolveTimeUs;
+ obj->ifIndex = inInterfaceIndex;
+ obj->port = inPort;
+
+ *outInstance = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if( obj ) _SBRServiceInstanceFree( obj );
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBRServiceInstanceFree
+//===========================================================================================================================
+
+static void _SBRServiceInstanceFree( SBRServiceInstance *inInstance )
+{
+ SBRIPAddress * ipaddr;
+
+ ForgetMem( &inInstance->name );
+ ForgetMem( &inInstance->hostname );
+ ForgetMem( &inInstance->txtPtr );
+ while( ( ipaddr = inInstance->ipaddrList ) != NULL )
+ {
+ inInstance->ipaddrList = ipaddr->next;
+ _SBRIPAddressFree( ipaddr );
+ }
+ free( inInstance );
+}
+
+//===========================================================================================================================
+// _SBRIPAddressCreate
+//===========================================================================================================================
+
+static OSStatus
+ _SBRIPAddressCreate(
+ const struct sockaddr * inSockAddr,
+ uint64_t inResolveTimeUs,
+ SBRIPAddress ** outIPAddress )
+{
+ OSStatus err;
+ SBRIPAddress * obj;
+
+ obj = (SBRIPAddress *) calloc( 1, sizeof( *obj ) );
+ require_action( obj, exit, err = kNoMemoryErr );
+
+ SockAddrCopy( inSockAddr, &obj->sip );
+ obj->resolveTimeUs = inResolveTimeUs;
+
+ *outIPAddress = obj;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _SBRIPAddressFree
+//===========================================================================================================================
+
+static void _SBRIPAddressFree( SBRIPAddress *inIPAddress )
+{
+ free( inIPAddress );
+}
+
+//===========================================================================================================================
+// _SocketWriteAll
+//
+// Note: This was copied from CoreUtils because the SocketWriteAll function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus _SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs )
+{
+ OSStatus err;
+ const uint8_t * src;
+ const uint8_t * end;
+ fd_set writeSet;
+ struct timeval timeout;
+ ssize_t n;
+
+ FD_ZERO( &writeSet );
+ src = (const uint8_t *) inData;
+ end = src + inSize;
+ while( src < end )
+ {
+ FD_SET( inSock, &writeSet );
+ timeout.tv_sec = inTimeoutSecs;
+ timeout.tv_usec = 0;
+ n = select( (int)( inSock + 1 ), NULL, &writeSet, NULL, &timeout );
+ if( n == 0 ) { err = kTimeoutErr; goto exit; }
+ err = map_socket_value_errno( inSock, n > 0, n );
+ require_noerr( err, exit );
+
+ n = send( inSock, (char *) src, (size_t)( end - src ), 0 );
+ err = map_socket_value_errno( inSock, n >= 0, n );
+ if( err == EINTR ) continue;
+ require_noerr( err, exit );
+
+ src += n;
+ }
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ParseIPv4Address
+//
+// Warning: "inBuffer" may be modified even in error cases.
+//
+// Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus _ParseIPv4Address( const char *inStr, uint8_t inBuffer[ 4 ], const char **outStr )
+{
+ OSStatus err;
+ uint8_t * dst;
+ int segments;
+ int sawDigit;
+ int c;
+ int v;
+
+ check( inBuffer );
+ check( outStr );
+
+ dst = inBuffer;
+ *dst = 0;
+ sawDigit = 0;
+ segments = 0;
+ for( ; ( c = *inStr ) != '\0'; ++inStr )
+ {
+ if( isdigit_safe( c ) )
+ {
+ v = ( *dst * 10 ) + ( c - '0' );
+ require_action_quiet( v <= 255, exit, err = kRangeErr );
+ *dst = (uint8_t) v;
+ if( !sawDigit )
+ {
+ ++segments;
+ require_action_quiet( segments <= 4, exit, err = kOverrunErr );
+ sawDigit = 1;
+ }
+ }
+ else if( ( c == '.' ) && sawDigit )
+ {
+ require_action_quiet( segments < 4, exit, err = kMalformedErr );
+ *++dst = 0;
+ sawDigit = 0;
+ }
+ else
+ {
+ break;
+ }
+ }
+ require_action_quiet( segments == 4, exit, err = kUnderrunErr );
+
+ *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _StringToIPv4Address
+//
+// Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus
+ _StringToIPv4Address(
+ const char * inStr,
+ StringToIPAddressFlags inFlags,
+ uint32_t * outIP,
+ int * outPort,
+ uint32_t * outSubnet,
+ uint32_t * outRouter,
+ const char ** outStr )
+{
+ OSStatus err;
+ uint8_t buf[ 4 ];
+ int c;
+ uint32_t ip;
+ int hasPort;
+ int port;
+ int hasPrefix;
+ int prefix;
+ uint32_t subnetMask;
+ uint32_t router;
+
+ require_action( inStr, exit, err = kParamErr );
+
+ // Parse the address-only part of the address (e.g. "1.2.3.4").
+
+ err = _ParseIPv4Address( inStr, buf, &inStr );
+ require_noerr_quiet( err, exit );
+ ip = (uint32_t)( ( buf[ 0 ] << 24 ) | ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ] );
+ c = *inStr;
+
+ // Parse the port (if any).
+
+ hasPort = 0;
+ port = 0;
+ if( c == ':' )
+ {
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
+ require_action_quiet( port <= 65535, exit, err = kRangeErr );
+ hasPort = 1;
+ }
+
+ // Parse the prefix length (if any).
+
+ hasPrefix = 0;
+ prefix = 0;
+ subnetMask = 0;
+ router = 0;
+ if( c == '/' )
+ {
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
+ require_action_quiet( ( prefix >= 0 ) && ( prefix <= 32 ), exit, err = kRangeErr );
+ hasPrefix = 1;
+
+ subnetMask = ( prefix > 0 ) ? ( UINT32_C( 0xFFFFFFFF ) << ( 32 - prefix ) ) : 0;
+ router = ( ip & subnetMask ) | 1;
+ }
+
+ // Return the results. Only fill in port/prefix/router results if the info was found to allow for defaults.
+
+ if( outIP ) *outIP = ip;
+ if( outPort && hasPort ) *outPort = port;
+ if( outSubnet && hasPrefix ) *outSubnet = subnetMask;
+ if( outRouter && hasPrefix ) *outRouter = router;
+ if( outStr ) *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ParseIPv6Address
+//
+// Note: Parsed according to the rules specified in RFC 3513.
+// Warning: "inBuffer" may be modified even in error cases.
+//
+// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus _ParseIPv6Address( const char *inStr, int inAllowV4Mapped, uint8_t inBuffer[ 16 ], const char **outStr )
+{
+ // Table to map uppercase hex characters - '0' to their numeric values.
+ // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
+ static const uint8_t kASCIItoHexTable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
+ OSStatus err;
+ const char * ptr;
+ uint8_t * dst;
+ uint8_t * lim;
+ uint8_t * colonPtr;
+ int c;
+ int sawDigit;
+ unsigned int v;
+ int i;
+ int n;
+
+ // Pre-zero the address to simplify handling of compressed addresses (e.g. "::1").
+
+ for( i = 0; i < 16; ++i ) inBuffer[ i ] = 0;
+
+ // Special case leading :: (e.g. "::1") to simplify processing later.
+
+ if( *inStr == ':' )
+ {
+ ++inStr;
+ require_action_quiet( *inStr == ':', exit, err = kMalformedErr );
+ }
+
+ // Parse the address.
+
+ ptr = inStr;
+ dst = inBuffer;
+ lim = dst + 16;
+ colonPtr = NULL;
+ sawDigit = 0;
+ v = 0;
+ while( ( ( c = *inStr++ ) != '\0' ) && ( c != '%' ) && ( c != '/' ) && ( c != ']' ) )
+ {
+ if( ( c >= 'a' ) && ( c <= 'f' ) ) c -= ( 'a' - 'A' );
+ if( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) )
+ {
+ c -= '0';
+ check( c < (int) countof( kASCIItoHexTable ) );
+ v = ( v << 4 ) | kASCIItoHexTable[ c ];
+ require_action_quiet( v <= 0xFFFF, exit, err = kRangeErr );
+ sawDigit = 1;
+ continue;
+ }
+ if( c == ':' )
+ {
+ ptr = inStr;
+ if( !sawDigit )
+ {
+ require_action_quiet( !colonPtr, exit, err = kMalformedErr );
+ colonPtr = dst;
+ continue;
+ }
+ require_action_quiet( *inStr != '\0', exit, err = kUnderrunErr );
+ require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
+ *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
+ *dst++ = (uint8_t)( v & 0xFF );
+ sawDigit = 0;
+ v = 0;
+ continue;
+ }
+
+ // Handle IPv4-mapped/compatible addresses (e.g. ::FFFF:1.2.3.4).
+
+ if( inAllowV4Mapped && ( c == '.' ) && ( ( dst + 4 ) <= lim ) )
+ {
+ err = _ParseIPv4Address( ptr, dst, &inStr );
+ require_noerr_quiet( err, exit );
+ dst += 4;
+ sawDigit = 0;
+ ++inStr; // Increment because the code below expects the end to be at "inStr - 1".
+ }
+ break;
+ }
+ if( sawDigit )
+ {
+ require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
+ *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
+ *dst++ = (uint8_t)( v & 0xFF );
+ }
+ check( dst <= lim );
+ if( colonPtr )
+ {
+ require_action_quiet( dst < lim, exit, err = kOverrunErr );
+ n = (int)( dst - colonPtr );
+ for( i = 1; i <= n; ++i )
+ {
+ lim[ -i ] = colonPtr[ n - i ];
+ colonPtr[ n - i ] = 0;
+ }
+ dst = lim;
+ }
+ require_action_quiet( dst == lim, exit, err = kUnderrunErr );
+
+ *outStr = inStr - 1;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _ParseIPv6Scope
+//
+// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus _ParseIPv6Scope( const char *inStr, uint32_t *outScope, const char **outStr )
+{
+#if( TARGET_OS_POSIX )
+ OSStatus err;
+ char scopeStr[ 64 ];
+ char * dst;
+ char * lim;
+ int c;
+ uint32_t scope;
+ const char * ptr;
+
+ // Copy into a local NULL-terminated string since that is what if_nametoindex expects.
+
+ dst = scopeStr;
+ lim = dst + ( countof( scopeStr ) - 1 );
+ while( ( ( c = *inStr ) != '\0' ) && ( c != ':' ) && ( c != '/' ) && ( c != ']' ) && ( dst < lim ) )
+ {
+ *dst++ = *inStr++;
+ }
+ *dst = '\0';
+ check( dst <= lim );
+
+ // First try to map as a name and if that fails, treat it as a numeric scope.
+
+ scope = if_nametoindex( scopeStr );
+ if( scope == 0 )
+ {
+ for( ptr = scopeStr; ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr )
+ {
+ scope = ( scope * 10 ) + ( ( (uint8_t) c ) - '0' );
+ }
+ require_action_quiet( c == '\0', exit, err = kMalformedErr );
+ require_action_quiet( ( ptr != scopeStr ) && ( ( (int)( ptr - scopeStr ) ) <= 10 ), exit, err = kMalformedErr );
+ }
+
+ *outScope = scope;
+ *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+#else
+ OSStatus err;
+ uint32_t scope;
+ const char * start;
+ int c;
+
+ scope = 0;
+ for( start = inStr; ( ( c = *inStr ) >= '0' ) && ( c <= '9' ); ++inStr )
+ {
+ scope = ( scope * 10 ) + ( c - '0' );
+ }
+ require_action_quiet( ( inStr != start ) && ( ( (int)( inStr - start ) ) <= 10 ), exit, err = kMalformedErr );
+
+ *outScope = scope;
+ *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+#endif
+}
+
+//===========================================================================================================================
+// _StringToIPv6Address
+//
+// Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus
+ _StringToIPv6Address(
+ const char * inStr,
+ StringToIPAddressFlags inFlags,
+ uint8_t outIPv6[ 16 ],
+ uint32_t * outScope,
+ int * outPort,
+ int * outPrefix,
+ const char ** outStr )
+{
+ OSStatus err;
+ uint8_t ipv6[ 16 ];
+ int c;
+ int hasScope;
+ uint32_t scope;
+ int hasPort;
+ int port;
+ int hasPrefix;
+ int prefix;
+ int hasBracket;
+ int i;
+
+ require_action( inStr, exit, err = kParamErr );
+
+ if( *inStr == '[' ) ++inStr; // Skip a leading bracket for []-wrapped addresses (e.g. "[::1]:80").
+
+ // Parse the address-only part of the address (e.g. "1::1").
+
+ err = _ParseIPv6Address( inStr, !( inFlags & kStringToIPAddressFlagsNoIPv4Mapped ), ipv6, &inStr );
+ require_noerr_quiet( err, exit );
+ c = *inStr;
+
+ // Parse the scope, port, or prefix length.
+
+ hasScope = 0;
+ scope = 0;
+ hasPort = 0;
+ port = 0;
+ hasPrefix = 0;
+ prefix = 0;
+ hasBracket = 0;
+ for( ;; )
+ {
+ if( c == '%' ) // Scope (e.g. "%en0" or "%5")
+ {
+ require_action_quiet( !hasScope, exit, err = kMalformedErr );
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoScope ), exit, err = kUnexpectedErr );
+ ++inStr;
+ err = _ParseIPv6Scope( inStr, &scope, &inStr );
+ require_noerr_quiet( err, exit );
+ hasScope = 1;
+ c = *inStr;
+ }
+ else if( c == ':' ) // Port (e.g. ":80")
+ {
+ require_action_quiet( !hasPort, exit, err = kMalformedErr );
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
+ require_action_quiet( port <= 65535, exit, err = kRangeErr );
+ hasPort = 1;
+ }
+ else if( c == '/' ) // Prefix Length (e.g. "/64")
+ {
+ require_action_quiet( !hasPrefix, exit, err = kMalformedErr );
+ require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
+ while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
+ require_action_quiet( ( prefix >= 0 ) && ( prefix <= 128 ), exit, err = kRangeErr );
+ hasPrefix = 1;
+ }
+ else if( c == ']' )
+ {
+ require_action_quiet( !hasBracket, exit, err = kMalformedErr );
+ hasBracket = 1;
+ c = *( ++inStr );
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // Return the results. Only fill in scope/port/prefix results if the info was found to allow for defaults.
+
+ if( outIPv6 ) for( i = 0; i < 16; ++i ) outIPv6[ i ] = ipv6[ i ];
+ if( outScope && hasScope ) *outScope = scope;
+ if( outPort && hasPort ) *outPort = port;
+ if( outPrefix && hasPrefix ) *outPrefix = prefix;
+ if( outStr ) *outStr = inStr;
+ err = kNoErr;
+
+exit:
+ return( err );
+}
+
+//===========================================================================================================================
+// _StringArray_Free
+//
+// Note: This was copied from CoreUtils because the StringArray_Free function is currently not exported in the framework.
+//===========================================================================================================================
+
+static void _StringArray_Free( char **inArray, size_t inCount )
+{
+ size_t i;
+
+ for( i = 0; i < inCount; ++i )
+ {
+ free( inArray[ i ] );
+ }
+ if( inCount > 0 ) free( inArray );
+}
+
+//===========================================================================================================================
+// _ParseQuotedEscapedString
+//
+// Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static Boolean
+ _ParseQuotedEscapedString(
+ const char * inSrc,
+ const char * inEnd,
+ const char * inDelimiters,
+ char * inBuf,
+ size_t inMaxLen,
+ size_t * outCopiedLen,
+ size_t * outTotalLen,
+ const char ** outSrc )
+{
+ const unsigned char * src;
+ const unsigned char * end;
+ unsigned char * dst;
+ unsigned char * lim;
+ unsigned char c;
+ unsigned char c2;
+ size_t totalLen;
+ Boolean singleQuote;
+ Boolean doubleQuote;
+
+ if( inEnd == NULL ) inEnd = inSrc + strlen( inSrc );
+ src = (const unsigned char *) inSrc;
+ end = (const unsigned char *) inEnd;
+ dst = (unsigned char *) inBuf;
+ lim = dst + inMaxLen;
+ while( ( src < end ) && isspace_safe( *src ) ) ++src; // Skip leading spaces.
+ if( src >= end ) return( false );
+
+ // Parse each argument from the string.
+ //
+ // See <http://resources.mpi-inf.mpg.de/departments/rg1/teaching/unixffb-ss98/quoting-guide.html> for details.
+
+ totalLen = 0;
+ singleQuote = false;
+ doubleQuote = false;
+ while( src < end )
+ {
+ c = *src++;
+ if( singleQuote )
+ {
+ // Single quotes protect everything (even backslashes, newlines, etc.) except single quotes.
+
+ if( c == '\'' )
+ {
+ singleQuote = false;
+ continue;
+ }
+ }
+ else if( doubleQuote )
+ {
+ // Double quotes protect everything except double quotes and backslashes. A backslash can be
+ // used to protect " or \ within double quotes. A backslash-newline pair disappears completely.
+ // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
+ // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
+ // A backslash that does not precede ", \, x, X, or a newline is taken literally.
+
+ if( c == '"' )
+ {
+ doubleQuote = false;
+ continue;
+ }
+ else if( c == '\\' )
+ {
+ if( src < end )
+ {
+ c2 = *src;
+ if( ( c2 == '"' ) || ( c2 == '\\' ) )
+ {
+ ++src;
+ c = c2;
+ }
+ else if( c2 == '\n' )
+ {
+ ++src;
+ continue;
+ }
+ else if( ( c2 == 'x' ) || ( c2 == 'X' ) )
+ {
+ ++src;
+ c = c2;
+ if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
+ {
+ c = HexPairToByte( src );
+ src += 2;
+ }
+ }
+ else if( isoctal_safe( c2 ) )
+ {
+ if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
+ {
+ c = OctalTripleToByte( src );
+ src += 3;
+ }
+ }
+ }
+ }
+ }
+ else if( strchr( inDelimiters, c ) )
+ {
+ break;
+ }
+ else if( c == '\\' )
+ {
+ // A backslash protects the next character, except a newline, x, X and 2 hex bytes or 3 octal bytes.
+ // A backslash followed by a newline disappears completely.
+ // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
+ // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
+
+ if( src < end )
+ {
+ c = *src;
+ if( c == '\n' )
+ {
+ ++src;
+ continue;
+ }
+ else if( ( c == 'x' ) || ( c == 'X' ) )
+ {
+ ++src;
+ if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
+ {
+ c = HexPairToByte( src );
+ src += 2;
+ }
+ }
+ else if( isoctal_safe( c ) )
+ {
+ if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
+ {
+ c = OctalTripleToByte( src );
+ src += 3;
+ }
+ else
+ {
+ ++src;
+ }
+ }
+ else
+ {
+ ++src;
+ }
+ }
+ }
+ else if( c == '\'' )
+ {
+ singleQuote = true;
+ continue;
+ }
+ else if( c == '"' )
+ {
+ doubleQuote = true;
+ continue;
+ }
+
+ if( dst < lim )
+ {
+ if( inBuf ) *dst = c;
+ ++dst;
+ }
+ ++totalLen;
+ }
+
+ if( outCopiedLen ) *outCopiedLen = (size_t)( dst - ( (unsigned char *) inBuf ) );
+ if( outTotalLen ) *outTotalLen = totalLen;
+ if( outSrc ) *outSrc = (const char *) src;
+ return( true );
+}
+
+//===========================================================================================================================
+// _ServerSocketOpenEx2
+//
+// Note: Based on ServerSocketOpenEx() from CoreUtils. Added parameter to not use SO_REUSEPORT.
+//===========================================================================================================================
+
+static OSStatus
+ _ServerSocketOpenEx2(
+ int inFamily,
+ int inType,
+ int inProtocol,
+ const void * inAddr,
+ int inPort,
+ int * outPort,
+ int inRcvBufSize,
+ Boolean inNoPortReuse,
+ SocketRef * outSock )
+{
+ OSStatus err;
+ int port;
+ SocketRef sock;
+ int name;
+ int option;
+ sockaddr_ip sip;
+ socklen_t len;
+
+ port = ( inPort < 0 ) ? -inPort : inPort; // Negated port number means "try this port, but allow dynamic".
+
+ sock = socket( inFamily, inType, inProtocol );
+ err = map_socket_creation_errno( sock );
+ require_noerr_quiet( err, exit );
+
+#if( defined( SO_NOSIGPIPE ) )
+ setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, (socklen_t) sizeof( int ) );
+#endif
+
+ err = SocketMakeNonBlocking( sock );
+ require_noerr( err, exit );
+
+ // Set receive buffer size. This has to be done on the listening socket *before* listen is called because
+ // accept does not return until after the window scale option is exchanged during the 3-way handshake.
+ // Since accept returns a new socket, the only way to use a larger window scale option is to set the buffer
+ // size on the listening socket since SO_RCVBUF is inherited by the accepted socket. See UNPv1e3 Section 7.5.
+
+ err = SocketSetBufferSize( sock, SO_RCVBUF, inRcvBufSize );
+ check_noerr( err );
+
+ // Allow port or address reuse because we may bind separate IPv4 and IPv6 sockets to the same port.
+
+ if( ( inType != SOCK_DGRAM ) || !inNoPortReuse )
+ {
+ option = 1;
+ name = ( inType == SOCK_DGRAM ) ? SO_REUSEPORT : SO_REUSEADDR;
+ err = setsockopt( sock, SOL_SOCKET, name, (char *) &option, (socklen_t) sizeof( option ) );
+ err = map_socket_noerr_errno( sock, err );
+ require_noerr( err, exit );
+ }
+
+ if( inFamily == AF_INET )
+ {
+ // Bind to the port. If it fails, retry with a dynamic port.
+
+ memset( &sip.v4, 0, sizeof( sip.v4 ) );
+ SIN_LEN_SET( &sip.v4 );
+ sip.v4.sin_family = AF_INET;
+ sip.v4.sin_port = htons( (uint16_t) port );
+ sip.v4.sin_addr.s_addr = inAddr ? *( (const uint32_t *) inAddr ) : htonl( INADDR_ANY );
+ err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
+ err = map_socket_noerr_errno( sock, err );
+ if( err && ( inPort < 0 ) )
+ {
+ sip.v4.sin_port = 0;
+ err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
+ err = map_socket_noerr_errno( sock, err );
+ }
+ require_noerr( err, exit );
+ }
+#if( defined( AF_INET6 ) )
+ else if( inFamily == AF_INET6 )
+ {
+ // Restrict this socket to IPv6 only because we're going to use a separate socket for IPv4.
+
+ option = 1;
+ err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, (socklen_t) sizeof( option ) );
+ err = map_socket_noerr_errno( sock, err );
+ require_noerr( err, exit );
+
+ // Bind to the port. If it fails, retry with a dynamic port.
+
+ memset( &sip.v6, 0, sizeof( sip.v6 ) );
+ SIN6_LEN_SET( &sip.v6 );
+ sip.v6.sin6_family = AF_INET6;
+ sip.v6.sin6_port = htons( (uint16_t) port );
+ sip.v6.sin6_addr = inAddr ? *( (const struct in6_addr *) inAddr ) : in6addr_any;
+ err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
+ err = map_socket_noerr_errno( sock, err );
+ if( err && ( inPort < 0 ) )
+ {
+ sip.v6.sin6_port = 0;
+ err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
+ err = map_socket_noerr_errno( sock, err );
+ }
+ require_noerr( err, exit );
+ }
+#endif
+ else
+ {
+ dlogassert( "Unsupported family: %d", inFamily );
+ err = kUnsupportedErr;
+ goto exit;
+ }
+
+ if( inType == SOCK_STREAM )
+ {
+ err = listen( sock, SOMAXCONN );
+ err = map_socket_noerr_errno( sock, err );
+ if( err )
+ {
+ err = listen( sock, 5 );
+ err = map_socket_noerr_errno( sock, err );
+ require_noerr( err, exit );
+ }
+ }
+
+ if( outPort )
+ {
+ len = (socklen_t) sizeof( sip );
+ err = getsockname( sock, &sip.sa, &len );
+ err = map_socket_noerr_errno( sock, err );
+ require_noerr( err, exit );
+
+ *outPort = SockAddrGetPort( &sip );
+ }
+ *outSock = sock;
+ sock = kInvalidSocketRef;
+
+exit:
+ ForgetSocket( &sock );
+ return( err );
+}
+
+//===========================================================================================================================
+// _memdup
+//
+// Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static void * _memdup( const void *inPtr, size_t inLen )
+{
+ void * mem;
+
+ mem = malloc( ( inLen > 0 ) ? inLen : 1 ); // If inLen is 0, use 1 since malloc( 0 ) is not well defined.
+ require( mem, exit );
+ if( inLen > 0 ) memcpy( mem, inPtr, inLen );
+
+exit:
+ return( mem );
+}
+
+//===========================================================================================================================
+// _memicmp
+//
+// Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static int _memicmp( const void *inP1, const void *inP2, size_t inLen )
+{
+ const unsigned char * p1;
+ const unsigned char * e1;
+ const unsigned char * p2;
+ int c1;
+ int c2;
+
+ p1 = (const unsigned char *) inP1;
+ e1 = p1 + inLen;
+ p2 = (const unsigned char *) inP2;
+ while( p1 < e1 )
+ {
+ c1 = *p1++;
+ c2 = *p2++;
+ c1 = tolower( c1 );
+ c2 = tolower( c2 );
+ if( c1 < c2 ) return( -1 );
+ if( c1 > c2 ) return( 1 );
+ }
+ return( 0 );
+}
+
+//===========================================================================================================================
+// _FNV1
+//
+// Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static uint32_t _FNV1( const void *inData, size_t inSize )
+{
+ const uint8_t * src = (const uint8_t *) inData;
+ const uint8_t * const end = src + inSize;
+ uint32_t hash;
+
+ hash = 0x811c9dc5U;
+ while( src != end )
+ {
+ hash *= 0x01000193;
+ hash ^= *src++;
+ }
+ return( hash );
+}
--- /dev/null
+/* dso-transport.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ */
+
+//*************************************************************************************************************
+// Headers
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include <netdb.h> // For gethostbyname()
+#include <sys/socket.h> // For AF_INET, AF_INET6, etc.
+#include <net/if.h> // For IF_NAMESIZE
+#include <netinet/in.h> // For INADDR_NONE
+#include <netinet/tcp.h> // For SOL_TCP, TCP_NOTSENT_LOWAT
+#include <arpa/inet.h> // For inet_addr()
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "dns_sd.h"
+#include "DNSCommon.h"
+#include "mDNSEmbeddedAPI.h"
+#include "dso.h"
+#include "dso-transport.h"
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+// Network Framework only works on MacOS X at the moment, and we need the locking primitives for
+// MacOSX.
+#include "mDNSMacOSX.h"
+#endif
+
+extern mDNS mDNSStorage;
+
+static dso_connect_state_t *dso_connect_states; // DSO connect states that exist.
+static dso_transport_t *dso_transport_states; // DSO transport states that exist.
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static uint32_t dso_transport_serial; // Serial number of next dso_transport_state_t or dso_connect_state_t.
+static dispatch_queue_t dso_dispatch_queue;
+#else
+static void dso_read_callback(TCPSocket *sock, void *context, mDNSBool connection_established,
+ mStatus err);
+#endif
+
+void
+dso_transport_init(void)
+{
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ // It's conceivable that we might want a separate queue, but we don't know yet, so for
+ // now we just use the main dispatch queue, which should be on the main dispatch thread,
+ // which is _NOT_ the kevent thread. So whenever we are doing anything on the dispatch
+ // queue (any completion functions for NW framework) we need to acquire the lock before
+ // we even look at any variables that could be changed by the other thread.
+ dso_dispatch_queue = dispatch_get_main_queue();
+#endif
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static dso_connect_state_t *
+dso_connect_state_find(uint32_t serial)
+{
+ dso_connect_state_t *csp;
+ for (csp = dso_connect_states; csp; csp = csp->next) {
+ if (csp->serial == serial) {
+ return csp;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static void
+dso_transport_finalize(dso_transport_t *transport)
+{
+ dso_transport_t **tp = &dso_transport_states;
+ if (transport->connection != NULL) {
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ nw_connection_cancel(transport->connection);
+ nw_release(transport->connection);
+#else
+ mDNSPlatformTCPCloseConnection(transport->connection);
+#endif
+ transport->connection = NULL;
+ }
+ while (*tp) {
+ if (*tp == transport) {
+ *tp = transport->next;
+ } else {
+ tp = &transport->next;
+ }
+ }
+ free(transport);
+}
+
+// We do all of the finalization for the dso state object and any objects it depends on here in the
+// dso_idle function because it avoids the possibility that some code on the way out to the event loop
+// _after_ the DSO connection has been dropped might still write to the DSO structure or one of the
+// dependent structures and corrupt the heap, or indeed in the unlikely event that this memory was
+// freed and then reallocated before the exit to the event loop, there could be a bad pointer
+// dereference.
+//
+// If there is a finalize function, that function MUST either free its own state that references the
+// DSO state, or else must NULL out the pointer to the DSO state.
+int64_t dso_transport_idle(void *context, int64_t now_in, int64_t next_timer_event)
+{
+ dso_connect_state_t *cs, *cnext;
+ mDNS *m = context;
+ mDNSs32 now = (mDNSs32)now_in;
+ mDNSs32 next_event = (mDNSs32)next_timer_event;
+
+ // Notice if a DSO connection state is active but hasn't seen activity in a while.
+ for (cs = dso_connect_states; cs != NULL; cs = cnext) {
+ cnext = cs->next;
+ if (!cs->connecting && cs->last_event != 0) {
+ mDNSs32 expiry = cs->last_event + 90 * mDNSPlatformOneSecond;
+ if (now - expiry > 0) {
+ cs->last_event = 0;
+ cs->callback(cs->context, NULL, NULL, kDSOEventType_ConnectFailed);
+ if (cs->lookup != NULL) {
+ DNSServiceRef ref = cs->lookup;
+ cs->lookup = NULL;
+ mDNS_DropLockBeforeCallback();
+ DNSServiceRefDeallocate(ref);
+ mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
+ }
+ } else {
+ if (next_timer_event - expiry > 0) {
+ next_timer_event = expiry;
+ }
+ }
+ } else if (!cs->connecting && cs->reconnect_time && now - cs->reconnect_time > 0) {
+ cs->reconnect_time = 0; // Don't try to immediately reconnect if it fails.
+ // If cs->dso->transport is non-null, we're already connected.
+ if (cs->dso && cs->dso->transport == NULL) {
+ cs->callback(cs->context, NULL, NULL, kDSOEventType_ShouldReconnect);
+ }
+ }
+ if (cs->reconnect_time != 0 && next_event - cs->reconnect_time > 0) {
+ next_event = cs->reconnect_time;
+ }
+ }
+
+ return next_event;
+}
+
+// Call to schedule a reconnect at a later time.
+void dso_schedule_reconnect(mDNS *m, dso_connect_state_t *cs, mDNSs32 when)
+{
+ cs->reconnect_time = when * mDNSPlatformOneSecond + m->timenow;
+}
+
+// If a DSO was created by an incoming connection, the creator of the listener can use this function
+// to supply context and a callback for future events.
+void dso_set_callback(dso_state_t *dso, void *context, dso_event_callback_t cb)
+{
+ dso->cb = cb;
+ dso->context = context;
+}
+
+// This is called before writing a DSO message to the output buffer. length is the length of the message.
+// Returns true if we have successfully selected for write (which means that we're under TCP_NOTSENT_LOWAT).
+// Otherwise returns false. It is valid to write even if it returns false, but there is a risk that
+// the write will return EWOULDBLOCK, at which point we'd have to blow away the connection. It is also
+// valid to give up at this point and not write a message; as long as dso_write_finish isn't called, a later
+// call to dso_write_start will overwrite the length that was stored by the previous invocation.
+//
+// The circumstance in which this would occur is that we have filled the kernel's TCP output buffer for this
+// connection all the way up to TCP_NOTSENT_LOWAT, and then we get a query from the Discovery Proxy to which we
+// need to respond. Because TCP_NOTSENT_LOWAT is fairly low, there should be a lot of room in the TCP output
+// buffer for small responses; it would need to be the case that we are getting requests from the proxy at a
+// high rate for us to fill the output buffer to the point where a write of a 12-byte response returns
+// EWOULDBLOCK; in that case, things are so dysfunctional that killing the connection isn't any worse than
+// allowing it to continue.
+
+// An additional note about the motivation for this code: the idea originally was that we'd do scatter/gather
+// I/O here: this lets us write everything out in a single sendmsg() call. This isn't used with the mDNSPlatformTCP
+// code because it doesn't support scatter/gather. Network Framework does, however, and in principle we could
+// write to the descriptor directly if that were really needed.
+
+bool dso_write_start(dso_transport_t *transport, size_t length)
+{
+ // The transport doesn't support messages outside of this range.
+ if (length < 12 || length > 65535) {
+ return false;
+ }
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ uint8_t lenbuf[2];
+
+ if (transport->to_write != NULL) {
+ nw_release(transport->to_write);
+ transport->to_write = NULL;
+ }
+ lenbuf[0] = length >> 8;
+ lenbuf[1] = length & 255;
+ transport->to_write = dispatch_data_create(lenbuf, 2, dso_dispatch_queue,
+ DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+ if (transport->to_write == NULL) {
+ transport->write_failed = true;
+ return false;
+ }
+ transport->bytes_to_write = length + 2;
+
+ // We don't have access to TCP_NOTSENT_LOWAT, so for now we track how many bytes we've written
+ // versus how many bytes that we've written have completed, and if that creeps above MAX_UNSENT_BYTES,
+ // we return false here to indicate that there is congestion.
+ if (transport->unsent_bytes > MAX_UNSENT_BYTES) {
+ return false;
+ } else {
+ return true;
+ }
+#else
+ transport->lenbuf[0] = length >> 8;
+ transport->lenbuf[1] = length & 255;
+
+ transport->to_write[0] = transport->lenbuf;
+ transport->write_lengths[0] = 2;
+ transport->num_to_write = 1;
+
+ return mDNSPlatformTCPWritable(transport->connection);
+#endif // DSO_USES_NETWORK_FRAMEWORK
+}
+
+// Called to finish a write (dso_write_start .. dso_write .. [ dso_write ... ] dso_write_finish). The
+// write must completely finish--if we get a partial write, this means that the connection is stalled, and
+// so we drop it. Since this can call dso_drop, the caller must not reference the DSO state object
+// after this call if the return value is false.
+bool dso_write_finish(dso_transport_t *transport)
+{
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ uint32_t serial = transport->dso->serial;
+ int bytes_to_write = transport->bytes_to_write;
+ transport->bytes_to_write = 0;
+ if (transport->write_failed) {
+ dso_drop(transport->dso);
+ return false;
+ }
+ transport->unsent_bytes += bytes_to_write;
+ nw_connection_send(transport->connection, transport->to_write, NW_CONNECTION_DEFAULT_STREAM_CONTEXT, true,
+ ^(nw_error_t _Nullable error) {
+ dso_state_t *dso;
+ KQueueLock();
+ dso = dso_find_by_serial(serial);
+ if (error != NULL) {
+ LogMsg("dso_write_finish: write failed: %s", strerror(nw_error_get_error_code(error)));
+ if (dso != NULL) {
+ dso_drop(dso);
+ }
+ } else {
+ dso->transport->unsent_bytes -= bytes_to_write;
+ LogMsg("dso_write_finish completion routine: %d bytes written, %d bytes outstanding",
+ bytes_to_write, dso->transport->unsent_bytes);
+ }
+ KQueueUnlock("dso_write_finish completion routine");
+ });
+ nw_release(transport->to_write);
+ transport->to_write = NULL;
+ return true;
+#else
+ ssize_t result, total = 0;
+ int i;
+
+ if (transport->num_to_write > MAX_WRITE_HUNKS) {
+ LogMsg("dso_write_finish: fatal internal programming error: called %d times (more than limit of %d)",
+ transport->num_to_write, MAX_WRITE_HUNKS);
+ dso_drop(transport->dso);
+ return false;
+ }
+
+ // This is our ersatz scatter/gather I/O.
+ for (i = 0; i < transport->num_to_write; i++) {
+ result = mDNSPlatformWriteTCP(transport->connection, (const char *)transport->to_write[i], transport->write_lengths[i]);
+ if (result != transport->write_lengths[i]) {
+ if (result < 0) {
+ LogMsg("dso_write_finish: fatal: mDNSPlatformWrite on %s returned %d", transport->dso->remote_name, errno);
+ } else {
+ LogMsg("dso_write_finish: fatal: mDNSPlatformWrite: short write on %s: %ld < %ld",
+ transport->dso->remote_name, (long)result, (long)total);
+ }
+ dso_drop(transport->dso);
+ return false;
+ }
+ }
+#endif
+ return true;
+}
+
+// This function may only be called after a previous call to dso_write_start; it records the length of and
+// pointer to the write buffer. These buffers must remain valid until dso_write_finish() is called. The
+// caller is responsible for managing the memory they contain. The expected control flow for writing is:
+// dso_write_start(); dso_write(); dso_write(); dso_write(); dso_write_finished(); There should be one or
+// more calls to dso_write; these will ideally be translated into a single scatter/gather sendmsg call (or
+// equivalent) to the kernel.
+void dso_write(dso_transport_t *transport, const uint8_t *buf, size_t length)
+{
+ if (length == 0) {
+ return;
+ }
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ if (transport->write_failed) {
+ return;
+ }
+ dispatch_data_t dpd = dispatch_data_create(buf, length, dso_dispatch_queue,
+ DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+ if (dpd == NULL) {
+ transport->write_failed = true;
+ return;
+ }
+ if (transport->to_write != NULL) {
+ dispatch_data_t dpc = dispatch_data_create_concat(transport->to_write, dpd);
+ dispatch_release(dpd);
+ dispatch_release(transport->to_write);
+ if (dpc == NULL) {
+ transport->to_write = NULL;
+ transport->write_failed = true;
+ return;
+ }
+ transport->to_write = dpc;
+ }
+#else
+ // We'll report this in dso_write_finish();
+ if (transport->num_to_write >= MAX_WRITE_HUNKS) {
+ transport->num_to_write++;
+ return;
+ }
+
+ transport->to_write[transport->num_to_write] = buf;
+ transport->write_lengths[transport->num_to_write] = length;
+ transport->num_to_write++;
+#endif
+}
+
+// Write a DSO message
+int dso_message_write(dso_state_t *dso, dso_message_t *msg, bool disregard_low_water)
+{
+ dso_transport_t *transport = dso->transport;
+ if (transport->connection != NULL) {
+ if (dso_write_start(transport, dso_message_length(msg)) || disregard_low_water) {
+ dso_write(transport, msg->buf, msg->no_copy_bytes_offset);
+ dso_write(transport, msg->no_copy_bytes, msg->no_copy_bytes_len);
+ dso_write(transport, &msg->buf[msg->no_copy_bytes_offset], msg->cur - msg->no_copy_bytes_offset);
+ return dso_write_finish(transport);
+ }
+ }
+ return mStatus_NoMemoryErr;
+}
+
+// Replies to some message we were sent with a response code and no data.
+// This is a convenience function for replies that do not require that a new
+// packet be constructed. It takes advantage of the fact that the message
+// to which this is a reply is still in the input buffer, and modifies that
+// message in place to turn it into a response.
+
+bool dso_send_simple_response(dso_state_t *dso, int rcode, const DNSMessageHeader *header, const char *pres)
+{
+ dso_transport_t *transport = dso->transport;
+ (void)pres; // might want this later.
+ DNSMessageHeader response = *header;
+
+ // Just return the message, with no questions, answers, etc.
+ response.flags.b[1] = (response.flags.b[1] & ~kDNSFlag1_RC_Mask) | rcode;
+ response.flags.b[0] |= kDNSFlag0_QR_Response;
+ response.numQuestions = 0;
+ response.numAnswers = 0;
+ response.numAuthorities = 0;
+ response.numAdditionals = 0;
+
+ // Buffered write back to discovery proxy
+ (void)dso_write_start(transport, 12);
+ dso_write(transport, (uint8_t *)&response, 12);
+ if (!dso_write_finish(transport)) {
+ return false;
+ }
+ return true;
+}
+
+// DSO Message we received has a primary TLV that's not implemented.
+// XXX is this what we're supposed to do here? check draft.
+bool dso_send_not_implemented(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ return dso_send_simple_response(dso, kDNSFlag1_RC_DSOTypeNI, header, "DSOTYPENI");
+}
+
+// Non-DSO message we received is refused.
+bool dso_send_refused(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ return dso_send_simple_response(dso, kDNSFlag1_RC_Refused, header, "REFUSED");
+}
+
+bool dso_send_formerr(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ return dso_send_simple_response(dso, kDNSFlag1_RC_FormErr, header, "FORMERR");
+}
+
+bool dso_send_servfail(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ return dso_send_simple_response(dso, kDNSFlag1_RC_ServFail, header, "SERVFAIL");
+}
+
+bool dso_send_name_error(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ return dso_send_simple_response(dso, kDNSFlag1_RC_NXDomain, header, "NXDOMAIN");
+}
+
+bool dso_send_no_error(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ return dso_send_simple_response(dso, kDNSFlag1_RC_NoErr, header, "NOERROR");
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static void dso_read_message(dso_transport_t *transport, size_t length);
+
+static void dso_read_message_length(dso_transport_t *transport)
+{
+ const uint32_t serial = transport->dso->serial;
+ if (transport->connection == NULL) {
+ LogMsg("dso_read_message_length called with null connection.");
+ return;
+ }
+ nw_connection_receive(transport->connection, 2, 2,
+ ^(dispatch_data_t content, nw_content_context_t __unused context,
+ bool __unused is_complete, nw_error_t error) {
+ dso_state_t *dso;
+ // Don't touch anything or look at anything until we have the lock.
+ KQueueLock();
+ dso = dso_find_by_serial(serial);
+ if (error != NULL) {
+ LogMsg("dso_read_message_length: read failed: %s",
+ strerror(nw_error_get_error_code(error)));
+ fail:
+ if (dso != NULL) {
+ mDNS_Lock(&mDNSStorage);
+ dso_drop(dso);
+ mDNS_Unlock(&mDNSStorage);
+ }
+ } else if (content == NULL) {
+ LogMsg("dso_read_message_length: remote end closed connection.");
+ goto fail;
+ } else {
+ size_t length;
+ const uint8_t *lenbuf;
+ dispatch_data_t map = dispatch_data_create_map(content, (const void **)&lenbuf, &length);
+ if (map == NULL) {
+ LogMsg("dso_read_message_length: map create failed");
+ goto fail;
+ } else if (length != 2) {
+ LogMsg("dso_read_message_length: invalid length = %d", length);
+ goto fail;
+ }
+ length = ((unsigned)(lenbuf[0]) << 8) | ((unsigned)lenbuf[1]);
+ dso_read_message(transport, length);
+ }
+ KQueueUnlock("dso_read_message_length completion routine");
+ });
+}
+
+void dso_read_message(dso_transport_t *transport, size_t length)
+{
+ const uint32_t serial = transport->dso->serial;
+ if (transport->connection == NULL) {
+ LogMsg("dso_read_message called with null connection.");
+ return;
+ }
+ nw_connection_receive(transport->connection, length, length,
+ ^(dispatch_data_t content, nw_content_context_t __unused context,
+ bool __unused is_complete, nw_error_t error) {
+ dso_state_t *dso;
+ // Don't touch anything or look at anything until we have the lock.
+ KQueueLock();
+ dso = dso_find_by_serial(serial);
+ if (error != NULL) {
+ LogMsg("dso_read_message: read failed: %s", strerror(nw_error_get_error_code(error)));
+ fail:
+ if (dso != NULL) {
+ mDNS_Lock(&mDNSStorage);
+ dso_drop(dso);
+ mDNS_Unlock(&mDNSStorage);
+ }
+ } else if (content == NULL) {
+ LogMsg("dso_read_message: remote end closed connection");
+ goto fail;
+ } else {
+ size_t bytes_read;
+ const uint8_t *message;
+ dispatch_data_t map = dispatch_data_create_map(content, (const void **)&message, &bytes_read);
+ if (map == NULL) {
+ LogMsg("dso_read_message_length: map create failed");
+ goto fail;
+ } else if (bytes_read != length) {
+ LogMsg("dso_read_message_length: only %d of %d bytes read", bytes_read, length);
+ goto fail;
+ }
+ // Process the message.
+ mDNS_Lock(&mDNSStorage);
+ dns_message_received(dso, message, length);
+ mDNS_Unlock(&mDNSStorage);
+
+ // Now read the next message length.
+ dso_read_message_length(transport);
+ }
+ KQueueUnlock("dso_read_message completion routine");
+ });
+}
+#else
+// Called whenever there's data available on a DSO connection
+void dso_read_callback(TCPSocket *sock, void *context, mDNSBool connection_established, int err)
+{
+ dso_transport_t *transport = context;
+ dso_state_t *dso;
+ mDNSBool closed = mDNSfalse;
+
+ mDNS_Lock(&mDNSStorage);
+ dso = transport->dso;
+
+ // This shouldn't ever happen.
+ if (err) {
+ LogMsg("dso_read_callback: error %d", err);
+ dso_drop(dso);
+ goto out;
+ }
+
+ // Connection is already established by the time we set this up.
+ if (connection_established) {
+ goto out;
+ }
+
+ // This will be true either if we have never read a message or
+ // if the last thing we did was to finish reading a message and
+ // process it.
+ if (transport->message_length == 0) {
+ transport->need_length = true;
+ transport->inbufp = transport->inbuf;
+ transport->bytes_needed = 2;
+ }
+
+ // Read up to bytes_needed bytes.
+ ssize_t count = mDNSPlatformReadTCP(sock, transport->inbufp, transport->bytes_needed, &closed);
+ // LogMsg("read(%d, %p:%p, %d) -> %d", fd, dso->inbuf, dso->inbufp, dso->bytes_needed, count);
+ if (count < 0) {
+ LogMsg("dso_read_callback: read from %s returned %d", dso->remote_name, errno);
+ dso_drop(dso);
+ goto out;
+ }
+
+ // If we get selected for read and there's nothing to read, the remote end has closed the
+ // connection.
+ if (closed) {
+ LogMsg("dso_read_callback: remote %s closed", dso->remote_name);
+ dso_drop(dso);
+ goto out;
+ }
+
+ transport->inbufp += count;
+ transport->bytes_needed -= count;
+
+ // If we read all the bytes we wanted, do what's next.
+ if (transport->bytes_needed == 0) {
+ // We just finished reading the complete length of a DNS-over-TCP message.
+ if (transport->need_length) {
+ // Get the number of bytes in this DNS message
+ transport->bytes_needed = (((int)transport->inbuf[0]) << 8) | transport->inbuf[1];
+
+ // Under no circumstances can length be zero.
+ if (transport->bytes_needed == 0) {
+ LogMsg("dso_read_callback: %s sent zero-length message.", dso->remote_name);
+ dso_drop(dso);
+ goto out;
+ }
+
+ // The input buffer size is AbsoluteMaxDNSMessageData, which is around 9000 bytes on
+ // big platforms and around 1500 bytes on smaller ones. If the remote end has sent
+ // something larger than that, it's an error from which we can't recover.
+ if (transport->bytes_needed > transport->inbuf_size - 2) {
+ LogMsg("dso_read_callback: fatal: Proxy at %s sent a too-long (%ld bytes) message",
+ dso->remote_name, (long)transport->bytes_needed);
+ dso_drop(dso);
+ goto out;
+ }
+
+ transport->message_length = transport->bytes_needed;
+ transport->inbufp = transport->inbuf + 2;
+ transport->need_length = false;
+
+ // We just finished reading a complete DNS-over-TCP message.
+ } else {
+ dns_message_received(dso, &transport->inbuf[2], transport->message_length);
+ transport->message_length = 0;
+ }
+ }
+out:
+ mDNS_Unlock(&mDNSStorage);
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static dso_transport_t *dso_transport_create(nw_connection_t connection, bool is_server, void *context,
+ int max_outstanding_queries, size_t outbuf_size_in, const char *remote_name,
+ dso_event_callback_t cb, dso_state_t *dso)
+{
+ dso_transport_t *transport;
+ uint8_t *transp;
+ const size_t outbuf_size = outbuf_size_in + 256; // Space for additional TLVs
+
+ // We allocate everything in a single hunk so that we can free it together as well.
+ transp = mallocL("dso_transport_create", (sizeof *transport) + outbuf_size);
+ if (transp == NULL) {
+ transport = NULL;
+ goto out;
+ }
+ // Don't clear the buffers.
+ mDNSPlatformMemZero(transp, sizeof (*transport));
+
+ transport = (dso_transport_t *)transp;
+ transp += sizeof *transport;
+
+ transport->outbuf = transp;
+ transport->outbuf_size = outbuf_size;
+
+ if (dso == NULL) {
+ transport->dso = dso_create(is_server, max_outstanding_queries, remote_name, cb, context, transport);
+ if (transport->dso == NULL) {
+ mDNSPlatformMemFree(transport);
+ transport = NULL;
+ goto out;
+ }
+ } else {
+ transport->dso = dso;
+ }
+ transport->connection = connection;
+ nw_retain(transport->connection);
+ transport->serial = dso_transport_serial++;
+
+ transport->dso->transport = transport;
+ transport->dso->transport_finalize = dso_transport_finalize;
+ transport->next = dso_transport_states;
+ dso_transport_states = transport;
+
+ // Start looking for messages...
+ dso_read_message_length(transport);
+out:
+ return transport;
+}
+#else
+// Create a dso_transport_t structure
+static dso_transport_t *dso_transport_create(TCPSocket *sock, bool is_server, void *context, int max_outstanding_queries,
+ size_t inbuf_size_in, size_t outbuf_size_in, const char *remote_name,
+ dso_event_callback_t cb, dso_state_t *dso)
+{
+ dso_transport_t *transport;
+ size_t outbuf_size;
+ size_t inbuf_size;
+ uint8_t *transp;
+ int status;
+
+ // There's no point in a DSO that doesn't have a callback.
+ if (!cb) {
+ return NULL;
+ }
+
+ outbuf_size = outbuf_size_in + 256; // Space for additional TLVs
+ inbuf_size = inbuf_size_in + 2; // Space for length
+
+ // We allocate everything in a single hunk so that we can free it together as well.
+ transp = mallocL("dso_transport_create", (sizeof *transport) + inbuf_size + outbuf_size);
+ if (transp == NULL) {
+ transport = NULL;
+ goto out;
+ }
+ // Don't clear the buffers.
+ mDNSPlatformMemZero(transp, sizeof (*transport));
+
+ transport = (dso_transport_t *)transp;
+ transp += sizeof *transport;
+
+ transport->inbuf = transp;
+ transport->inbuf_size = inbuf_size;
+ transp += inbuf_size;
+
+ transport->outbuf = transp;
+ transport->outbuf_size = outbuf_size;
+
+ if (dso == NULL) {
+ transport->dso = dso_create(is_server, max_outstanding_queries, remote_name, cb, context, transport);
+ if (transport->dso == NULL) {
+ mDNSPlatformMemFree(transport);
+ transport = NULL;
+ goto out;
+ }
+ } else {
+ transport->dso = dso;
+ }
+ transport->connection = sock;
+
+ status = mDNSPlatformTCPSocketSetCallback(sock, dso_read_callback, transport);
+ if (status != mStatus_NoError) {
+ LogMsg("dso_create: unable to set callback: %d", status);
+ dso_drop(transport->dso);
+ goto out;
+ }
+
+ transport->dso->transport = transport;
+ transport->dso->transport_finalize = dso_transport_finalize;
+ transport->next = dso_transport_states;
+ dso_transport_states = transport;
+out:
+ return transport;
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+// This should all be replaced with Network Framework connection setup.
+dso_connect_state_t *dso_connect_state_create(const char *hostname, mDNSAddr *addr, mDNSIPPort port,
+ int max_outstanding_queries, size_t inbuf_size, size_t outbuf_size,
+ dso_event_callback_t callback, dso_state_t *dso, void *context, const char *detail)
+{
+ int detlen = strlen(detail) + 1;
+ int hostlen = hostname == NULL ? 0 : strlen(hostname) + 1;
+ int len;
+ dso_connect_state_t *cs;
+ char *csp;
+ char nbuf[INET6_ADDRSTRLEN + 1];
+ dso_connect_state_t **states;
+
+ // Enforce Some Minimums (Xxx these are a bit arbitrary, maybe not worth doing?)
+ if (inbuf_size < MaximumRDSize || outbuf_size < 128 || max_outstanding_queries < 1) {
+ return 0;
+ }
+
+ // If we didn't get a hostname, make a presentation form of the IP address to use instead.
+ if (!hostlen) {
+ if (addr != NULL) {
+ if (addr->type == mDNSAddrType_IPv4) {
+ hostname = inet_ntop(AF_INET, &addr->ip.v4, nbuf, sizeof nbuf);
+ } else {
+ hostname = inet_ntop(AF_INET6, &addr->ip.v6, nbuf, sizeof nbuf);
+ }
+ if (hostname != NULL) {
+ hostlen = strlen(nbuf);
+ }
+ }
+ }
+ // If we don't have a printable name, we won't proceed, because this means we don't know
+ // what to connect to.
+ if (!hostlen) {
+ return 0;
+ }
+
+ len = (sizeof *cs) + detlen + hostlen;
+ csp = malloc(len);
+ if (!csp) {
+ return NULL;
+ }
+ cs = (dso_connect_state_t *)csp;
+ memset(cs, 0, sizeof *cs);
+ csp += sizeof *cs;
+
+ cs->detail = csp;
+ memcpy(cs->detail, detail, detlen);
+ csp += detlen;
+ cs->hostname = csp;
+ memcpy(cs->hostname, hostname, hostlen);
+
+ cs->config_port = port;
+ cs->max_outstanding_queries = max_outstanding_queries;
+ cs->outbuf_size = outbuf_size;
+ if (context) {
+ cs->context = context;
+ } // else cs->context = NULL because of memset call above.
+ cs->callback = callback;
+ cs->connect_port.NotAnInteger = 0;
+ cs->dso = dso;
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ cs->serial = dso_transport_serial++;
+#else
+ cs->inbuf_size = inbuf_size;
+#endif
+
+ if (addr) {
+ cs->num_addrs = 1;
+ cs->addresses[0] = *addr;
+ cs->ports[0] = port;
+ }
+ for (states = &dso_connect_states; *states != NULL; states = &(*states)->next)
+ ;
+ *states = cs;
+ return cs;
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+void dso_connect_state_use_tls(dso_connect_state_t *cs)
+{
+ cs->tls_enabled = true;
+}
+#endif
+
+void dso_connect_state_drop(dso_connect_state_t *cs)
+{
+ dso_connect_state_t **states;
+
+ for (states = &dso_connect_states; *states != NULL && *states != cs; states = &(*states)->next)
+ ;
+ if (*states) {
+ *states = cs->next;;
+ } else {
+ LogMsg("dso_connect_state_drop: dropping a connect state that isn't recognized.");
+ }
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ if (cs->connection != NULL) {
+ nw_connection_cancel(cs->connection);
+ nw_release(cs->connection);
+ cs->connection = NULL;
+ }
+#endif
+ mDNSPlatformMemFree(cs);
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static void
+dso_connection_succeeded(dso_connect_state_t *cs)
+{
+ // We got a connection.
+ dso_transport_t *transport =
+ dso_transport_create(cs->connection, false, cs->context, cs->max_outstanding_queries,
+ cs->outbuf_size, cs->hostname, cs->callback, cs->dso);
+ nw_release(cs->connection);
+ cs->connection = NULL;
+ if (transport == NULL) {
+ // If dso_transport_create fails, there's no point in continuing to try to connect to new
+ // addresses
+ LogMsg("dso_connection_succeeded: dso_create failed");
+ // XXX we didn't retain the connection, so we're done when it goes out of scope, right?
+ } else {
+ // Call the "we're connected" callback, which will start things up.
+ transport->dso->cb(cs->context, NULL, transport->dso, kDSOEventType_Connected);
+ }
+
+ cs->last_event = 0;
+
+ // When the connection has succeeded, stop asking questions.
+ if (cs->lookup != NULL) {
+ mDNS *m = &mDNSStorage;
+ DNSServiceRef ref = cs->lookup;
+ cs->lookup = NULL;
+ mDNS_DropLockBeforeCallback();
+ DNSServiceRefDeallocate(ref);
+ mDNS_ReclaimLockAfterCallback();
+ }
+ return;
+}
+
+
+static void dso_connect_internal(dso_connect_state_t *cs)
+{
+ uint32_t serial = cs->serial;
+
+ cs->last_event = mDNSStorage.timenow;
+
+ if (cs->num_addrs <= cs->cur_addr) {
+ if (cs->lookup == NULL) {
+ LogMsg("dso_connect_internal: %s: no more addresses to try", cs->hostname);
+ cs->last_event = 0;
+ cs->callback(cs->context, NULL, NULL, kDSOEventType_ConnectFailed);
+ }
+ // Otherwise, we will get more callbacks when outstanding queries either fail or succeed.
+ return;
+ }
+
+ char addrbuf[INET6_ADDRSTRLEN + 1];
+ char portbuf[6];
+
+ inet_ntop(cs->addresses[cs->cur_addr].type == mDNSAddrType_IPv4 ? AF_INET : AF_INET6,
+ cs->addresses[cs->cur_addr].type == mDNSAddrType_IPv4
+ ? (void *)cs->addresses[cs->cur_addr].ip.v4.b
+ : (void *)cs->addresses[cs->cur_addr].ip.v6.b, addrbuf, sizeof addrbuf);
+ snprintf(portbuf, sizeof portbuf, "%u", ntohs(cs->ports[cs->cur_addr].NotAnInteger));
+ cs->cur_addr++;
+
+ nw_endpoint_t endpoint = nw_endpoint_create_host(addrbuf, portbuf);
+ if (endpoint == NULL) {
+ nomem:
+ LogMsg("dso_connect_internal: no memory creating connection.");
+ return;
+ }
+ nw_parameters_t parameters = NULL;
+ nw_parameters_configure_protocol_block_t configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;
+ if (cs->tls_enabled) {
+ // This sets up a block that's called when we get a TLS connection and want to verify
+ // the cert. Right now we only support opportunistic security, which means we have
+ // no way to validate the cert. Future work: add support for validating the cert
+ // using a TLSA record if one is present.
+ configure_tls = ^(nw_protocol_options_t tls_options) {
+ sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options);
+ sec_protocol_options_set_verify_block(sec_options,
+ ^(sec_protocol_metadata_t __unused metadata,
+ sec_trust_t __unused trust_ref,
+ sec_protocol_verify_complete_t complete) {
+ complete(true);
+ }, dso_dispatch_queue);
+ };
+ }
+ parameters = nw_parameters_create_secure_tcp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION);
+ if (parameters == NULL) {
+ goto nomem;
+ }
+ nw_connection_t connection = nw_connection_create(endpoint, parameters);
+ if (connection == NULL) {
+ goto nomem;
+ }
+ cs->connection = connection;
+
+ LogMsg("dso_connect_internal: Attempting to connect to %s%%%s", addrbuf, portbuf);
+ nw_connection_set_queue(connection, dso_dispatch_queue);
+ nw_connection_set_state_changed_handler(
+ connection, ^(nw_connection_state_t state, nw_error_t error) {
+ dso_connect_state_t *ncs;
+ KQueueLock();
+ ncs = dso_connect_state_find(serial); // Might have been freed.
+ if (ncs == NULL) {
+ LogMsg("forgotten connection is %s.",
+ state == nw_connection_state_cancelled ? "canceled" :
+ state == nw_connection_state_failed ? "failed" :
+ state == nw_connection_state_waiting ? "canceled" :
+ state == nw_connection_state_ready ? "ready" : "unknown");
+ if (state != nw_connection_state_cancelled) {
+ nw_connection_cancel(connection);
+ // Don't need to release it because only NW framework is holding a reference (XXX right?)
+ }
+ } else {
+ if (state == nw_connection_state_waiting) {
+ LogMsg("connection to %#a%%%d is waiting", &ncs->addresses[ncs->cur_addr], ncs->ports[ncs->cur_addr]);
+
+ // XXX the right way to do this is to just let NW Framework wait until we get a connection,
+ // but there are a bunch of problems with that right now. First, will we get "waiting" on
+ // every connection we try? We aren't relying on NW Framework for DNS lookups, so we are
+ // connecting to an IP address, not a host, which means in principle that a later IP address
+ // might be reachable. So we have to stop trying on this one to try that one. Oops.
+ // Once we get NW Framework to use internal calls to resolve names, we can fix this.
+ // Second, maybe we want to switch to polling if this happens. Probably not, but we need
+ // to think this through. So right now we're just using the semantics of regular sockets,
+ // which we /have/ thought through. So in the future we should do this think-through and
+ // try to use NW Framework as it's intended to work rather than as if it were just sockets.
+ ncs->connecting = mDNSfalse;
+ nw_connection_cancel(connection);
+ } else if (state == nw_connection_state_failed) {
+ // We tried to connect, but didn't succeed.
+ LogMsg("dso_connect_internal: failed to connect to %s on %#a%%%d: %s%s",
+ ncs->hostname, &ncs->addresses[ncs->cur_addr], ncs->ports[ncs->cur_addr],
+ strerror(nw_error_get_error_code(error)), ncs->detail);
+ nw_release(ncs->connection);
+ ncs->connection = NULL;
+ ncs->connecting = mDNSfalse;
+ // This will do the work of figuring out if there are more addresses to try.
+ mDNS_Lock(&mDNSStorage);
+ dso_connect_internal(ncs);
+ mDNS_Unlock(&mDNSStorage);
+ } else if (state == nw_connection_state_ready) {
+ ncs->connecting = mDNSfalse;
+ mDNS_Lock(&mDNSStorage);
+ dso_connection_succeeded(ncs);
+ mDNS_Unlock(&mDNSStorage);
+ } else if (state == nw_connection_state_cancelled) {
+ if (ncs->connection) {
+ nw_release(ncs->connection);
+ }
+ ncs->connection = NULL;
+ ncs->connecting = mDNSfalse;
+ // If we get here and cs exists, we are still trying to connect. So do the next step.
+ mDNS_Lock(&mDNSStorage);
+ dso_connect_internal(ncs);
+ mDNS_Unlock(&mDNSStorage);
+ }
+ }
+ KQueueUnlock("dso_connect_internal state change handler");
+ });
+ nw_connection_start(connection);
+ cs->connecting = mDNStrue;
+}
+
+#else
+static void dso_connect_callback(TCPSocket *sock, void *context, mDNSBool connected, int err)
+{
+ dso_connect_state_t *cs = context;
+ char *detail;
+ int status;
+ dso_transport_t *transport;
+ mDNS *m = &mDNSStorage;
+
+ (void)connected;
+ mDNS_Lock(m);
+ detail = cs->detail;
+
+ // If we had a socket open but the connect failed, close it and try the next address, if we have
+ // a next address.
+ if (sock != NULL) {
+ cs->last_event = m->timenow;
+
+ cs->connecting = mDNSfalse;
+ if (err != mStatus_NoError) {
+ mDNSPlatformTCPCloseConnection(sock);
+ LogMsg("dso_connect_callback: connect %p failed (%d)", cs, err);
+ } else {
+ success:
+ // We got a connection.
+ transport = dso_transport_create(sock, false, cs->context, cs->max_outstanding_queries,
+ cs->inbuf_size, cs->outbuf_size, cs->hostname, cs->callback, cs->dso);
+ if (transport == NULL) {
+ // If dso_create fails, there's no point in continuing to try to connect to new
+ // addresses
+ fail:
+ LogMsg("dso_connect_callback: dso_create failed");
+ mDNSPlatformTCPCloseConnection(sock);
+ } else {
+ // Call the "we're connected" callback, which will start things up.
+ transport->dso->cb(cs->context, NULL, transport->dso, kDSOEventType_Connected);
+ }
+
+ cs->last_event = 0;
+
+ // When the connection has succeeded, stop asking questions.
+ if (cs->lookup != NULL) {
+ DNSServiceRef ref = cs->lookup;
+ cs->lookup = NULL;
+ mDNS_DropLockBeforeCallback();
+ DNSServiceRefDeallocate(ref);
+ mDNS_ReclaimLockAfterCallback();
+ }
+ mDNS_Unlock(m);
+ return;
+ }
+ }
+
+ // If there are no addresses to connect to, and there are no queries running, then we can give
+ // up. Otherwise, we wait for one of the queries to deliver an answer.
+ if (cs->num_addrs <= cs->cur_addr) {
+ if (cs->lookup == NULL) {
+ LogMsg("dso_connect_callback: %s: no more addresses to try", cs->hostname);
+ cs->last_event = 0;
+ cs->callback(cs->context, NULL, NULL, kDSOEventType_ConnectFailed);
+ }
+ // Otherwise, we will get more callbacks when outstanding queries either fail or succeed.
+ mDNS_Unlock(m);
+ return;
+ }
+
+ sock = mDNSPlatformTCPSocket(kTCPSocketFlags_Zero, cs->addresses[cs->cur_addr].type, NULL, NULL, mDNSfalse);
+ if (sock == NULL) {
+ LogMsg("drConnectCallback: couldn't get a socket for %s: %s%s",
+ cs->hostname, strerror(errno), detail);
+ goto fail;
+ }
+
+ LogMsg("dso_connect_callback: Attempting to connect to %#a%%%d",
+ &cs->addresses[cs->cur_addr], ntohs(cs->ports[cs->cur_addr].NotAnInteger));
+
+ status = mDNSPlatformTCPConnect(sock, &cs->addresses[cs->cur_addr], cs->ports[cs->cur_addr], NULL,
+ dso_connect_callback, cs);
+ cs->cur_addr++;
+ if (status == mStatus_NoError || status == mStatus_ConnEstablished) {
+ // This can't happen in practice on MacOS; we don't know about all other operating systems,
+ // so we handle it just in case.
+ LogMsg("dso_connect_callback: synchronous connect to %s", cs->hostname);
+ goto success;
+ } else if (status == mStatus_ConnPending) {
+ LogMsg("dso_connect_callback: asynchronous connect to %s", cs->hostname);
+ cs->connecting = mDNStrue;
+ // We should get called back when the connection succeeds or fails.
+ mDNS_Unlock(m);
+ return;
+ }
+ LogMsg("dso_connect_callback: failed to connect to %s on %#a%d: %s%s",
+ cs->hostname, &cs->addresses[cs->cur_addr],
+ ntohs(cs->ports[cs->cur_addr].NotAnInteger), strerror(errno), detail);
+ mDNS_Unlock(m);
+}
+
+static void dso_connect_internal(dso_connect_state_t *cs)
+{
+ dso_connect_callback(NULL, cs, false, mStatus_NoError);
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+static void dso_inaddr_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char *fullname, const struct sockaddr *sa,
+ uint32_t ttl, void *context)
+{
+ dso_connect_state_t *cs = context;
+ char addrbuf[INET6_ADDRSTRLEN + 1];
+ mDNS *m = &mDNSStorage;
+ (void)sdRef;
+
+ cs->last_event = m->timenow;
+ inet_ntop(sa->sa_family, (sa->sa_family == AF_INET
+ ? (void *)&((struct sockaddr_in *)sa)->sin_addr
+ : (void *)&((struct sockaddr_in6 *)sa)->sin6_addr), addrbuf, sizeof addrbuf);
+ LogMsg("dso_inaddr_callback: %s: flags %x index %d error %d fullname %s addr %s ttl %lu",
+ cs->hostname, flags, interfaceIndex, errorCode, fullname, addrbuf, (unsigned long)ttl);
+
+ if (errorCode != mStatus_NoError) {
+ return;
+ }
+
+ if (cs->num_addrs == MAX_DSO_CONNECT_ADDRS) {
+ if (cs->cur_addr > 1) {
+ memmove(&cs->addresses, &cs->addresses[cs->cur_addr],
+ (MAX_DSO_CONNECT_ADDRS - cs->cur_addr) * sizeof cs->addresses[0]);
+ cs->num_addrs -= cs->cur_addr;
+ cs->cur_addr = 0;
+ } else {
+ LogMsg("dso_inaddr_callback: ran out of room for addresses.");
+ return;
+ }
+ }
+
+ if (sa->sa_family == AF_INET) {
+ cs->addresses[cs->num_addrs].type = mDNSAddrType_IPv4;
+ mDNSPlatformMemCopy(&cs->addresses[cs->num_addrs].ip.v4,
+ &((struct sockaddr_in *)sa)->sin_addr, sizeof cs->addresses[cs->num_addrs].ip.v4);
+ } else {
+ cs->addresses[cs->num_addrs].type = mDNSAddrType_IPv6;
+ mDNSPlatformMemCopy(&cs->addresses[cs->num_addrs].ip.v6,
+ &((struct sockaddr_in *)sa)->sin_addr, sizeof cs->addresses[cs->num_addrs].ip.v6);
+ }
+
+ cs->ports[cs->num_addrs] = cs->config_port;
+ cs->num_addrs++;
+ if (!cs->connecting) {
+ LogMsg("dso_inaddr_callback: starting a new connection.");
+ dso_connect_internal(cs);
+ } else {
+ LogMsg("dso_inaddr_callback: connection in progress, deferring new connect until it fails.");
+ }
+}
+
+bool dso_connect(dso_connect_state_t *cs)
+{
+ struct in_addr in;
+ struct in6_addr in6;
+
+ // If the connection state was created with an address, use that rather than hostname.
+ if (cs->num_addrs > 0) {
+ dso_connect_internal(cs);
+ }
+ // Else allow an IPv4 address literal string
+ else if (inet_pton(AF_INET, cs->hostname, &in)) {
+ cs->num_addrs = 1;
+ cs->addresses[0].type = mDNSAddrType_IPv4;
+ cs->addresses[0].ip.v4.NotAnInteger = in.s_addr;
+ cs->ports[0] = cs->config_port;
+ dso_connect_internal(cs);
+ }
+ // ...or an IPv6 address literal string
+ else if (inet_pton(AF_INET6, cs->hostname, &in6)) {
+ cs->num_addrs = 1;
+ cs->addresses[0].type = mDNSAddrType_IPv6;
+ memcpy(&cs->addresses[0].ip.v6, &in6, sizeof in6);
+ cs->ports[0] = cs->config_port;
+ dso_connect_internal(cs);
+ }
+ // ...or else look it up.
+ else {
+ mDNS *m = &mDNSStorage;
+ int err;
+ mDNS_DropLockBeforeCallback();
+ err = DNSServiceGetAddrInfo(&cs->lookup, kDNSServiceFlagsReturnIntermediates,
+ kDNSServiceInterfaceIndexAny, 0, cs->hostname, dso_inaddr_callback, cs);
+
+ mDNS_ReclaimLockAfterCallback();
+ if (err != mStatus_NoError) {
+ LogMsg("dso_connect: inaddr lookup query allocate failed for '%s': %d", cs->hostname, err);
+ return false;
+ }
+ }
+ return true;
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+// We don't need this for DNS Push, so it is being left as future work.
+int dso_listen(dso_connect_state_t * __unused listen_context)
+{
+ return mStatus_UnsupportedErr;
+}
+
+#else
+
+// Called whenever we get a connection on the DNS TCP socket
+static void dso_listen_callback(TCPSocket *sock, mDNSAddr *addr, mDNSIPPort *port,
+ const char *remote_name, void *context)
+{
+ dso_connect_state_t *lc = context;
+ dso_transport_t *transport;
+
+ mDNS_Lock(&mDNSStorage);
+ transport = dso_transport_create(sock, mDNStrue, lc->context, lc->max_outstanding_queries,
+ lc->inbuf_size, lc->outbuf_size, remote_name, lc->callback, NULL);
+ if (transport == NULL) {
+ mDNSPlatformTCPCloseConnection(sock);
+ LogMsg("No memory for new DSO connection from %s", remote_name);
+ goto out;
+ }
+
+ transport->remote_addr = *addr;
+ transport->remote_port = ntohs(port->NotAnInteger);
+ if (transport->dso->cb) {
+ transport->dso->cb(lc->context, 0, transport->dso, kDSOEventType_Connected);
+ }
+ LogMsg("DSO connection from %s", remote_name);
+out:
+ mDNS_Unlock(&mDNSStorage);
+}
+
+// Listen for connections; each time we get a connection, make a new dso_state_t object with the specified
+// parameters and call the callback. Port can be zero to leave it unspecified.
+
+int dso_listen(dso_connect_state_t *listen_context)
+{
+ char addrbuf[INET6_ADDRSTRLEN + 1];
+ mDNSIPPort port;
+ mDNSBool reuseAddr = mDNSfalse;
+
+ if (listen_context->config_port.NotAnInteger) {
+ port = listen_context->config_port;
+ reuseAddr = mDNStrue;
+ }
+ listen_context->listener = mDNSPlatformTCPListen(mDNSAddrType_None, &port, NULL, kTCPSocketFlags_Zero,
+ reuseAddr, 5, dso_listen_callback, listen_context);
+ if (!listen_context->listener) {
+ return mStatus_UnknownErr;
+ }
+ listen_context->connect_port = port;
+ if (listen_context->addresses[0].type == mDNSAddrType_IPv4) {
+ inet_ntop(AF_INET, &listen_context->addresses[0].ip.v4, addrbuf, sizeof addrbuf);
+ } else {
+ inet_ntop(AF_INET6, &listen_context->addresses[0].ip.v6, addrbuf, sizeof addrbuf);
+ }
+
+ LogMsg("DSOListen: Listening on %s%%%d", addrbuf, ntohs(listen_context->connect_port.NotAnInteger));
+ return mStatus_NoError;
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* dso-transport.h
+ *
+ * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DSO_TRANSPORT_H
+#define __DSO_TRANSPORT_H
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+#include <Network/Network.h>
+#endif
+
+// Maximum number of IP addresses that we'll deal with as a result of looking up a name
+// to which to connect.
+#define MAX_DSO_CONNECT_ADDRS 16
+
+// Threshold above which we indicate that a DSO connection isn't writable. This is advisory,
+// but e.g. for a Discovery Relay, if the remote proxy isn't consuming what we are sending, we
+// should start dropping packets on the floor rather than just queueing more and more packets.
+// 60k may actually be too much. This is used when we're using NW Framework, because it doesn't
+// allow us to use TCP_NOTSENT_LOWAT directly.
+#define MAX_UNSENT_BYTES 60000
+
+struct dso_transport {
+ dso_state_t *dso; // DSO state for which this is the transport
+ struct dso_transport *next; // Transport is on list of transports.
+ void *event_context; // I/O event context
+ mDNSAddr remote_addr; // The IP address to which we have connected
+ int remote_port; // The port to which we have connected
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ nw_connection_t connection;
+ dispatch_data_t to_write;
+ size_t bytes_to_write;
+ size_t unsent_bytes;
+ uint32_t serial; // Serial number for locating possibly freed dso_transport_t structs
+ bool write_failed; // This is set if any of the parts of the dso_write process fail
+#else
+ TCPSocket *connection; // Socket connected to Discovery Proxy
+ size_t bytes_needed;
+ size_t message_length; // Length of message we are currently accumulating, if known
+ uint8_t *inbuf; // Buffer for incoming messages.
+ size_t inbuf_size;
+ uint8_t *inbufp; // Current read pointer (may not be in inbuf)
+ bool need_length; // True if we need a 2-byte length
+
+ uint8_t lenbuf[2]; // Buffer for storing the length in a DNS TCP message
+
+#define MAX_WRITE_HUNKS 4 // When writing a DSO message, we need this many separate hunks.
+ const uint8_t *to_write[MAX_WRITE_HUNKS];
+ ssize_t write_lengths[MAX_WRITE_HUNKS];
+ int num_to_write;
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+ uint8_t *outbuf; // Output buffer for building and sending DSO messages
+ size_t outbuf_size;
+};
+
+typedef struct dso_lookup dso_lookup_t;
+struct dso_lookup {
+ dso_lookup_t *next;
+ DNSServiceRef sdref;
+};
+
+typedef struct dso_connect_state dso_connect_state_t;
+struct dso_connect_state {
+ dso_connect_state_t *next;
+ dso_event_callback_t callback;
+ dso_state_t *dso;
+ char *detail;
+ void *context;
+ TCPListener *listener;
+
+ char *hostname;
+ int num_addrs;
+ int cur_addr;
+ mDNSAddr addresses[MAX_DSO_CONNECT_ADDRS];
+ mDNSIPPort ports[MAX_DSO_CONNECT_ADDRS];
+ DNSServiceRef lookup;
+
+ mDNSBool connecting;
+ mDNSIPPort config_port, connect_port;
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+ uint32_t serial;
+ nw_connection_t connection;
+ bool tls_enabled;
+#else
+ size_t inbuf_size;
+#endif
+ size_t outbuf_size;
+ int max_outstanding_queries;
+ mDNSs32 last_event;
+ mDNSs32 reconnect_time;
+};
+
+typedef struct {
+ TCPListener *listener;
+ dso_event_callback_t callback;
+ void *context;
+} dso_listen_context_t;
+
+void dso_transport_init(void);
+mStatus dso_set_connection(dso_state_t *dso, TCPSocket *socket);
+void dso_schedule_reconnect(mDNS *m, dso_connect_state_t *cs, mDNSs32 when);
+void dso_set_callback(dso_state_t *dso, void *context, dso_event_callback_t cb);
+mStatus dso_message_write(dso_state_t *dso, dso_message_t *msg, bool disregard_low_water);
+dso_connect_state_t *dso_connect_state_create(const char *host, mDNSAddr *addr, mDNSIPPort port,
+ int num_outstanding_queries,
+ size_t inbuf_size, size_t outbuf_size,
+ dso_event_callback_t callback,
+ dso_state_t *dso, void *context, const char *detail);
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+void dso_connect_state_use_tls(dso_connect_state_t *cs);
+#endif
+void dso_connect_state_drop(dso_connect_state_t *cs);
+bool dso_connect(dso_connect_state_t *connect_state);
+mStatus dso_listen(dso_connect_state_t *listen_context);
+bool dso_write_start(dso_transport_t *transport, size_t length);
+bool dso_write_finish(dso_transport_t *transport);
+void dso_write(dso_transport_t *transport, const uint8_t *buf, size_t length);
+#endif // __DSO_TRANSPORT_H
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* dso.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ */
+
+//*************************************************************************************************************
+// Headers
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include <netdb.h> // For gethostbyname()
+#include <sys/socket.h> // For AF_INET, AF_INET6, etc.
+#include <net/if.h> // For IF_NAMESIZE
+#include <netinet/in.h> // For INADDR_NONE
+#include <netinet/tcp.h> // For SOL_TCP, TCP_NOTSENT_LOWAT
+#include <arpa/inet.h> // For inet_addr()
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "DNSCommon.h"
+#include "mDNSEmbeddedAPI.h"
+
+#include "dso.h"
+
+#ifdef STANDALONE
+#undef LogMsg
+#define LogMsg(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+#define mDNSRandom(x) arc4random_uniform(x)
+#define mDNSPlatformMemAllocateClear(length) calloc(1, length)
+#endif // STANDALONE
+
+//*************************************************************************************************************
+// Remaining work TODO
+
+// - Add keepalive/inactivity timeout support
+// - Notice if it takes a long time to get a response when establishing a session, and treat that
+// as "DSO not supported."
+// - TLS support
+// - Actually use Network Framework
+
+
+//*************************************************************************************************************
+// Globals
+
+static dso_state_t *dso_connections;
+static dso_state_t *dso_connections_needing_cleanup; // DSO connections that have been shut down but aren't yet freed.
+static uint32_t dso_serial; // Used to uniquely mark DSO objects, incremented once for each dso_state_t created.
+
+dso_state_t *dso_find_by_serial(uint32_t serial)
+{
+ dso_state_t *dsop;
+
+ for (dsop = dso_connections; dsop; dsop = dsop->next) {
+ if (dsop->serial == serial) {
+ return dsop;
+ }
+ }
+ return NULL;
+}
+
+// This function is called either when an error has occurred requiring the a DSO connection be
+// dropped, or else when a connection to a DSO endpoint has been cleanly closed and is ready to be
+// dropped for that reason.
+
+void dso_drop(dso_state_t *dso)
+{
+ dso_state_t *dsop;
+
+ if (dso_connections == dso) {
+ dso_connections = dso->next;
+ } else {
+ for (dsop = dso_connections; dsop != NULL && dsop->next != dso; dsop = dsop->next) {
+ LogMsg("dsop = %p dsop->next = %p dso = %p", dsop, dsop->next, dso);
+ }
+ if (dsop) {
+ dsop->next = dso->next;
+ // If we get to the end of the list without finding dso, it means that it's already
+ // been dropped.
+ } else {
+ return;
+ }
+ }
+ dso->next = dso_connections_needing_cleanup;
+ dso_connections_needing_cleanup = dso;
+}
+
+int64_t dso_idle(void *context, int64_t now, int64_t next_timer_event)
+{
+ dso_state_t *dso, *dnext;
+ dso_activity_t *ap, *anext;
+
+ for (dso = dso_connections_needing_cleanup; dso; dso = dnext) {
+ dnext = dso->next;
+ // Finalize and then free any activities.
+ for (ap = dso->activities; ap; ap = anext) {
+ anext = ap->next;
+ if (ap->finalize) {
+ ap->finalize(ap);
+ }
+ free(ap);
+ }
+ if (dso->transport != NULL && dso->transport_finalize != NULL) {
+ dso->transport_finalize(dso->transport);
+ dso->transport = NULL;
+ }
+ if (dso->cb) {
+ dso_disconnect_context_t disconnect_context;
+ memset(&disconnect_context, 0, sizeof disconnect_context);
+ dso->cb(dso->context, &disconnect_context, dso, kDSOEventType_Disconnected);
+ dso->cb(dso->context, NULL, dso, kDSOEventType_Finalize);
+ } else {
+ free(dso);
+ }
+ }
+ dso_connections_needing_cleanup = NULL;
+
+ // Do keepalives.
+ for (dso = dso_connections; dso; dso = dso->next) {
+ if (dso->inactivity_due == 0) {
+ if (dso->inactivity_timeout != 0) {
+ dso->inactivity_due = now + dso->inactivity_timeout;
+ if (next_timer_event - dso->keepalive_due > 0) {
+ next_timer_event = dso->keepalive_due;
+ }
+ }
+ } else if (now - dso->inactivity_due > 0 && dso->cb != NULL) {
+ dso->cb(dso->context, 0, dso, kDSOEventType_Inactive);
+ }
+ if (dso->keepalive_due != 0 && dso->keepalive_due < now && dso->cb != NULL) {
+ dso_keepalive_context_t kc;
+ memset(&kc, 0, sizeof kc);
+ dso->cb(dso->context, &kc, dso, kDSOEventType_Keepalive);
+ dso->keepalive_due = now + dso->keepalive_interval;
+ if (next_timer_event - dso->keepalive_due > 0) {
+ next_timer_event = dso->keepalive_due;
+ }
+ }
+ }
+ return dso_transport_idle(context, now, next_timer_event);
+}
+
+// Called when something happens that establishes a DSO session.
+static void dso_session_established(dso_state_t *dso)
+{
+ dso->has_session = true;
+ // Set up inactivity timer and keepalive timer...
+}
+
+// Create a dso_state_t structure
+dso_state_t *dso_create(bool is_server, int max_outstanding_queries, const char *remote_name,
+ dso_event_callback_t callback, void *context, dso_transport_t *transport)
+{
+ dso_state_t *dso;
+ int namelen = strlen(remote_name) + 1;
+ int outsize = (sizeof (dso_outstanding_query_state_t)) + max_outstanding_queries * sizeof (dso_outstanding_query_t);
+
+ // We allocate everything in a single hunk so that we can free it together as well.
+ dso = (dso_state_t *) mDNSPlatformMemAllocateClear((sizeof *dso) + outsize + namelen);
+ if (dso == NULL) {
+ goto out;
+ }
+ dso->outstanding_queries = (dso_outstanding_query_state_t *)(dso + 1);
+ dso->outstanding_queries->max_outstanding_queries = max_outstanding_queries;
+
+ dso->remote_name = ((char *)dso->outstanding_queries) + outsize;
+ memcpy(dso->remote_name, remote_name, namelen);
+ dso->remote_name[namelen] = 0;
+
+ dso->cb = callback;
+ dso->context = context;
+ dso->transport = transport;
+ dso->is_server = is_server;
+ dso->serial = dso_serial++;
+
+ dso->next = dso_connections;
+ dso_connections = dso;
+out:
+ return dso;
+}
+
+// Start building a TLV in an outgoing dso message.
+void dso_start_tlv(dso_message_t *state, int opcode)
+{
+ // Make sure there's room for the length and the TLV opcode.
+ if (state->cur + 4 >= state->max) {
+ LogMsg("dso_start_tlv called when no space in output buffer!");
+ assert(0);
+ }
+
+ // We need to not yet have a TLV.
+ if (state->building_tlv) {
+ LogMsg("dso_start_tlv called while already building a TLV!");
+ assert(0);
+ }
+ state->building_tlv = true;
+ state->tlv_len = 0;
+
+ // Set up the TLV header.
+ state->buf[state->cur] = opcode >> 8;
+ state->buf[state->cur + 1] = opcode & 255;
+ state->tlv_len_offset = state->cur + 2;
+ state->cur += 4;
+}
+
+// Add some bytes to a TLV that's being built, but don't copy them--just remember the
+// pointer to the buffer. This is used so that when we have a message to forward, we
+// don't copy it into the output buffer--we just use scatter/gather I/O.
+void dso_add_tlv_bytes_no_copy(dso_message_t *state, const uint8_t *bytes, size_t len)
+{
+ if (!state->building_tlv) {
+ LogMsg("add_tlv_bytes called when not building a TLV!");
+ assert(0);
+ }
+ if (state->no_copy_bytes_len) {
+ LogMsg("add_tlv_bytesNoCopy called twice on the same DSO message.");
+ assert(0);
+ }
+ state->no_copy_bytes_len = len;
+ state->no_copy_bytes = bytes;
+ state->no_copy_bytes_offset = state->cur;
+ state->tlv_len += len;
+}
+
+// Add some bytes to a TLV that's being built.
+void dso_add_tlv_bytes(dso_message_t *state, const uint8_t *bytes, size_t len)
+{
+ if (!state->building_tlv) {
+ LogMsg("add_tlv_bytes called when not building a TLV!");
+ assert(0);
+ }
+ if (state->cur + len > state->max) {
+ LogMsg("add_tlv_bytes called with no room in output buffer.");
+ assert(0);
+ }
+ memcpy(&state->buf[state->cur], bytes, len);
+ state->cur += len;
+ state->tlv_len += len;
+}
+
+// Add a single byte to a TLV that's being built.
+void dso_add_tlv_byte(dso_message_t *state, uint8_t byte)
+{
+ if (!state->building_tlv) {
+ LogMsg("dso_add_tlv_byte called when not building a TLV!");
+ assert(0);
+ }
+ if (state->cur + 1 > state->max) {
+ LogMsg("dso_add_tlv_byte called with no room in output buffer.");
+ assert(0);
+ }
+ state->buf[state->cur++] = byte;
+ state->tlv_len++;
+}
+
+// Add an uint16_t to a TLV that's being built.
+void dso_add_tlv_u16(dso_message_t *state, uint16_t u16)
+{
+ if (!state->building_tlv) {
+ LogMsg("dso_add_tlv_u16 called when not building a TLV!");
+ assert(0);
+ }
+ if ((state->cur + sizeof u16) > state->max) {
+ LogMsg("dso_add_tlv_u16 called with no room in output buffer.");
+ assert(0);
+ }
+ state->buf[state->cur++] = u16 >> 8;
+ state->buf[state->cur++] = u16 & 255;
+ state->tlv_len += 2;
+}
+
+// Add an uint32_t to a TLV that's being built.
+void dso_add_tlv_u32(dso_message_t *state, uint32_t u32)
+{
+ if (!state->building_tlv) {
+ LogMsg("dso_add_tlv_u32 called when not building a TLV!");
+ assert(0);
+ }
+ if ((state->cur + sizeof u32) > state->max) {
+ LogMsg("dso_add_tlv_u32 called with no room in output buffer.");
+ assert(0);
+ }
+ state->buf[state->cur++] = u32 >> 24;
+ state->buf[state->cur++] = (u32 >> 16) & 255;
+ state->buf[state->cur++] = (u32 >> 8) & 255;
+ state->buf[state->cur++] = u32 & 255;
+ state->tlv_len += 4;
+}
+
+// Finish building a TLV.
+void dso_finish_tlv(dso_message_t *state)
+{
+ if (!state->building_tlv) {
+ LogMsg("dso_finish_tlv called when not building a TLV!");
+ assert(0);
+ }
+
+ // A TLV can't be longer than this.
+ if (state->tlv_len > 65535) {
+ LogMsg("dso_finish_tlv was given more than 65535 bytes of TLV payload!");
+ assert(0);
+ }
+ state->buf[state->tlv_len_offset] = state->tlv_len >> 8;
+ state->buf[state->tlv_len_offset + 1] = state->tlv_len & 255;
+ state->tlv_len = 0;
+ state->building_tlv = false;
+}
+
+dso_activity_t *dso_find_activity(dso_state_t *dso, const char *name, const char *activity_type, void *context)
+{
+ dso_activity_t *activity;
+
+ // If we haven't been given something to search for, don't search.
+ if (name == NULL && context == NULL) {
+ return NULL;
+ }
+
+ // An activity can be identified by name or context, but if name is present, that's what identifies it.
+ for (activity = dso->activities; activity; activity = activity->next) {
+ if (activity->activity_type == activity_type && ((activity->name == NULL || name == NULL|| !strcmp(activity->name, name)) &&
+ (context == NULL && context == activity->context))) {
+ return activity;
+ }
+ }
+ return NULL;
+}
+
+// Make an activity structure to hang off the DSO.
+dso_activity_t *dso_add_activity(dso_state_t *dso, const char *name, const char *activity_type,
+ void *context, void (*finalize)(dso_activity_t *))
+{
+ size_t namelen = name ? strlen(name) + 1 : 0;
+ size_t len;
+ dso_activity_t *activity;
+ void *ap;
+
+ // Shouldn't add an activity that's already been added.
+ activity = dso_find_activity(dso, name, activity_type, context);
+ if (activity != NULL) {
+ LogMsg("dso_add_activity: activity %s%s%p added twice.", name ? name : "", name ? " " : "", context);
+ return NULL;
+ }
+
+ len = namelen + sizeof *activity;
+ ap = mDNSPlatformMemAllocateClear(len);
+ if (ap == NULL) {
+ return NULL;
+ }
+ activity = (dso_activity_t *)ap;
+ ap = (char *)ap + sizeof *activity;
+
+ // Activities can be identified either by name or by context
+ if (namelen) {
+ activity->name = ap;
+ memcpy(activity->name, name, namelen);
+ } else {
+ activity->name = NULL;
+ }
+ activity->context = context;
+
+ // Activity type is expected to be a string constant; all activities of the same type must
+ // reference the same constant, not different constants with the same contents.
+ activity->activity_type = activity_type;
+ activity->finalize = finalize;
+
+ // Retain this activity on the list.
+ activity->next = dso->activities;
+ dso->activities = activity;
+ return activity;
+}
+
+void dso_drop_activity(dso_state_t *dso, dso_activity_t *activity)
+{
+ dso_activity_t **app = &dso->activities;
+ bool matched = false;
+
+ // Remove this activity from the list.
+ while (*app) {
+ if (*app == activity) {
+ *app = activity->next;
+ matched = true;
+ } else {
+ app = &((*app)->next);
+ }
+ }
+
+ // If an activity that's not on the DSO list is passed here, it's an internal consistency
+ // error that probably indicates something is corrupted.
+ if (!matched) {
+ LogMsg("dso_drop_activity: FATAL: activity that's not on the list has been dropped!");
+ assert(0);
+ }
+
+ activity->finalize(activity);
+ free(activity);
+}
+
+void dso_ignore_response(dso_state_t *dso, void *context)
+{
+ dso_outstanding_query_state_t *midState = dso->outstanding_queries;
+ int i;
+ for (i = 0; i < midState->max_outstanding_queries; i++) {
+ // The query is still be outstanding, and we want to know it when it comes back, but we forget the context,
+ // which presumably is a reference to something that's going away.
+ if (midState->queries[i].context == context) {
+ midState->queries[i].context = NULL;
+ }
+ }
+}
+
+bool dso_make_message(dso_message_t *state, uint8_t *outbuf, size_t outbuf_size,
+ dso_state_t *dso, bool unidirectional, void *callback_state)
+{
+ DNSMessageHeader *msg_header;
+ dso_outstanding_query_state_t *midState = dso->outstanding_queries;
+
+ memset(state, 0, sizeof *state);
+ state->buf = outbuf;
+ state->max = outbuf_size;
+
+ // We need space for the TCP message length plus the DNS header.
+ if (state->max < sizeof *msg_header) {
+ LogMsg("dso_make_message: called without enough buffer space to store a DNS header!");
+ assert(0);
+ }
+
+ // This buffer should be 16-bit aligned.
+ msg_header = (DNSMessageHeader *)state->buf;
+
+ // The DNS header for a DSO message is mostly zeroes
+ memset(msg_header, 0, sizeof *msg_header);
+ msg_header->flags.b[0] = kDNSFlag0_QR_Query | kDNSFlag0_OP_DSO;
+
+ // Servers can't send DSO messages until there's a DSO session.
+ if (dso->is_server && !dso->has_session) {
+ LogMsg("dso_make_message: FATAL: server attempting to make a DSO message with no session!");
+ assert(0);
+ }
+
+ // Response-requiring messages need to have a message ID.
+ if (!unidirectional) {
+ bool msg_id_ok = true;
+ uint16_t message_id;
+ int looping = 0;
+ int i, avail = -1;
+
+ // If we don't have room for another outstanding message, the caller should try
+ // again later.
+ if (midState->outstanding_query_count == midState->max_outstanding_queries) {
+ return false;
+ }
+ // Generate a random message ID. This doesn't really need to be cryptographically sound
+ // (right?) because we're encrypting the whole data stream in TLS.
+ do {
+ // This would be a surprising fluke, but let's not get killed by it.
+ if (looping++ > 1000) {
+ return false;
+ }
+ message_id = mDNSRandom(65536);
+ msg_id_ok = true;
+ if (message_id == 0) {
+ msg_id_ok = false;
+ } else {
+ for (i = 0; i < midState->max_outstanding_queries; i++) {
+ if (midState->queries[i].id == 0 && avail == -1) {
+ avail = i;
+ } else if (midState->queries[i].id == message_id) {
+ msg_id_ok = false;
+ }
+ }
+ }
+ } while (!msg_id_ok);
+ midState->queries[avail].id = message_id;
+ midState->queries[avail].context = callback_state;
+ midState->outstanding_query_count++;
+ msg_header->id.NotAnInteger = message_id;
+ state->outstanding_query_number = avail;
+ } else {
+ // Clients aren't allowed to send unidirectional messages until there's a session.
+ if (!dso->has_session) {
+ LogMsg("dso_make_message: FATAL: client making a DSO unidirectional message with no session!");
+ assert(0);
+ }
+ state->outstanding_query_number = -1;
+ }
+
+ state->cur = sizeof *msg_header;
+ return true;
+}
+
+size_t dso_message_length(dso_message_t *state)
+{
+ return state->cur + state->no_copy_bytes_len;
+}
+
+void dso_retry_delay(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ dso_disconnect_context_t context;
+ if (dso->cb) {
+ memset(&context, 0, sizeof context);
+ if (dso->primary.length != 4) {
+ LogMsg("Invalid DSO Retry Delay length %d from %s", dso->primary.length, dso->remote_name);
+ dso_send_formerr(dso, header);
+ return;
+ }
+ memcpy(&context, dso->primary.payload, dso->primary.length);
+ context.reconnect_delay = ntohl(context.reconnect_delay);
+ dso->cb(dso->context, &context, dso, kDSOEventType_RetryDelay);
+ }
+}
+
+void dso_keepalive(dso_state_t *dso, const DNSMessageHeader *header)
+{
+ dso_keepalive_context_t context;
+ memset(&context, 0, sizeof context);
+ if (dso->primary.length != 8) {
+ LogMsg("Invalid DSO Keepalive length %d from %s", dso->primary.length, dso->remote_name);
+ dso_send_formerr(dso, header);
+ return;
+ }
+ memcpy(&context, dso->primary.payload, dso->primary.length);
+ context.inactivity_timeout = ntohl(context.inactivity_timeout);
+ context.keepalive_interval = ntohl(context.keepalive_interval);
+ if (dso->is_server) {
+ if (dso->cb) {
+ if (dso->keepalive_interval < context.keepalive_interval) {
+ context.keepalive_interval = dso->keepalive_interval;
+ }
+ if (dso->inactivity_timeout < context.inactivity_timeout) {
+ context.inactivity_timeout = dso->inactivity_timeout;
+ }
+ dso->cb(dso->context, &context, dso, kDSOEventType_KeepaliveRcvd);
+ }
+ } else {
+ if (dso->keepalive_interval > context.keepalive_interval) {
+ dso->keepalive_interval = context.keepalive_interval;
+ }
+ if (dso->inactivity_timeout > context.inactivity_timeout) {
+ dso->inactivity_timeout = context.inactivity_timeout;
+ }
+ }
+}
+
+// We received a DSO message; validate it, parse it and, if implemented, dispatch it.
+void dso_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length)
+{
+ int i;
+ size_t offset;
+ const DNSMessageHeader *header = (const DNSMessageHeader *)message;
+ int response = (header->flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Response;
+ dso_query_receive_context_t qcontext;
+
+ if (message_length < 12) {
+ LogMsg("dso_message_received: response too short: %ld bytes", (long)message_length);
+ dso_drop(dso);
+ goto out;
+ }
+
+ // See if we have sent a message for which a response is expected.
+ if (response) {
+ bool expected = false;
+
+ // A zero ID on a response is not permitted.
+ if (header->id.NotAnInteger == 0) {
+ LogMsg("dso_message_received: response with id==0 received from %s", dso->remote_name);
+ dso_drop(dso);
+ goto out;
+ }
+ // It's possible for a DSO response to contain no TLVs, but if that's the case, the length
+ // should always be twelve.
+ if (message_length < 16 && message_length != 12) {
+ LogMsg("dso_message_received: response with bogus length==%ld received from %s", (long)message_length, dso->remote_name);
+ dso_drop(dso);
+ goto out;
+ }
+ for (i = 0; i < dso->outstanding_queries->max_outstanding_queries; i++) {
+ if (dso->outstanding_queries->queries[i].id == header->id.NotAnInteger) {
+ qcontext.query_context = dso->outstanding_queries->queries[i].context;
+ qcontext.rcode = header->flags.b[1] & kDNSFlag1_RC_Mask;
+
+ // If we are a client, and we just got an acknowledgment, a session has been established.
+ if (!dso->is_server && !dso->has_session && (header->flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr) {
+ dso_session_established(dso);
+ }
+ dso->outstanding_queries->queries[i].id = 0;
+ dso->outstanding_queries->queries[i].context = 0;
+ dso->outstanding_queries->outstanding_query_count--;
+ if (dso->outstanding_queries->outstanding_query_count < 0) {
+ LogMsg("dso_message_receive: programming error: outstanding_query_count went negative.");
+ assert(0);
+ }
+ // If there were no TLVs, we don't need to parse them.
+ expected = true;
+ if (message_length == 12) {
+ dso->primary.opcode = 0;
+ dso->primary.length = 0;
+ dso->num_additls = 0;
+ }
+ break;
+ }
+ }
+
+ // This is fatal because we've received a response to a message we didn't send, so
+ // it's not just that we don't understand what was sent.
+ if (!expected) {
+ LogMsg("dso_message_received: fatal: %s sent %ld byte message, QR=1", dso->remote_name, (long)message_length);
+ dso_drop(dso);
+ goto out;
+ }
+ }
+
+ // Make sure that the DNS header is okay (QDCOUNT, ANCOUNT, NSCOUNT and ARCOUNT are all zero)
+ for (i = 0; i < 4; i++) {
+ if (message[4 + i * 2] != 0 || message[4 + i * 2 + 1] != 0) {
+ LogMsg("dso_message_received: fatal: %s sent %ld byte DSO message, %s is nonzero",
+ dso->remote_name, (long)message_length,
+ (i == 0 ? "QDCOUNT" : (i == 1 ? "ANCOUNT" : ( i == 2 ? "NSCOUNT" : "ARCOUNT"))));
+ dso_drop(dso);
+ goto out;
+ }
+ }
+
+ // Check that there is space for there to be a primary TLV
+ if (message_length < 16 && message_length != 12) {
+ LogMsg("dso_message_received: fatal: %s sent short (%ld byte) DSO message",
+ dso->remote_name, (long)message_length);
+
+ // Short messages are a fatal error. XXX check DSO document
+ dso_drop(dso);
+ goto out;
+ }
+
+ // If we are a server, and we don't have a session, and this is a message, then we have now established a session.
+ if (!dso->has_session && dso->is_server && !response) {
+ dso_session_established(dso);
+ }
+
+ // If a DSO session isn't yet established, make sure the message is a request (if is_server) or a
+ // response (if not).
+ if (!dso->has_session && ((dso->is_server && response) || (!dso->is_server && !response))) {
+ LogMsg("dso_message_received: received a %s with no established session from %s",
+ response ? "response" : "request", dso->remote_name);
+ dso_drop(dso);
+ }
+
+ // Get the primary TLV and count how many TLVs there are in total
+ offset = 12;
+ while (offset < message_length) {
+ // Get the TLV opcode
+ int opcode = (((unsigned)message[offset]) << 8) + message[offset + 1];
+ // And the length
+ size_t length = (((unsigned)message[offset + 2]) << 8) + message[offset + 3];
+
+ // Is there room for the contents of this TLV?
+ if (length + offset > message_length) {
+ LogMsg("dso_message_received: fatal: %s: TLV (%d %ld) extends past end (%ld)",
+ dso->remote_name, opcode, (long)length, (long)message_length);
+
+ // Short messages are a fatal error. XXX check DSO document
+ dso_drop(dso);
+ goto out;
+ }
+
+ // Is this the primary TLV?
+ if (offset == 12) {
+ dso->primary.opcode = opcode;
+ dso->primary.length = length;
+ dso->primary.payload = &message[offset + 4];
+ dso->num_additls = 0;
+ } else {
+ if (dso->num_additls < MAX_ADDITLS) {
+ dso->additl[dso->num_additls].opcode = opcode;
+ dso->additl[dso->num_additls].length = length;
+ dso->additl[dso->num_additls].payload = &message[offset + 4];
+ dso->num_additls++;
+ } else {
+ // XXX MAX_ADDITLS should be enough for all possible additional TLVs, so this
+ // XXX should never happen; if it does, maybe it's a fatal error.
+ LogMsg("dso_message_received: %s: ignoring additional TLV (%d %ld) in excess of %d",
+ dso->remote_name, opcode, (long)length, MAX_ADDITLS);
+ }
+ }
+ offset += 4 + length;
+ }
+
+ // Call the callback with the message or response
+ if (dso->cb) {
+ if (message_length != 12 && dso->primary.opcode == kDSOType_Keepalive) {
+ dso_keepalive(dso, header);
+ } else if (message_length != 12 && dso->primary.opcode == kDSOType_RetryDelay) {
+ dso_retry_delay(dso, header);
+ } else {
+ if (response) {
+ dso->cb(dso->context, &qcontext, dso, kDSOEventType_DSOResponse);
+ } else {
+ dso->cb(dso->context, header, dso, kDSOEventType_DSOMessage);
+ }
+ }
+ }
+out:
+ ;
+}
+
+// This code is currently assuming that we won't get a DNS message, but that's not true. Fix.
+void dns_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length)
+{
+ DNSMessageHeader *header;
+ int opcode, response;
+
+ // We can safely assume that the header is 16-bit aligned.
+ header = (DNSMessageHeader *)message;
+ opcode = header->flags.b[0] & kDNSFlag0_OP_Mask;
+ response = (header->flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Response;
+
+ // Validate the length of the DNS message.
+ if (message_length < 12) {
+ LogMsg("dns_message_received: fatal: %s sent short (%ld byte) message",
+ dso->remote_name, (long)message_length);
+
+ // Short messages are a fatal error.
+ dso_drop(dso);
+ return;
+ }
+
+ // This is not correct for the general case.
+ if (opcode != kDNSFlag0_OP_DSO) {
+ LogMsg("dns_message_received: %s sent %ld byte %s, QTYPE=%d",
+ dso->remote_name, (long)message_length, (response ? "response" : "request"), opcode);
+ if (dso->cb) {
+ dso->cb(dso->context, header, dso,
+ response ? kDSOEventType_DNSMessage : kDSOEventType_DNSResponse);
+ }
+ } else {
+ dso_message_received(dso, message, message_length);
+ }
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* dso.h
+ *
+ * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DSO_H
+#define __DSO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// Maximum number of additional TLVs we support in a DSO message.
+#define MAX_ADDITLS 10
+
+typedef enum {
+ kDSOType_Keepalive = 1,
+ kDSOType_RetryDelay = 2,
+ kDSOType_EncryptionPadding = 3,
+ kDSOType_DNSPushSubscribe = 0x40,
+ kDSOType_DNSPushUpdate = 0x41,
+ kDSOType_DNSPushUnsubscribe = 0x42,
+ kDSOType_DNSPushReconfirm = 0x43,
+ kDSOType_mDNSLinkRequest = 0xF901,
+ kDSOType_mDNSLinkDiscontinue = 0xF902,
+ kDSOType_mDNSMessage = 0xF903,
+ kDSOType_LinkIdentifier = 0xF904,
+ kDSOType_L2SourceAddress = 0xF905,
+ kDSOType_IPSourceAddress = 0xF906,
+ kDSOType_mDNSReportLinkChanges = 0xF907,
+ kDSOType_mDNSStopLinkChanges = 0xF908,
+ kDSOType_mDNSLinkAvailable = 0xF900,
+ kDSOType_mDNSLinkUnavailable = 0xF90a,
+ kDSOType_LinkPrefix = 0xf90b
+} dso_message_types_t;
+
+// When a DSO message arrives, or one that was sent is acknowledged, or the state of the DSO connection
+// changes, we need to call the user of the DSO connection.
+typedef enum {
+ kDSOEventType_DNSMessage, // A DNS message that is not a DSO message
+ kDSOEventType_DNSResponse, // A DNS response that is not a DSO response
+ kDSOEventType_DSOMessage, // DSOState.primary and DSOState.additl will contain the message TLVs;
+ // header will contain the DNS header
+ kDSOEventType_Finalize, // The DSO connection to the other DSO endpoint has terminated and we are
+ // in the idle loop.
+ kDSOEventType_DSOResponse, // DSOState.primary and DSOState.additl contain any TLVs in the response;
+ // header contains the DNS header
+ kDSOEventType_Connected, // We succeeded in making a connection
+ kDSOEventType_ConnectFailed, // We failed to get a connection
+ kDSOEventType_Disconnected, // We were connected, but have disconnected or been disconnected
+ kDSOEventType_ShouldReconnect, // We are disconnected, and a scheduled reconnect timer has gone off.
+ // Recipient is responsible for reconnecting, or deciding not to.
+ kDSOEventType_Inactive, // We went inactive and the inactivity timeout expired, so it's time to drop the connection.
+ kDSOEventType_Keepalive, // It's time to send a keepalive message, here are the values to send
+ kDSOEventType_KeepaliveRcvd, // We just received a keepalive from a client, here are the values.
+ kDSOEventType_RetryDelay // We got a RetryDelay from the server. Have to shut down.
+} dso_event_type_t;
+
+typedef struct dso_outstanding_query {
+ uint16_t id;
+ void *context;
+} dso_outstanding_query_t;
+
+typedef struct dso_outstanding_query_state {
+ int outstanding_query_count;
+ int max_outstanding_queries;
+ dso_outstanding_query_t queries[0];
+} dso_outstanding_query_state_t;
+
+typedef struct dso_query_receive_context {
+ void *query_context;
+ uint16_t rcode;
+} dso_query_receive_context_t;
+
+typedef struct dso_disconnect_context {
+ uint32_t reconnect_delay;
+} dso_disconnect_context_t;
+
+typedef struct dso_keepalive_context {
+ uint32_t inactivity_timeout;
+ uint32_t keepalive_interval;
+} dso_keepalive_context_t;
+
+// Structure to represent received DSO TLVs
+typedef struct dsotlv {
+ uint16_t opcode;
+ uint16_t length;
+ const uint8_t *payload;
+} dso_tlv_t;
+
+// DSO message under construction
+typedef struct dso_message {
+ uint8_t *buf; // The buffer in which we are constructing the message
+ size_t max; // Size of the buffer
+ size_t cur; // Current position in the buffer
+ bool building_tlv; // True if we have started and not finished building a TLV
+ int outstanding_query_number; // Number of the outstanding query state entry for this message, or -1
+ size_t tlv_len; // Current length of the TLV we are building.
+ size_t tlv_len_offset; // Where to store the length of the current TLV when finished.
+ const uint8_t *no_copy_bytes; // One TLV can have data that isn't copied into the buffer
+ size_t no_copy_bytes_len; // Length of that data, if any.
+ size_t no_copy_bytes_offset; // Where in the buffer the data should be interposed.
+} dso_message_t;
+
+// Record of ongoing activity
+typedef struct dso_activity dso_activity_t;
+struct dso_activity {
+ dso_activity_t *next;
+ void (*finalize)(dso_activity_t *activity);
+ const char *activity_type; // Name of the activity type, must be the same pointer for all activities of a type.
+ void *context; // Activity implementation's context (if any).
+ char *name; // Name of the individual activity
+};
+
+typedef struct dso_transport dso_transport_t;
+typedef struct dso_state dso_state_t;
+typedef int64_t event_time_t;
+
+typedef void (*dso_event_callback_t)(void *context, const void *header,
+ dso_state_t *dso, dso_event_type_t eventType);
+typedef void (*dso_transport_finalize_t)(dso_transport_t *transport);
+
+// DNS Stateless Operations state
+struct dso_state {
+ dso_state_t *next;
+ void *context; // The context of the next layer up (e.g., a Discovery Proxy)
+ dso_event_callback_t cb; // Called when an event happens
+
+ // Transport state; handled separately for reusability
+ dso_transport_t *transport; // The transport (e.g., dso-transport.c or other).
+ dso_transport_finalize_t transport_finalize;
+
+ uint32_t serial; // Unique serial number which can be used after the DSO has been dropped.
+ bool is_server; // True if the endpoint represented by this DSO state is a server
+ // (according to the DSO spec)
+ bool has_session; // True if DSO session establishment has happened for this DSO endpoint
+ event_time_t response_awaited; // If we are waiting for a session-establishing response, when it's
+ // expected; otherwise zero.
+ uint32_t keepalive_interval; // Time between keepalives (to be sent, on client, expected, on server)
+ uint32_t inactivity_timeout; // Session can't be inactive more than this amount of time.
+ event_time_t keepalive_due; // When the next keepalive is due (to be received or sent)
+ event_time_t inactivity_due; // When next activity has to happen for connection to remain active
+ dso_activity_t *activities; // Outstanding DSO activities.
+
+ dso_tlv_t primary; // Primary TLV for current message
+ dso_tlv_t additl[MAX_ADDITLS]; // Additional TLVs
+ int num_additls; // Number of additional TLVs in this message
+
+ char *remote_name;
+
+ dso_outstanding_query_state_t *outstanding_queries;
+};
+
+// Provided by dso.c
+dso_state_t *dso_create(bool is_server, int max_outstanding_queries, const char *remote_name,
+ dso_event_callback_t callback, void *context, dso_transport_t *transport);
+dso_state_t *dso_find_by_serial(uint32_t serial);
+void dso_drop(dso_state_t *dso);
+int64_t dso_idle(void *context, int64_t now, int64_t next_timer_event);
+void dso_release(dso_state_t **dsop);
+void dso_start_tlv(dso_message_t *state, int opcode);
+void dso_add_tlv_bytes(dso_message_t *state, const uint8_t *bytes, size_t len);
+void dso_add_tlv_bytes_no_copy(dso_message_t *state, const uint8_t *bytes, size_t len);
+void dso_add_tlv_byte(dso_message_t *state, uint8_t byte);
+void dso_add_tlv_u16(dso_message_t *state, uint16_t u16);
+void dso_add_tlv_u32(dso_message_t *state, uint32_t u32);
+void dso_finish_tlv(dso_message_t *state);
+dso_activity_t *dso_find_activity(dso_state_t *dso, const char *name, const char *activity_type, void *context);
+dso_activity_t *dso_add_activity(dso_state_t *dso, const char *name, const char *activity_type,
+ void *context, void (*finalize)(dso_activity_t *));
+void dso_drop_activity(dso_state_t *dso, dso_activity_t *activity);
+void dso_ignore_response(dso_state_t *dso, void *context);
+bool dso_make_message(dso_message_t *state, uint8_t *outbuf, size_t outbuf_size,
+ dso_state_t *dso, bool unidirectional, void *callback_state);
+size_t dso_message_length(dso_message_t *state);
+void dso_retry_delay(dso_state_t *dso, const DNSMessageHeader *header);
+void dso_keepalive(dso_state_t *dso, const DNSMessageHeader *header);
+void dso_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length);
+void dns_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length);
+
+// Provided by DSO transport implementation for use by dso.c:
+int64_t dso_transport_idle(void *context, int64_t now, int64_t next_timer_event);
+bool dso_send_simple_response(dso_state_t *dso, int rcode, const DNSMessageHeader *header, const char *pres);
+bool dso_send_not_implemented(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_refused(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_formerr(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_servfail(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_name_error(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_no_error(dso_state_t *dso, const DNSMessageHeader *header);
+#endif // !defined(__DSO_H)
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
#
-# Top level makefile for Build & Integration.
+# Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+#
+# Top level makefile for Build & Integration (B&I).
#
-# This file is used to facilitate checking the mDNSResponder project
-# directly out of CVS and submitting to B&I at Apple.
+# This file is used to facilitate checking the mDNSResponder project directly from git and submitting to B&I at Apple.
#
-# The various platform directories contain makefiles or projects
-# specific to that platform.
+# The various platform directories contain makefiles or projects specific to that platform.
#
# B&I builds must respect the following target:
# install:
include $(MAKEFILEPATH)/pb_makefiles/platform.make
-MVERS = "mDNSResponder-878.270.2"
+MVERS = "mDNSResponder-1096.0.2"
VER =
ifneq ($(strip $(GCC_VERSION)),)
endif
echo "VER = $(VER)"
+projectdir := $(SRCROOT)/mDNSMacOSX
+buildsettings := OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)
+
+.PHONY: install installSome installEmpty installExtras SystemLibraries installhdrs installapi installsrc java clean
+
+# B&I install build targets
+#
+# For the mDNSResponder build alias, the make target used by B&I depends on the platform:
+#
+# Platform Make Target
+# -------- -----------
+# osx install
+# ios installSome
+# atv installSome
+# watch installSome
+#
+# For the mDNSResponderSystemLibraries and mDNSResponderSystemLibraries_sim build aliases, B&I uses the SystemLibraries
+# target for all platforms.
+
+install:
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Services' $(VER)
+else
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) $(VER)
+endif
+
installSome:
-ifneq ($(findstring iphoneos, $(shell echo '$(SDKROOT)' | tr '[:upper:]' '[:lower:]')),)
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some\ iOS $(VER)
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Services' $(VER)
else
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some $(VER)
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) $(VER)
endif
-SystemLibraries:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
+installEmpty:
+ mkdir -p $(DSTROOT)/AppleInternal
-install:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) $(VER)
+installExtras:
+ifeq ($(RC_PROJECT_COMPILATION_PLATFORM), osx)
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Extras-macOS' $(VER)
+else ifeq ($(RC_PROJECT_COMPILATION_PLATFORM), ios)
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Extras-iOS' $(VER)
+else
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Extras' $(VER)
+endif
-installsrc:
- ditto . "$(SRCROOT)"
+SystemLibraries:
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target SystemLibraries $(VER)
+
+# B&I installhdrs build targets
installhdrs::
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER)
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target dns_services $(VER)
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+ cd '$(projectdir)'; xcodebuild installhdrs $(buildsettings) -target 'Build Services' $(VER)
+else ifneq ($(findstring SystemLibraries,$(RC_ProjectName)),)
+ cd '$(projectdir)'; xcodebuild installhdrs $(buildsettings) -target SystemLibraries $(VER)
+endif
+
+# B&I installapi build targets
installapi:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installapi OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibrariesDynamic $(VER)
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+ cd '$(projectdir)'; xcodebuild installapi $(buildsettings) -target 'Build Services' $(VER)
+else ifneq ($(findstring SystemLibraries,$(RC_ProjectName)),)
+ cd '$(projectdir)'; xcodebuild installapi $(buildsettings) -target SystemLibrariesDynamic $(VER)
+endif
+
+# Misc. targets
+
+installsrc:
+ ditto . '$(SRCROOT)'
+ rm -rf '$(SRCROOT)/mDNSWindows' '$(SRCROOT)/Clients/FirefoxExtension'
java:
- cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target libjdns_sd.jnilib $(VER)
+ cd '$(projectdir)'; xcodebuild install $(buildsettings) -target libjdns_sd.jnilib $(VER)
clean::
echo clean
layer to send and receive the multicast UDP packets to do the actual work.
Apple currently provides "Platform Support" layers for Mac OS 9, Mac OS X,
-Microsoft Windows, VxWorks, and for POSIX platforms like Linux, Solaris,
-FreeBSD, etc.
+Microsoft Windows, and for POSIX platforms like Linux, Solaris, FreeBSD,
+etc.
Note: Developers writing applications for OS X do not need to incorporate
this code into their applications, since OS X provides a system service to
--- /dev/null
+SRPCFLAGS = -O0 -g -Wall -Werror -DSTANDALONE -I../mDNSCore -I/usr/local/include -I. -I../mDNSShared -I../DSO -MMD -MF .depfile-${notdir $<}
+LINKOPTS = -lmbedcrypto
+
+BUILDDIR = build
+OBJDIR = objects
+
+all: setup $(BUILDDIR)/srp-simple $(BUILDDIR)/srp-gw $(BUILDDIR)/keydump $(BUILDDIR)/dnssd-proxy
+
+# 'setup' sets up the build directory structure the way we want
+setup:
+ @if test ! -d $(OBJDIR) ; then mkdir -p $(OBJDIR) ; fi
+ @if test ! -d $(BUILDDIR) ; then mkdir -p $(BUILDDIR) ; fi
+
+# clean removes targets and objects
+clean:
+ @if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi
+ @if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+
+SIGNOBJS = $(OBJDIR)/sign-mbedtls.o
+SIMPLEOBJS = $(OBJDIR)/towire.o $(SIGNOBJS)
+DSOOBJS = $(OBJDIR)/dso.o
+MDNSOBJS = $(OBJDIR)/dnssd_clientstub.o $(OBJDIR)/dnssd_ipc.o
+VERIFYOBJS = $(OBJDIR)/verify-mbedtls.o
+FROMWIREOBJS = $(OBJDIR)/fromwire.o $(VERIFYOBJS)
+IOOBJS = $(OBJDIR)/ioloop.o
+
+$(BUILDDIR)/dnssd-proxy: $(OBJDIR)/dnssd-proxy.o $(SIMPLEOBJS) $(DSOOBJS) $(MDNSOBJS) $(FROMWIREOBJS) $(IOOBJS)
+ $(CC) -o $@ $+ $(LINKOPTS)
+
+$(BUILDDIR)/srp-simple: $(OBJDIR)/srp-simple.o $(SIMPLEOBJS)
+ $(CC) -o $@ $+ $(LINKOPTS)
+
+$(BUILDDIR)/srp-gw: $(OBJDIR)/srp-gw.o $(SIMPLEOBJS) $(FROMWIREOBJS) $(IOOBJS)
+ $(CC) -o $@ $+ $(LINKOPTS)
+
+$(BUILDDIR)/keydump: $(OBJDIR)/keydump.o $(SIMPLEOBJS) $(FROMWIREOBJS)
+ $(CC) -o $@ $+ $(LINKOPTS)
+
+$(OBJDIR)/dso.o: ../DSO/dso.c
+ $(CC) -o $@ $(SRPCFLAGS) -c -I. -I../mDNSShared $<
+
+$(OBJDIR)/dnssd_clientstub.o: ../mDNSShared/dnssd_clientstub.c
+ $(CC) -o $@ $(SRPCFLAGS) -c -I. -I../mDNSShared $<
+
+$(OBJDIR)/dnssd_ipc.o: ../mDNSShared/dnssd_ipc.c
+ $(CC) -o $@ $(SRPCFLAGS) -c -I. -I../mDNSShared $<
+
+$(OBJDIR)/%.o: %.c
+ $(CC) -o $@ $(SRPCFLAGS) -c $<
+
+-include .depfile-dnssd-proxy.c
+-include .depfile-fromwire.c
+-include .depfile-ioloop.c
+-include .depfile-keydump.c
+-include .depfile-sign-mbedtls.c
+-include .depfile-srp-gw.c
+-include .depfile-srp-simple.c
+-include .depfile-towire.c
+-include .depfile-verify-mbedtls.c
+-include .depfile-dso.c
--- /dev/null
+/* dns-msg.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Lightweight framework for generating, sending, and unpacking DNS messages.
+ * Definitions...
+ */
+
+#ifndef __DNS_MSG_H
+#define __DNS_MSG_H
+
+#ifndef DNS_MAX_UDP_PAYLOAD
+#define DNS_MAX_UDP_PAYLOAD 1410
+#endif
+
+#define DNS_HEADER_SIZE 12
+#define DNS_DATA_SIZE (DNS_MAX_UDP_PAYLOAD - DNS_HEADER_SIZE)
+#define DNS_MAX_POINTER ((2 << 14) - 1)
+#define DNS_MAX_LABEL_SIZE 63
+#define DNS_MAX_NAME_SIZE 255
+#define DNS_MAX_NAME_SIZE_ESCAPED 1009
+
+typedef struct dns_wire dns_wire_t;
+struct dns_wire {
+ uint16_t id;
+ uint16_t bitfield;
+ uint16_t qdcount;
+ uint16_t ancount;
+ uint16_t nscount;
+ uint16_t arcount;
+ uint8_t data[DNS_DATA_SIZE];
+};
+
+typedef struct dns_towire_state dns_towire_state_t;
+struct dns_towire_state {
+ dns_wire_t *NULLABLE message;
+ uint8_t *NONNULL p;
+ uint8_t *NONNULL lim;
+ uint8_t *NULLABLE p_rdlength;
+ uint8_t *NULLABLE p_opt;
+ int error;
+};
+
+typedef struct dns_transaction dns_transaction_t;
+struct dns_transaction {
+ dns_transaction_t *NULLABLE next;
+ dns_towire_state_t towire;
+ dns_wire_t *NULLABLE response;
+ int response_length;
+ int sock;
+};
+
+typedef struct dns_name_pointer dns_name_pointer_t;
+struct dns_name_pointer {
+ uint8_t *NONNULL message_start;
+ uint8_t *NONNULL name_start;
+ int num_labels;
+ int length;
+};
+
+typedef void (*dns_response_callback_t)(dns_transaction_t *NONNULL txn);
+
+typedef struct dns_label dns_label_t;
+typedef dns_label_t dns_name_t;
+struct dns_label {
+ dns_label_t *NULLABLE next;
+ uint8_t len;
+ char data[DNS_MAX_LABEL_SIZE];
+};
+
+typedef struct dns_txt_element dns_txt_element_t;
+struct dns_txt_element {
+ dns_txt_element_t *NULLABLE next;
+ uint8_t len;
+ char data[0];
+};
+
+typedef struct dns_rdata_unparsed dns_rdata_unparsed_t;
+struct dns_rdata_unparsed {
+ uint8_t *NULLABLE data;
+ uint16_t len;
+};
+
+typedef struct dns_rdata_single_name dns_rdata_ptr_t;
+typedef struct dns_rdata_single_name dns_rdata_cname_t;
+struct dns_rdata_single_name {
+ dns_label_t *NONNULL name;
+};
+
+typedef struct dns_rdata_a dns_rdata_a_t;
+struct dns_rdata_a {
+ struct in_addr *NONNULL addrs;
+ int num;
+};
+
+typedef struct dns_rdata_aaaa dns_rdata_aaaa_t;
+struct dns_rdata_aaaa {
+ struct in6_addr *NONNULL addrs;
+ int num;
+} aaaa;
+
+typedef struct dns_rdata_srv dns_rdata_srv_t;
+struct dns_rdata_srv {
+ dns_label_t *NONNULL name;
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+} srv;
+
+typedef struct dns_rdata_sig dns_rdata_sig_t;
+struct dns_rdata_sig {
+ uint16_t type;
+ uint8_t algorithm;
+ uint8_t label;
+ uint32_t rrttl;
+ uint32_t expiry;
+ uint32_t inception;
+ uint16_t key_tag;
+ dns_label_t *NONNULL signer;
+ int start;
+ int len;
+ uint8_t *NONNULL signature;
+} sig;
+
+typedef struct dns_rdata_key dns_rdata_key_t;
+struct dns_rdata_key {
+ uint16_t flags;
+ uint8_t protocol;
+ uint8_t algorithm;
+ int len;
+ uint8_t *NONNULL key;
+} key;
+
+typedef struct dns_rr dns_rr_t;
+struct dns_rr {
+ dns_label_t *NONNULL name;
+ uint16_t type;
+ uint16_t qclass;
+ uint32_t ttl;
+ union {
+ dns_rdata_unparsed_t unparsed;
+ dns_rdata_ptr_t ptr;
+ dns_rdata_cname_t cname;
+ dns_rdata_a_t a;
+ dns_rdata_aaaa_t aaaa;
+ dns_rdata_srv_t srv;
+ dns_txt_element_t *NONNULL txt;
+ dns_rdata_sig_t sig;
+ dns_rdata_key_t key;
+ } data;
+};
+
+typedef struct dns_edns0 dns_edns0_t;
+struct dns_edns0 {
+ dns_edns0_t *NULLABLE next;
+ uint16_t length;
+ uint8_t data[0];
+};
+
+typedef struct dns_message dns_message_t;
+struct dns_message {
+ dns_wire_t *NULLABLE wire;
+ int qdcount, ancount, nscount, arcount;
+ dns_rr_t *NULLABLE questions;
+ dns_rr_t *NULLABLE answers;
+ dns_rr_t *NULLABLE authority;
+ dns_rr_t *NULLABLE additional;
+ dns_edns0_t *NULLABLE edns0;
+};
+
+// Masks for bitfield data
+#define dns_qr_mask 0x8000
+#define dns_opcode_mask 0x7800
+#define dns_flags_mask 0x07f0
+#define dns_rcode_mask 0x000f
+
+// Shifts for bitfield data
+#define dns_qr_shift 15
+#define dns_opcode_shift 11
+#define dns_rcode_shift 0
+
+// Booleans
+#define dns_flags_aa 0x0400
+#define dns_flags_tc 0x0200
+#define dns_flags_rd 0x0100
+#define dns_flags_ra 0x0080
+#define dns_flags_ad 0x0020
+#define dns_flags_cd 0x0010
+
+// Getters
+#define dns_qr_get(w) ((ntohs((w)->bitfield) & dns_qr_mask) >> dns_qr_shift)
+#define dns_opcode_get(w) ((ntohs((w)->bitfield) & dns_opcode_mask) >> dns_opcode_shift)
+#define dns_rcode_get(w) ((ntohs((w)->bitfield) & dns_rcode_mask) >> dns_rcode_shift)
+
+// Setters
+#define dns_qr_set(w, value) ((w)->bitfield = htons(((ntohs((w)->bitfield) & ~dns_qr_mask) | \
+ ((value) << dns_qr_shift))))
+#define dns_opcode_set(w, value) ((w)->bitfield = htons(((ntohs((w)->bitfield) & ~dns_opcode_mask) | \
+ ((value) << dns_opcode_shift))))
+#define dns_rcode_set(w, value) ((w)->bitfield = htons(((ntohs((w)->bitfield) & ~dns_rcode_mask) | \
+ ((value) << dns_rcode_shift))))
+
+// Query/Response
+#define dns_qr_query 0
+#define dns_qr_response 1
+
+// Opcodes
+#define dns_opcode_query 0
+#define dns_opcode_iquery 1
+#define dns_opcode_status 2
+#define dns_opcode_notify 4
+#define dns_opcode_update 5
+#define dns_opcode_dso 6
+
+// Response Codes
+#define dns_rcode_noerror 0 // [RFC1035] No Error
+#define dns_rcode_formerr 1 // [RFC1035] Format Error
+#define dns_rcode_servfail 2 // [RFC1035] Server Failure
+#define dns_rcode_nxdomain 3 // [RFC1035] Non-Existent Domain
+#define dns_rcode_notimp 4 // [RFC1035] Not Implemented
+#define dns_rcode_refused 5 // [RFC1035] Query Refused
+#define dns_rcode_yxdomain 6 // [RFC2136][RFC6672] Name Exists when it should not
+#define dns_rcode_yxrrset 7 // [RFC2136] RR Set Exists when it should not
+#define dns_rcode_nxrrset 8 // [RFC2136] RR Set that should exist does not
+#define dns_rcode_notauth 9 // [RFC2136] Server Not Authoritative for zone, or [RFC2845] Not Authorized
+#define dns_rcode_notzone 10 // [RFC2136] Name not contained in zone
+#define dns_rcode_dsotypeni 11 // [RFCTBD draft-ietf-dnsop-session-signal] DSO-Type Not Implemented
+#define dns_rcode_badvers 16 // [RFC6891] Bad OPT Version, or [RFC2845] TSIG Signature Failure
+#define dns_rcode_badkey 17 // [RFC2845] Key not recognized
+#define dns_rcode_badtime 18 // [RFC2845] Signature out of time window
+#define dns_rcode_badmode 19 // [RFC2930] Bad TKEY Mode
+#define dns_rcode_badname 20 // [RFC2930] Duplicate key name
+#define dns_rcode_badalg 21 // [RFC2930] Algorithm not supported
+#define dns_rcode_badtrunc 22 // [RFC4635] Bad Truncation
+#define dns_rcode_badcookie 23 // [RFC7873] Bad/missing Server Cookie
+
+#define dns_qclass_in 1 // [RFC1035] Internet (IN)
+#define dns_qclass_chaos 3 // [D. Moon, "Chaosnet"] Chaosnet (MIT)
+#define dns_qclass_hesiod 4 // [MIT Project Athena Technical Plan] Hesiod service
+#define dns_qclass_none 254 // [RFC2136] NONE (delete, or not in use)
+#define dns_qclass_any 255 // [RFC1035] ANY (wildcard)
+
+#define dns_rrtype_a 1 // [RFC1035] a host address
+#define dns_rrtype_ns 2 // [RFC1035] an authoritative name server
+#define dns_rrtype_md 3 // [RFC1035] a mail destination (OBSOLETE - use MX)
+#define dns_rrtype_mf 4 // [RFC1035] a mail forwarder (OBSOLETE - use MX)
+#define dns_rrtype_cname 5 // [RFC1035] the canonical name for an alias
+#define dns_rrtype_soa 6 // [RFC1035] marks the start of a zone of authority
+#define dns_rrtype_mb 7 // [RFC1035] a mailbox domain name (EXPERIMENTAL)
+#define dns_rrtype_mg 8 // [RFC1035] a mail group member (EXPERIMENTAL)
+#define dns_rrtype_mr 9 // [RFC1035] a mail rename domain name (EXPERIMENTAL)
+#define dns_rrtype_null 10 // [RFC1035] a null RR (EXPERIMENTAL)
+#define dns_rrtype_wks 11 // [RFC1035] a well known service description
+#define dns_rrtype_ptr 12 // [RFC1035] a domain name pointer
+#define dns_rrtype_hinfo 13 // [RFC1035] host information
+#define dns_rrtype_minfo 14 // [RFC1035] mailbox or mail list information
+#define dns_rrtype_mx 15 // [RFC1035] mail exchange
+#define dns_rrtype_txt 16 // [RFC1035] text strings
+#define dns_rrtype_rp 17 // [RFC1183] for Responsible Person
+#define dns_rrtype_afsdb 18 // [RFC1183,RFC5864] for AFS Data Base location
+#define dns_rrtype_x25 19 // [RFC1183] for X.25 PSDN address
+#define dns_rrtype_isdn 20 // [RFC1183] for ISDN address
+#define dns_rrtype_rt 21 // [RFC1183] for Route Through
+#define dns_rrtype_nsap 22 // [RFC1706] for NSAP address, NSAP style A record
+#define dns_rrtype_nsap_ptr 23 // [RFC1348,RFC1637,RFC1706] for domain name pointer, NSAP style
+#define dns_rrtype_sig 24 // [RFC4034,RFC3755,RFC2535,RFC2536,RFC2537,RFC2931,RFC3110,RFC3008]
+#define dns_rrtype_key 25 // [RFC4034,RFC3755,RFC2535,RFC2536,RFC2537,RFC2539,RFC3008,RFC3110]
+#define dns_rrtype_px 26 // [RFC2163] X.400 mail mapping information
+#define dns_rrtype_gpos 27 // [RFC1712] Geographical Position
+#define dns_rrtype_aaaa 28 // [RFC3596] IP6 Address
+#define dns_rrtype_loc 29 // [RFC1876] Location Information
+#define dns_rrtype_nxt 30 // [RFC3755] [RFC2535] Next Domain (OBSOLETE)
+#define dns_rrtype_eid 31 // [http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] Endpoint Identifier
+#define dns_rrtype_nimloc 32 // [http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] Nimrod Locator
+#define dns_rrtype_srv 33 // [RFC2782] Server Selection
+#define dns_rrtype_atma 34 // ["ATM Name System, V2.0"] ATM Address
+#define dns_rrtype_naptr 35 // [RFC2915] [RFC2168] [RFC3403] Naming Authority Pointer
+#define dns_rrtype_kx 36 // [RFC2230] Key Exchanger
+#define dns_rrtype_cert 37 // [RFC4398] CERT
+#define dns_rrtype_a6 38 // [RFC3226] [RFC2874] [RFC6563] A6 (OBSOLETE - use AAAA)
+#define dns_rrtype_dname 39 // [RFC6672]
+#define dns_rrtype_sink 40 // [http://tools.ietf.org/html/draft-eastlake-kitchen-sink]
+#define dns_rrtype_opt 41 // [RFC6891] [RFC3225]
+#define dns_rrtype_apl 42 // [RFC3123]
+#define dns_rrtype_ds 43 // [RFC4034] [RFC3658] Delegation Signer
+#define dns_rrtype_sshfp 44 // [RFC4255] SSH Key Fingerprint
+#define dns_rrtype_ipseckey 45 // [RFC4025]
+#define dns_rrtype_rrsig 46 // [RFC4034] [RFC3755]
+#define dns_rrtype_nsec 47 // [RFC4034] [RFC3755]
+#define dns_rrtype_dnskey 48 // [RFC4034] [RFC3755]
+#define dns_rrtype_dhcid 49 // [RFC4701] DHCID
+#define dns_rrtype_nsec3 50 // [RFC5155] NSEC3
+#define dns_rrtype_nsec3param 51 // [RFC5155] NSEC3PARAM
+#define dns_rrtype_tlsa 52 // [RFC6698] TLSA
+#define dns_rrtype_smimea 53 // [RFC8162] S/MIME cert association
+#define dns_rrtype_hip 55 // Host Identity Protocol
+#define dns_rrtype_ninfo 56 // [Jim_Reid] NINFO/ninfo-completed-template
+#define dns_rrtype_rkey 57 // [Jim_Reid] RKEY/rkey-completed-template
+#define dns_rrtype_talink 58 // [Wouter_Wijngaards] Trust Anchor LINK
+#define dns_rrtype_cds 59 // [RFC7344] Child DS
+#define dns_rrtype_cdnskey 60 // [RFC7344] DNSKEY(s) the Child wants reflected in DS
+#define dns_rrtype_openpgpkey 61 // [RFC7929] OpenPGP Key
+#define dns_rrtype_csync 62 // [RFC7477] Child-To-Parent Synchronization
+#define dns_rrtype_spf 99 // [RFC7208]
+#define dns_rrtype_uinfo 100 // [IANA-Reserved]
+#define dns_rrtype_uid 101 // [IANA-Reserved]
+#define dns_rrtype_gid 102 // [IANA-Reserved]
+#define dns_rrtype_unspec 103 // [IANA-Reserved]
+#define dns_rrtype_nid 104 // [RFC6742]
+#define dns_rrtype_l32 105 // [RFC6742]
+#define dns_rrtype_l64 106 // [RFC6742]
+#define dns_rrtype_lp 107 // [RFC6742]
+#define dns_rrtype_eui48 108 // an EUI-48 address [RFC7043]
+#define dns_rrtype_eui64 109 // an EUI-64 address [RFC7043]
+#define dns_rrtype_tkey 249 // Transaction Key [RFC2930]
+#define dns_rrtype_tsig 250 // Transaction Signature [RFC2845]
+#define dns_rrtype_ixfr 251 // incremental transfer [RFC1995]
+#define dns_rrtype_axfr 252 // transfer of an entire zone [RFC1035][RFC5936]
+#define dns_rrtype_mailb 253 // mailbox-related RRs (MB, MG or MR) [RFC1035]
+#define dns_rrtype_maila 254 // mail agent RRs (OBSOLETE - see MX) [RFC1035]
+#define dns_rrtype_any 255 // A request for some or all records the server has available
+#define dns_rrtype_uri 256 // URI [RFC7553] URI/uri-completed-template
+#define dns_rrtype_caa 257 // Certification Authority Restriction [RFC6844]
+#define dns_rrtype_avc 258 // Application Visibility and Control [Wolfgang_Riedel]
+#define dns_rrtype_doa 259 // Digital Object Architecture [draft-durand-doa-over-dns]
+
+#define dns_opt_llq 1 // On-hold [http://files.dns-sd.org/draft-sekar-dns-llq.txt]
+#define dns_opt_update_lease 2 // On-hold [http://files.dns-sd.org/draft-sekar-dns-ul.txt]
+#define dns_opt_nsid 3 // [RFC5001]
+#define dns_opt_owner 4 // [draft-cheshire-edns0-owner-option]
+#define dns_opt_dau 5 // [RFC6975]
+#define dns_opt_dhu 6 // [RFC6975]
+#define dns_opt_n3u 7 // [RFC6975]
+#define dns_opt_client_subnet 8 // [RFC7871]
+#define dns_opt_expire 9 // [RFC7314]
+#define dns_opt_cookie 10 // [RFC7873]
+#define dns_opt_keepalive 11 // [RFC7828]
+#define dns_opt_padding 12 // [RFC7830]
+#define dns_opt_chain 13 // [RFC7901]
+#define dns_opt_key_tag 14 // [RFC8145]
+
+// towire.c:
+
+uint16_t srp_random16(void);
+void dns_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+ dns_towire_state_t *NONNULL txn,
+ const char *NONNULL name);
+void dns_full_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+ dns_towire_state_t *NONNULL txn,
+ const char *NONNULL name);
+void dns_pointer_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+ dns_towire_state_t *NONNULL txn,
+ dns_name_pointer_t *NONNULL pointer);
+void dns_u8_to_wire(dns_towire_state_t *NONNULL txn,
+ uint8_t val);
+void dns_u16_to_wire(dns_towire_state_t *NONNULL txn,
+ uint16_t val);
+void dns_u32_to_wire(dns_towire_state_t *NONNULL txn,
+ uint32_t val);
+void dns_ttl_to_wire(dns_towire_state_t *NONNULL txn,
+ int32_t val);
+void dns_rdlength_begin(dns_towire_state_t *NONNULL txn);
+void dns_rdlength_end(dns_towire_state_t *NONNULL txn);
+void dns_rdata_a_to_wire(dns_towire_state_t *NONNULL txn,
+ const char *NONNULL ip_address);
+void dns_rdata_aaaa_to_wire(dns_towire_state_t *NONNULL txn,
+ const char *NONNULL ip_address);
+uint16_t dns_rdata_key_to_wire(dns_towire_state_t *NONNULL txn,
+ unsigned key_type,
+ unsigned name_type,
+ unsigned signatory,
+ srp_key_t *NONNULL key);
+void dns_rdata_txt_to_wire(dns_towire_state_t *NONNULL txn,
+ const char *NONNULL txt_record);
+void dns_rdata_raw_data_to_wire(dns_towire_state_t *NONNULL txn, const void *NONNULL raw_data, size_t length);
+void dns_edns0_header_to_wire(dns_towire_state_t *NONNULL txn,
+ int mtu,
+ int xrcode,
+ int version,
+ int DO);
+void dns_edns0_option_begin(dns_towire_state_t *NONNULL txn);
+void dns_edns0_option_end(dns_towire_state_t *NONNULL txn);
+void dns_sig0_signature_to_wire(dns_towire_state_t *NONNULL txn,
+ srp_key_t *NONNULL key, uint16_t key_tag,
+ dns_name_pointer_t *NONNULL signer,
+ const char *NONNULL signer_fqdn);
+int dns_send_to_server(dns_transaction_t *NONNULL txn,
+ const char *NONNULL anycast_address, uint16_t port,
+ dns_response_callback_t NONNULL callback);
+
+// fromwire.c:
+dns_label_t *NULLABLE dns_label_parse(const uint8_t *NONNULL buf, unsigned mlen, unsigned *NONNULL offp);
+bool dns_opt_parse(dns_edns0_t *NONNULL *NULLABLE ret, dns_rr_t *NONNULL rrset);
+bool dns_name_parse(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *NONNULL buf, unsigned len,
+ unsigned *NONNULL offp, unsigned base);
+bool dns_u8_parse(const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, uint8_t *NONNULL ret);
+bool dns_u16_parse(const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, uint16_t *NONNULL ret);
+bool dns_u32_parse(const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, uint32_t *NONNULL ret);
+bool dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *NONNULL buf, unsigned *NONNULL offp,
+ unsigned target, unsigned rdlen, unsigned rrstart);
+bool dns_rr_parse(dns_rr_t *NONNULL rrset,
+ const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, bool rrdata_permitted);
+void dns_name_free(dns_label_t *NONNULL name);
+void dns_rrdata_free(dns_rr_t *NONNULL rr);
+void dns_message_free(dns_message_t *NONNULL message);
+bool dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *NONNULL buf, unsigned *NONNULL offp,
+ unsigned target, unsigned rdlen, unsigned rrstart);
+bool dns_wire_parse(dns_message_t *NONNULL *NULLABLE ret, dns_wire_t *NONNULL message, unsigned len);
+bool dns_names_equal(dns_label_t *NONNULL name1, dns_label_t *NONNULL name2);
+const char *NONNULL dns_name_print(dns_name_t *NONNULL name, char *NONNULL buf, int bufmax);
+bool dns_names_equal_text(dns_label_t *NONNULL name1, const char *NONNULL name2);
+size_t dns_name_wire_length(dns_label_t *NONNULL name);
+size_t dns_name_to_wire_canonical(uint8_t *NONNULL buf, size_t max, dns_label_t *NONNULL name);
+#endif // _DNS_MSG_H
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* dnssd-proxy.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ * This is a Discovery Proxy module for the SRP gateway.
+ *
+ * The motivation here is that it makes sense to co-locate the SRP relay and the Discovery Proxy because
+ * these functions are likely to co-exist on the same node, listening on the same port. For homenet-style
+ * name resolution, we need a DNS proxy that implements DNSSD Discovery Proxy for local queries, but
+ * forwards other queries to an ISP resolver. The SRP gateway is already expecting to do this.
+ * This module implements the functions required to allow the SRP gateway to also do Discovery Relay.
+ *
+ * The Discovery Proxy relies on Apple's DNS-SD library and the mDNSResponder DNSSD server, which is included
+ * in Apple's open source mDNSResponder package, available here:
+ *
+ * https://opensource.apple.com/tarballs/mDNSResponder/
+ */
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <ctype.h>
+
+#include "dns_sd.h"
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+#include "dso.h"
+#include "ioloop.h"
+
+// Enumerate the list of interfaces, map them to interface indexes, give each one a name
+// Have a tree of subdomains for matching
+
+typedef struct dnssd_query {
+ io_t io;
+ DNSServiceRef ref;
+ char *name; // The name we are looking up.
+ const char *enclosing_domain; // The domain the name is in, or NULL if not ours; if null, name is an FQDN.
+ dns_name_pointer_t enclosing_domain_pointer;
+ message_t *question;
+ comm_t *connection;
+ dso_activity_t *activity;
+ int serviceFlags; // Service flags to use with this query.
+ bool is_dns_push;
+ bool is_edns0;
+ uint16_t type, qclass; // Original query type and class.
+ dns_towire_state_t towire;
+ uint8_t *p_dso_length; // Where to store the DSO length just before we write out a push notification.
+ dns_wire_t response; // This has to be at the end because we don't zero the RRdata buffer.
+} dnssd_query_t;
+
+const char push_subscription_activity_type[] = "push subscription";
+
+const char local_suffix[] = ".local.";
+#define PROXIED_DOMAIN "proxy.home.arpa."
+const char proxied_domain[] = PROXIED_DOMAIN;
+const char proxied_domain_ld[] = "." PROXIED_DOMAIN;
+#define MY_NAME "proxy.example.com."
+#define MY_IPV4_ADDR "192.0.2.1"
+// #define MY_IPV6_ADDR "2001:db8::1" // for example
+
+#define TOWIRE_CHECK(note, towire, func) { func; if ((towire)->error != 0 && failnote == NULL) failnote = (note); }
+
+int64_t dso_transport_idle(void *context, int64_t next_event)
+{
+ return next_event;
+}
+
+void dnssd_query_cancel(io_t *io)
+{
+ dnssd_query_t *query = (dnssd_query_t *)io;
+ if (query->io.sock != -1) {
+ DNSServiceRefDeallocate(query->ref);
+ query->io.sock = -1;
+ }
+ query->connection = NULL;
+}
+
+void
+dns_push_finalize(dso_activity_t *activity)
+{
+ dnssd_query_t *query = (dnssd_query_t *)activity->context;
+ INFO("dnssd_push_finalize: %s", activity->name);
+ dnssd_query_cancel(&query->io);
+}
+
+void
+dnssd_query_finalize(io_t *io)
+{
+ dnssd_query_t *query = (dnssd_query_t *)io;
+ INFO("dnssd_query_finalize on %s%s", query->name, query->enclosing_domain ? ".local" : "");
+ if (query->question) {
+ message_free(query->question);
+ }
+ free(query->name);
+ free(query);
+}
+
+static void
+dnssd_query_callback(io_t *io)
+{
+ dnssd_query_t *query = (dnssd_query_t *)io;
+ int status = DNSServiceProcessResult(query->ref);
+ if (status != kDNSServiceErr_NoError) {
+ ERROR("DNSServiceProcessResult on %s%s returned %d", query->name, query->enclosing_domain ? ".local" : "", status);
+ if (query->activity != NULL && query->connection != NULL) {
+ dso_drop_activity(query->connection->dso, query->activity);
+ } else {
+ dnssd_query_cancel(&query->io);
+ }
+ }
+}
+
+static void
+add_dnssd_query(dnssd_query_t *query)
+{
+ io_t *io = &query->io;
+ io->sock = DNSServiceRefSockFD(query->ref);
+ io->cancel = dnssd_query_cancel;
+ io->cancel_on_close = &query->connection->io;
+ add_reader(io, dnssd_query_callback, dnssd_query_finalize);
+}
+
+// Parse a NUL-terminated text string into a sequence of labels.
+dns_name_t *
+dns_pres_name_parse(const char *pname)
+{
+ const char *dot = strchr(pname, '.');
+ dns_label_t *ret;
+ int len;
+ if (dot == NULL) {
+ dot = pname + strlen(pname);
+ }
+ len = (dot - pname) + 1 + (sizeof *ret) - DNS_MAX_LABEL_SIZE;
+ ret = calloc(len, 1);
+ if (ret == NULL) {
+ return NULL;
+ }
+ ret->len = dot - pname;
+ if (ret->len > 0) {
+ memcpy(ret->data, pname, ret->len);
+ }
+ ret->data[ret->len] = 0;
+ if (dot[0] == '.') {
+ ret->next = dns_pres_name_parse(dot + 1);
+ }
+ return ret;
+}
+
+bool
+dns_subdomain_of(dns_name_t *name, dns_name_t *domain, char *buf, size_t buflen)
+{
+ int dnum = 0, nnum = 0;
+ dns_name_t *np, *dp;
+ char *bufp = buf;
+ size_t bytesleft = buflen;
+
+ for (dp = domain; dp; dp = dp->next) {
+ dnum++;
+ }
+ for (np = name; np; np = np->next) {
+ nnum++;
+ }
+ if (nnum < dnum) {
+ return false;
+ }
+ for (np = name; np; np = np->next) {
+ if (nnum-- == dnum) {
+ break;
+ }
+ }
+ if (dns_names_equal(np, domain)) {
+ for (dp = name; dp != np; dp = dp->next) {
+ if (dp->len + 1 > bytesleft) {
+ // It's okay to return false here because a name that overflows the buffer isn't valid.
+ ERROR("dns_subdomain_of: out of buffer space!");
+ return false;
+ }
+ memcpy(bufp, dp->data, dp->len);
+ bufp += dp->len;
+ bytesleft = bytesleft - dp->len;
+ if (dp->next != np) {
+ *bufp++ = '.';
+ bytesleft -= dp->len;
+ }
+ }
+ *bufp = 0;
+ return true;
+ }
+ return false;
+}
+
+void
+dp_simple_response(comm_t *comm, int rcode)
+{
+ if (comm->send_response) {
+ struct iovec iov;
+ dns_wire_t response;
+ memset(&response, 0, DNS_HEADER_SIZE);
+
+ // We take the ID and the opcode from the incoming message, because if the
+ // header has been mangled, we (a) wouldn't have gotten here and (b) don't
+ // have any better choice anyway.
+ response.id = comm->message->wire.id;
+ dns_qr_set(&response, dns_qr_response);
+ dns_opcode_set(&response, dns_opcode_get(&comm->message->wire));
+ dns_rcode_set(&response, rcode);
+ iov.iov_base = &response;
+ iov.iov_len = DNS_HEADER_SIZE; // No RRs
+ comm->send_response(comm, comm->message, &iov, 1);
+ }
+}
+
+bool
+dp_served(dns_name_t *name, char *buf, size_t bufsize)
+{
+ static dns_name_t *home_dot_arpa = NULL;
+ if (home_dot_arpa == NULL) {
+ home_dot_arpa = dns_pres_name_parse(proxied_domain);
+ if (home_dot_arpa == NULL) {
+ ERROR("Unable to parse %s!", proxied_domain);
+ return false;
+ }
+ }
+
+ // For now we treat any query to home.arpa as local.
+ return dns_subdomain_of(name, home_dot_arpa, buf, bufsize);
+}
+
+// Utility function to find "local" on the end of a string of labels.
+bool
+truncate_local(dns_name_t *name)
+{
+ dns_label_t *lp, *prev, *prevprev;
+
+ prevprev = prev = NULL;
+ // Find the root label.
+ for (lp = name; lp && lp->len; lp = lp->next) {
+ prevprev = prev;
+ prev = lp;
+ }
+ if (lp && prev && prevprev) {
+ if (prev->len == 5 && !strncasecmp(prev->data, "local", 5)) {
+ dns_name_free(prev);
+ prevprev->next = NULL;
+ return true;
+ }
+ }
+ dns_name_free(name);
+ return false;
+}
+
+void
+dp_query_add_data_to_response(dnssd_query_t *query, const char *fullname,
+ uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl)
+{
+ dns_towire_state_t *towire = &query->towire;
+ const char *failnote = NULL;
+
+ // Rewrite the domain if it's .local.
+ if (query->enclosing_domain != NULL) {
+ TOWIRE_CHECK("query name", towire, dns_name_to_wire(NULL, towire, query->name));
+ if (query->enclosing_domain_pointer.message_start != NULL) {
+ // This happens if we are sending a DNS response, because we can always point back to the question.
+ TOWIRE_CHECK("enclosing_domain_pointer", towire,
+ dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+ INFO(" dns answer: type %02d class %02d %s.%s (p)", rrtype, rrclass, query->name, query->enclosing_domain);
+ } else {
+ // This happens if we are sending a DNS Push notification.
+ TOWIRE_CHECK("enclosing_domain", towire, dns_full_name_to_wire(NULL, towire, query->enclosing_domain));
+ INFO("push answer: type %02d class %02d %s.%s", rrtype, rrclass, query->name, query->enclosing_domain);
+ }
+ } else {
+ TOWIRE_CHECK("query->name", towire, dns_full_name_to_wire(NULL, towire, query->name));
+ INFO("%s answer: type %02d class %02d %s.%s (p)",
+ query->is_dns_push ? "push" : " dns", rrtype, rrclass, query->name, query->enclosing_domain);
+ }
+ TOWIRE_CHECK("rrtype", towire, dns_u16_to_wire(towire, rrtype));
+ TOWIRE_CHECK("rrclass", towire, dns_u16_to_wire(towire, rrclass));
+ TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, ttl));
+
+ if (rdlen > 0) {
+ // If necessary, correct domain names inside of rrdata.
+ if (rrclass == dns_qclass_in && (rrtype == dns_rrtype_srv ||
+ rrtype == dns_rrtype_ptr ||
+ rrtype == dns_rrtype_cname)) {
+ dns_rr_t answer;
+ dns_name_t *name;
+ unsigned offp = 0;
+ answer.type = rrtype;
+ answer.qclass = rrclass;
+ if (!dns_rdata_parse_data(&answer, rdata, &offp, rdlen, rdlen, 0)) {
+ ERROR("dp_query_add_data_to_response: rdata from mDNSResponder didn't parse!!");
+ goto raw;
+ }
+ switch(rrtype) {
+ case dns_rrtype_cname:
+ case dns_rrtype_ptr:
+ name = answer.data.ptr.name;
+ if (!truncate_local(name)) {
+ goto raw;
+ }
+ TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
+ break;
+ case dns_rrtype_srv:
+ name = answer.data.srv.name;
+ if (!truncate_local(name)) {
+ goto raw;
+ }
+ TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
+ TOWIRE_CHECK("answer.data.srv.priority", towire, dns_u16_to_wire(towire, answer.data.srv.priority));
+ TOWIRE_CHECK("answer.data.srv.weight", towire, dns_u16_to_wire(towire, answer.data.srv.weight));
+ TOWIRE_CHECK("answer.data.srv.port", towire, dns_u16_to_wire(towire, answer.data.srv.port));
+ break;
+ default:
+ ERROR("dp_query_add_data_to_response: can't get here.");
+ goto raw;
+ break;
+ }
+ // If we get here, the name ended in "local."
+ int bytes_written = dns_name_to_wire_canonical(towire->p, towire->lim - towire->p, name);
+ towire->p += bytes_written;
+ if (query->enclosing_domain_pointer.message_start != NULL) {
+ TOWIRE_CHECK("enclosing_domain_pointer internal", towire,
+ dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+ } else {
+ TOWIRE_CHECK("enclosing_domain internal", towire,
+ dns_full_name_to_wire(NULL, towire, query->enclosing_domain));
+ }
+ dns_rdlength_end(towire);
+ } else {
+ raw:
+ TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
+ TOWIRE_CHECK("rdata", towire, dns_rdata_raw_data_to_wire(towire, rdata, rdlen));
+ }
+ } else {
+ TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
+ }
+ if (failnote) {
+ ERROR("dp_query_add_data_to_response: %s", failnote);
+ }
+}
+
+typedef struct hardwired hardwired_t;
+struct hardwired {
+ hardwired_t *next;
+ uint16_t type;
+ char *name;
+ char *fullname;
+ uint8_t *rdata;
+ uint16_t rdlen;
+} *hardwired_responses;
+
+void
+dnssd_hardwired_add(const char *name, const char *domain, size_t rdlen, uint8_t *rdata, uint16_t type)
+{
+ hardwired_t *hp;
+ int namelen = strlen(name);
+ size_t total = (sizeof *hp) + rdlen + namelen * 2 + strlen(proxied_domain_ld) + 2;
+
+ hp = calloc(1, (sizeof *hp) + rdlen + namelen * 2 + strlen(proxied_domain_ld) + 2);
+ hp->rdata = (uint8_t *)(hp + 1);
+ hp->rdlen = rdlen;
+ memcpy(hp->rdata, rdata, rdlen);
+ hp->name = (char *)hp->rdata + rdlen;
+ strcpy(hp->name, name);
+ hp->fullname = hp->name + namelen + 1;
+ strcpy(hp->fullname, name);
+ strcpy(hp->fullname + namelen, proxied_domain_ld);
+ if (hp->fullname + strlen(hp->fullname) + 1 != (char *)hp + total) {
+ ERROR("%p != %p", hp->fullname + strlen(hp->fullname) + 1, ((char *)hp) + total);
+ }
+ hp->type = type;
+ hp->next = hardwired_responses;
+ hardwired_responses = hp;
+
+ INFO("hardwired_add: fullname %s name %s type %d rdlen %d", hp->fullname, hp->name, hp->type, hp->rdlen);
+}
+
+void
+dnssd_hardwired_setup(void)
+{
+ dns_wire_t wire;
+ dns_towire_state_t towire;
+
+#define RESET \
+ memset(&towire, 0, sizeof towire); \
+ towire.message = &wire; \
+ towire.p = wire.data; \
+ towire.lim = towire.p + sizeof wire.data
+
+ // Browsing pointers...
+ RESET;
+ dns_full_name_to_wire(NULL, &towire, proxied_domain);
+ dnssd_hardwired_add("b._dns-sd._udp", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_ptr);
+ dnssd_hardwired_add("lb._dns-sd._udp", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_ptr);
+
+ // SRV
+ // _dns-push-tls._tcp
+ RESET;
+ dns_u16_to_wire(&towire, 0); // priority
+ dns_u16_to_wire(&towire, 0); // weight
+ dns_u16_to_wire(&towire, 53); // port
+ // Define MY_NAME to reference a name for this server in a different zone.
+#ifndef MY_NAME
+ dns_name_to_wire(NULL, &towire, "ns");
+ dns_full_name_to_wire(NULL, &towire, proxied_domain);
+#else
+ dns_full_name_to_wire(NULL, &towire, MY_NAME);
+#endif
+ dnssd_hardwired_add("_dns-push-tls._tcp", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
+
+ // A
+#ifndef MY_NAME
+ // ns
+#ifdef MY_IPV4_ADDR
+ RESET;
+ dns_rdata_a_to_wire(&towire, MY_IPV4_ADDR);
+ dnssd_hardwired_add("ns", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_a);
+#endif
+
+ // AAAA
+#ifdef MY_IPV6_ADDR
+ RESET;
+ dns_rdata_aaaa_to_wire(&towire, MY_IPV6_ADDR);
+ dnssd_hardwired_add("ns", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_aaaa);
+#endif
+#endif
+
+ // NS
+ RESET;
+#ifdef MY_NAME
+ dns_full_name_to_wire(NULL, &towire, MY_NAME);
+#else
+ dns_name_to_wire(NULL, &towire, "ns");
+ dns_full_name_to_wire(NULL, &towire, proxied_domain);
+#endif
+ dnssd_hardwired_add("", proxied_domain, towire.p - wire.data, wire.data, dns_rrtype_ns);
+
+ // SOA (piggybacking on what we already did for NS, which starts the same.
+ dns_name_to_wire(NULL, &towire, "postmaster");
+ dns_full_name_to_wire(NULL, &towire, proxied_domain);
+ dns_u32_to_wire(&towire, 0); // serial
+ dns_ttl_to_wire(&towire, 7200); // refresh
+ dns_ttl_to_wire(&towire, 3600); // retry
+ dns_ttl_to_wire(&towire, 86400); // expire
+ dns_ttl_to_wire(&towire, 120); // minimum
+ dnssd_hardwired_add("", proxied_domain, towire.p - wire.data, wire.data, dns_rrtype_soa);
+}
+
+void
+dp_query_send_dns_response(dnssd_query_t *query)
+{
+ struct iovec iov;
+ dns_towire_state_t *towire = &query->towire;
+ const char *failnote = NULL;
+
+ // Send an SOA record if it's a .local query.
+ if (query->enclosing_domain != NULL) {
+ // DNSSD Hybrid, Section 6.1.
+ TOWIRE_CHECK("&query->enclosing_domain_pointer", towire,
+ dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+ TOWIRE_CHECK("dns_rrtype_soa", towire,
+ dns_u16_to_wire(towire, dns_rrtype_soa));
+ TOWIRE_CHECK("dns_qclass_in", towire,
+ dns_u16_to_wire(towire, dns_qclass_in));
+ TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, 3600));
+ TOWIRE_CHECK("rdlength_begin ", towire, dns_rdlength_begin(towire));
+#ifdef MY_NAME
+ TOWIRE_CHECK(MY_NAME, towire, dns_full_name_to_wire(NULL, towire, MY_NAME));
+#else
+ TOWIRE_CHECK("\"ns\"", towire, dns_name_to_wire(NULL, towire, "ns"));
+ TOWIRE_CHECK("&query->enclosing_domain_pointer", towire,
+ dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+#endif
+ TOWIRE_CHECK("\"postmaster\"", towire,
+ dns_name_to_wire(NULL, towire, "postmaster"));
+ TOWIRE_CHECK("&query->enclosing_domain_pointer", towire,
+ dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+ TOWIRE_CHECK("serial", towire,dns_u32_to_wire(towire, 0)); // serial
+ TOWIRE_CHECK("refresh", towire, dns_ttl_to_wire(towire, 7200)); // refresh
+ TOWIRE_CHECK("retry", towire, dns_ttl_to_wire(towire, 3600)); // retry
+ TOWIRE_CHECK("expire", towire, dns_ttl_to_wire(towire, 86400)); // expire
+ TOWIRE_CHECK("minimum", towire, dns_ttl_to_wire(towire, 120)); // minimum
+ dns_rdlength_end(towire);
+ query->response.nscount = htons(1);
+
+ // Response is authoritative and not recursive.
+ query->response.bitfield = htons((ntohs(query->response.bitfield) | dns_flags_aa) & ~dns_flags_ra);
+ } else {
+ // Response is recursive and not authoritative.
+ query->response.bitfield = htons((ntohs(query->response.bitfield) | dns_flags_ra) & ~dns_flags_aa);
+ }
+ // Not truncated, not authentic, checking not disabled.
+ query->response.bitfield = htons(ntohs(query->response.bitfield) & ~(dns_flags_rd | dns_flags_tc | dns_flags_ad | dns_flags_cd));
+
+ // This is a response
+ dns_qr_set(&query->response, dns_qr_response);
+ // No error.
+ dns_rcode_set(&query->response, dns_rcode_noerror);
+
+ // Send an OPT RR if we got one
+ if (query->is_edns0) {
+ TOWIRE_CHECK("Root label", towire, dns_u8_to_wire(towire, 0)); // Root label
+ TOWIRE_CHECK("dns_rrtype_opt", towire, dns_u16_to_wire(towire, dns_rrtype_opt));
+ TOWIRE_CHECK("UDP Payload size", towire, dns_u16_to_wire(towire, 4096)); // UDP Payload size
+ TOWIRE_CHECK("extended-rcode", towire, dns_u8_to_wire(towire, 0)); // extended-rcode
+ TOWIRE_CHECK("EDNS version 0", towire, dns_u8_to_wire(towire, 0)); // EDNS version 0
+ TOWIRE_CHECK("No extended flags", towire, dns_u16_to_wire(towire, 0)); // No extended flags
+ TOWIRE_CHECK("No payload", towire, dns_u16_to_wire(towire, 0)); // No payload
+ query->response.arcount = htons(1);
+ }
+
+ if (towire->error) {
+ ERROR("dp_query_send_dns_response failed on %s", failnote);
+ }
+
+ iov.iov_len = (query->towire.p - (uint8_t *)&query->response);
+ iov.iov_base = &query->response;
+ INFO("dp_query_send_dns_response: %s (len %zd)", query->name, iov.iov_len);
+
+ if (query->connection != NULL) {
+ query->connection->send_response(query->connection, query->question, &iov, 1);
+ }
+
+ // Free up state
+ dnssd_query_cancel(&query->io);
+ // Query will be freed automatically next time through the io loop.
+}
+
+void
+dp_query_towire_reset(dnssd_query_t *query)
+{
+ query->towire.p = &query->response.data[0]; // We start storing RR data here.
+ query->towire.lim = &query->response.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
+ query->towire.message = &query->response;
+ query->p_dso_length = NULL;
+}
+
+void
+dns_push_start(dnssd_query_t *query)
+{
+ const char *failnote = NULL;
+
+ // If we don't have a dso header yet, start one.
+ if (query->p_dso_length == NULL) {
+ memset(&query->response, 0, (sizeof query->response) - DNS_DATA_SIZE);
+ dns_opcode_set(&query->response, dns_opcode_dso);
+ // This is a unidirectional DSO message, which is marked as a query
+ dns_qr_set(&query->response, dns_qr_query);
+ // No error cuz not a response.
+ dns_rcode_set(&query->response, dns_rcode_noerror);
+
+ TOWIRE_CHECK("kDSOType_DNSPushUpdate", &query->towire,
+ dns_u16_to_wire(&query->towire, kDSOType_DNSPushUpdate));
+ if (query->towire.p + 2 > query->towire.lim) {
+ ERROR("No room for dso length in DNS Push notification message.");
+ dp_query_towire_reset(query);
+ return;
+ }
+ query->p_dso_length = query->towire.p;
+ query->towire.p += 2;
+ }
+ if (failnote != NULL) {
+ ERROR("dns_push_start: couldn't start update: %s", failnote);
+ }
+}
+
+void
+dp_push_response(dnssd_query_t *query)
+{
+ struct iovec iov;
+
+ if (query->p_dso_length != NULL) {
+ int16_t dso_length = query->towire.p - query->p_dso_length - 2;
+ iov.iov_len = (query->towire.p - (uint8_t *)&query->response);
+ iov.iov_base = &query->response;
+ INFO("dp_push_response: %s (len %zd)", query->name, iov.iov_len);
+
+ query->towire.p = query->p_dso_length;
+ dns_u16_to_wire(&query->towire, dso_length);
+ if (query->connection != NULL) {
+ query->connection->send_response(query->connection, query->question, &iov, 1);
+ }
+ dp_query_towire_reset(query);
+ }
+}
+
+bool
+dnssd_hardwired_response(dnssd_query_t *query, DNSServiceQueryRecordReply callback)
+{
+ hardwired_t *hp;
+ bool got_response = false;
+
+ for (hp = hardwired_responses; hp; hp = hp->next) {
+ if ((query->type == hp->type || query->type == dns_rrtype_any) &&
+ query->qclass == dns_qclass_in && !strcasecmp(hp->name, query->name)) {
+ if (query->is_dns_push) {
+ dns_push_start(query);
+ dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata, 3600);
+ } else {
+ // Store the response
+ dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata, 3600);
+ query->response.ancount = htons(ntohs(query->response.ancount) + 1);
+ }
+ got_response = true;
+ }
+ }
+ if (got_response) {
+ if (query->is_dns_push) {
+ dp_push_response(query);
+ } else {
+ // Steal the question
+ query->question = query->connection->message;
+ query->connection->message = NULL;
+ // Send the answer(s).
+ dp_query_send_dns_response(query);
+ }
+ return true;
+ }
+ return false;
+}
+
+// This is the callback for dns query results.
+void
+dns_query_callback(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)
+{
+ dnssd_query_t *query = context;
+
+ INFO("%s %d %d %x %d", fullname, rrtype, rrclass, rdlen, errorCode);
+
+ if (errorCode == kDNSServiceErr_NoError) {
+ dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata,
+ ttl > 10 ? 10 : ttl); // Per dnssd-hybrid 5.5.1, limit ttl to 10 seconds
+ query->response.ancount = htons(ntohs(query->response.ancount) + 1);
+ // If there isn't more coming, send the response now
+ if (!(flags & kDNSServiceFlagsMoreComing)) {
+ dp_query_send_dns_response(query);
+ }
+ } else if (errorCode == kDNSServiceErr_NoSuchRecord) {
+ // If we get "no such record," we can't really do much except return the answer.
+ dp_query_send_dns_response(query);
+ } else {
+ dns_rcode_set(&query->response, dns_rcode_servfail);
+ dp_query_send_dns_response(query);
+ }
+}
+
+void
+dp_query_wakeup(io_t *io)
+{
+ dnssd_query_t *query = (dnssd_query_t *)io;
+ char name[DNS_MAX_NAME_SIZE + 1];
+ int namelen = strlen(query->name);
+
+ // Should never happen.
+ if ((namelen + query->enclosing_domain != NULL ? sizeof local_suffix : 0) > sizeof name) {
+ ERROR("db_query_wakeup: no space to construct name.");
+ dnssd_query_cancel(&query->io);
+ }
+
+ strcpy(name, query->name);
+ if (query->enclosing_domain != NULL) {
+ strcpy(name + namelen, local_suffix);
+ }
+ dp_query_send_dns_response(query);
+}
+
+bool
+dp_query_start(comm_t *comm, dnssd_query_t *query, int *rcode, DNSServiceQueryRecordReply callback)
+{
+ char name[DNS_MAX_NAME_SIZE + 1];
+ char *np;
+
+ if (query->enclosing_domain != NULL) {
+ if (dnssd_hardwired_response(query, callback)) {
+ *rcode = dns_rcode_noerror;
+ return true;
+ }
+
+ int len = strlen(query->name);
+ if (len + sizeof local_suffix > sizeof name) {
+ *rcode = dns_rcode_servfail;
+ free(query->name);
+ free(query);
+ ERROR("question name %s is too long for .local.", name);
+ return false;
+ }
+ memcpy(name, query->name, len);
+ memcpy(&name[len], local_suffix, sizeof local_suffix);
+ np = name;
+ } else {
+ np = query->name;
+ }
+
+ // Issue a DNSServiceQueryRecord call
+ int err = DNSServiceQueryRecord(&query->ref, query->serviceFlags,
+ kDNSServiceInterfaceIndexAny, np, query->type,
+ query->qclass, callback, query);
+ if (err != kDNSServiceErr_NoError) {
+ ERROR("dp_query_start: DNSServiceQueryRecord failed for '%s': %d", np, err);
+ *rcode = dns_rcode_servfail;
+ return false;
+ } else {
+ INFO("dp_query_start: DNSServiceQueryRecord started for '%s': %d", np, err);
+ }
+
+ // If this isn't a DNS Push subscription, we need to respond quickly with as much data as we have. It
+ // turns out that dig gives us a second, but also that responses seem to come back in on the order of a
+ // millisecond, so we'll wait 100ms.
+ if (!query->is_dns_push && query->enclosing_domain) {
+ query->io.wakeup_time = ioloop_now + IOLOOP_SECOND / 10;
+ query->io.wakeup = dp_query_wakeup;
+ }
+
+ add_dnssd_query(query);
+ return true;
+}
+
+dnssd_query_t *
+dp_query_generate(comm_t *comm, dns_rr_t *question, bool dns_push, int *rcode)
+{
+ char name[DNS_MAX_NAME_SIZE + 1];
+ const char *enclosing_domain;
+
+ // If it's a query for a name served by the local discovery proxy, do an mDNS lookup.
+ if ((dp_served(question->name, name, sizeof name))) {
+ enclosing_domain = proxied_domain;
+ INFO("%s question: type %d class %d %s%s -> %s.local", dns_push ? "push" : " dns",
+ question->type, question->qclass, name, proxied_domain, name);
+ } else {
+ dns_name_print(question->name, name, sizeof name);
+ enclosing_domain = NULL;
+ INFO("%s question: type %d class %d %s",
+ dns_push ? "push" : " dns", question->type, question->qclass, name);
+ }
+
+ dnssd_query_t *query = malloc(sizeof *query);
+ if (query == NULL) {
+ ERROR("Unable to allocate memory for query on %s", name);
+ *rcode = dns_rcode_servfail;
+ return NULL;
+ }
+ // Zero out everything except the message data buffer, which is large and doesn't need it.
+ memset(query, 0, (sizeof *query) - (sizeof query->response) + DNS_HEADER_SIZE);
+
+ // Steal the data from the question. If subdomain is not null, this is a local mDNS query; otherwise
+ // we are recursing.
+ INFO("name = %s", name);
+ query->name = strdup(name);
+ if (!query->name) {
+ *rcode = dns_rcode_servfail;
+ free(query);
+ ERROR("unable to allocate memory for question name on %s", name);
+ return NULL;
+ }
+ // It is safe to assume that enclosing domain will not be freed out from under us.
+ query->enclosing_domain = enclosing_domain;
+ query->serviceFlags = 0;
+
+ // If this is a local query, add ".local" to the end of the name and require multicast.
+ if (enclosing_domain != NULL) {
+ query->serviceFlags |= kDNSServiceFlagsForceMulticast;
+ } else {
+ query->serviceFlags |= kDNSServiceFlagsReturnIntermediates;
+ }
+ // Name now contains the name we want mDNSResponder to look up.
+
+ // XXX make sure finalize does the right thing.
+ query->connection = comm;
+
+ // Remember whether this is a long-lived query.
+ query->is_dns_push = dns_push;
+
+ // Start writing the response
+ dp_query_towire_reset(query);
+
+ query->type = question->type;
+ query->qclass = question->qclass;
+
+ // Just in case we don't need to do a DNSServiceQueryRecord query to satisfy it.
+ query->io.sock = -1;
+
+ *rcode = dns_rcode_noerror;
+ return query;
+}
+
+// This is the callback for DNS push query results, as opposed to push updates.
+void
+dns_push_query_callback(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)
+{
+ dnssd_query_t *query = context;
+
+ // From DNSSD-Hybrid, for mDNS queries:
+ // If we have cached answers, respond immediately, because we probably have all the answers.
+ // If we don't have cached answers, respond as soon as we get an answer (presumably more-coming will be false).
+
+ // The spec says to not query if we have cached answers. We trust the DNSServiceQueryRecord call to handle this.
+
+ // If we switch to using a single connection to mDNSResponder, we could have !more-coming trigger a flush of
+ // all outstanding queries that aren't waiting on a time trigger. This is because more-coming isn't
+ // query-specific
+
+ INFO("PUSH %s %d %d %x %d", fullname, rrtype, rrclass, rdlen, errorCode);
+
+ // query_state_waiting means that we're answering a regular DNS question
+ if (errorCode == kDNSServiceErr_NoError) {
+ dns_push_start(query);
+
+ // If kDNSServiceFlagsAdd is set, it's an add, otherwise a delete.
+ if (flags & kDNSServiceFlagsAdd) {
+ dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata, ttl);
+ } else {
+ // I think if this happens it means delete all RRs of this type.
+ if (rdlen == 0) {
+ dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_any, rdlen, rdata, 0);
+ } else {
+ dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_none, rdlen, rdata, 0);
+ }
+ }
+ // If there isn't more coming, send a DNS Push notification now.
+ // XXX If enough comes to fill the response, send the message.
+ if (!(flags & kDNSServiceFlagsMoreComing)) {
+ dp_push_response(query);
+ }
+ } else {
+ ERROR("dns_push_query_callback: unexpected error code %d", errorCode);
+ if (query->connection != NULL) {
+ dso_drop_activity(query->connection->dso, query->activity);
+ }
+ }
+}
+
+void
+dns_push_subscribe(comm_t *comm, dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
+ const char *activity_name, const char *opcode_name)
+{
+ int rcode;
+ dnssd_query_t *query = dp_query_generate(comm, question, true, &rcode);
+
+ if (!query) {
+ dp_simple_response(comm, rcode);
+ return;
+ }
+
+ dso_activity_t *activity = dso_add_activity(dso, activity_name, push_subscription_activity_type, query, dns_push_finalize);
+ query->activity = activity;
+ if (!dp_query_start(comm, query, &rcode, dns_push_query_callback)) {
+ dso_drop_activity(dso, activity);
+ dp_simple_response(comm, rcode);
+ return;
+ }
+ dp_simple_response(comm, dns_rcode_noerror);
+}
+
+void
+dns_push_reconfirm(comm_t *comm, dns_wire_t *header, dso_state_t *dso)
+{
+ dns_rr_t question;
+ char name[DNS_MAX_NAME_SIZE + 1];
+ uint16_t rdlen;
+
+ // The TLV offset should always be pointing into the message.
+ unsigned offp = dso->primary.payload - &header->data[0];
+ int len = offp + dso->primary.length;
+
+ // Parse the name, rrtype and class. We say there's no rdata even though there is
+ // because there's no ttl and also we want the raw rdata, not parsed rdata.
+ if (!dns_rr_parse(&question, header->data, len, &offp, false) ||
+ !dns_u16_parse(header->data, len, &offp, &rdlen)) {
+ dp_simple_response(comm, dns_rcode_formerr);
+ ERROR("dns_push_reconfirm: RR parse from %s failed", dso->remote_name);
+ return;
+ }
+ if (rdlen + offp != len) {
+ dp_simple_response(comm, dns_rcode_formerr);
+ ERROR("dns_push_reconfirm: RRdata parse from %s failed: length mismatch (%d != %d)",
+ dso->remote_name, rdlen + offp, len);
+ return;
+ }
+
+ if ((dp_served(question.name, name, sizeof name))) {
+ int len = strlen(name);
+ if (len + sizeof local_suffix > sizeof name) {
+ dp_simple_response(comm, dns_rcode_formerr);
+ ERROR("dns_push_reconfirm: name is too long for .local suffix: %s", name);
+ return;
+ }
+ memcpy(&name[len], local_suffix, sizeof local_suffix);
+ } else {
+ dns_name_print(question.name, &name[8], sizeof name - 8);
+ }
+ // transmogrify name.
+ DNSServiceReconfirmRecord(0, kDNSServiceInterfaceIndexAny, name,
+ question.type, question.qclass, rdlen, &header->data[offp]);
+ dp_simple_response(comm, dns_rcode_noerror);
+}
+
+void
+dns_push_unsubscribe(comm_t *comm, dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
+ dso_activity_t *activity, const char *opcode_name)
+{
+ dso_drop_activity(dso, activity);
+ // No response, unsubscribe is unidirectional.
+}
+
+void
+dns_push_subscription_change(const char *opcode_name, comm_t *comm, dns_wire_t *header, dso_state_t *dso)
+{
+ // type-in-hex/class-in-hex/name-to-subscribe
+ char activity_name[DNS_MAX_NAME_SIZE_ESCAPED + 3 + 4 + 4];
+ dso_activity_t *activity;
+
+ // The TLV offset should always be pointing into the message.
+ unsigned offp = dso->primary.payload - &header->data[0];
+ // Get the question
+ dns_rr_t question;
+
+ if (!dns_rr_parse(&question, header->data, offp + dso->primary.length, &offp, false)) {
+ // Unsubscribes are unidirectional, so no response can be sent
+ if (dso->primary.opcode != kDSOType_DNSPushUnsubscribe) {
+ dp_simple_response(comm, dns_rcode_formerr);
+ }
+ ERROR("RR parse for %s from %s failed", dso->remote_name, opcode_name);
+ return;
+ }
+
+ // Concoct an activity name.
+ snprintf(activity_name, sizeof activity_name, "%04x%04x", question.type, question.qclass);
+ if ((dp_served(question.name, &activity_name[8], (sizeof activity_name) - 8))) {
+ int len = strlen(activity_name);
+ if (len + sizeof local_suffix + 8 > sizeof (activity_name)) {
+ ERROR("activity name overflow for %s", activity_name);
+ return;
+ }
+ strncpy(&activity_name[len], local_suffix, sizeof local_suffix);
+ } else {
+ dns_name_print(question.name, &activity_name[8], (sizeof activity_name) - 8);
+ }
+
+ activity = dso_find_activity(dso, activity_name, push_subscription_activity_type, NULL);
+ if (activity == NULL) {
+ // Unsubscribe with no activity means no work to do; just return noerror.
+ if (dso->primary.opcode != kDSOType_DNSPushSubscribe) {
+ ERROR("dso_message: %s for %s when no subscription exists.", opcode_name, activity_name);
+ if (dso->primary.opcode == kDSOType_DNSPushReconfirm) {
+ dp_simple_response(comm, dns_rcode_noerror);
+ }
+ } else {
+ // In this case we have a push subscribe for which no subscription exists, which means we can do it.
+ dns_push_subscribe(comm, header, dso, &question, activity_name, opcode_name);
+ }
+ } else {
+ // Subscribe with a matching activity means no work to do; just return noerror.
+ if (dso->primary.opcode == kDSOType_DNSPushSubscribe) {
+ dp_simple_response(comm, dns_rcode_noerror);
+ }
+ // Otherwise cancel the subscription.
+ else {
+ dns_push_unsubscribe(comm, header, dso, &question, activity, opcode_name);
+ }
+ }
+}
+
+static void dso_message(comm_t *comm, dns_wire_t *header, dso_state_t *dso)
+{
+ switch(dso->primary.opcode) {
+ case kDSOType_DNSPushSubscribe:
+ dns_push_subscription_change("DNS Push Subscribe", comm, header, dso);
+ break;
+ case kDSOType_DNSPushUnsubscribe:
+ dns_push_subscription_change("DNS Push Unsubscribe", comm, header, dso);
+ break;
+
+ case kDSOType_DNSPushReconfirm:
+ dns_push_reconfirm(comm, header, dso);
+ break;
+
+ case kDSOType_DNSPushUpdate:
+ INFO("dso_message: bogus push update message %d", dso->primary.opcode);
+ dso_drop(dso);
+ break;
+
+ default:
+ INFO("dso_message: unexpected primary TLV %d", dso->primary.opcode);
+ dp_simple_response(comm, dns_rcode_dsotypeni);
+ break;
+ }
+ // XXX free the message if we didn't consume it.
+}
+
+static void dns_push_callback(void *context, void *header_context,
+ dso_state_t *dso, dso_event_type_t eventType)
+{
+ dns_wire_t *header = header_context;
+ switch(eventType)
+ {
+ case kDSOEventType_DNSMessage:
+ // We shouldn't get here because we already handled any DNS messages
+ INFO("dns_push_callback: DNS Message (opcode=%d) received from %s", dns_opcode_get(header), dso->remote_name);
+ break;
+ case kDSOEventType_DNSResponse:
+ // We shouldn't get here because we already handled any DNS messages
+ INFO("dns_push_callback: DNS Response (opcode=%d) received from %s", dns_opcode_get(header), dso->remote_name);
+ break;
+ case kDSOEventType_DSOMessage:
+ INFO("dns_push_callback: DSO Message (Primary TLV=%d) received from %s",
+ dso->primary.opcode, dso->remote_name);
+ dso_message((comm_t *)context, (dns_wire_t *)header, dso);
+ break;
+ case kDSOEventType_DSOResponse:
+ INFO("dns_push_callback: DSO Response (Primary TLV=%d) received from %s",
+ dso->primary.opcode, dso->remote_name);
+ break;
+
+ case kDSOEventType_Finalize:
+ INFO("dns_push_callback: Finalize");
+ break;
+
+ case kDSOEventType_Connected:
+ INFO("dns_push_callback: Connected to %s", dso->remote_name);
+ break;
+
+ case kDSOEventType_ConnectFailed:
+ INFO("dns_push_callback: Connection to %s failed", dso->remote_name);
+ break;
+
+ case kDSOEventType_Disconnected:
+ INFO("dns_push_callback: Connection to %s disconnected", dso->remote_name);
+ break;
+ }
+}
+
+void
+dp_dns_query(comm_t *comm, dns_rr_t *question)
+{
+ int rcode;
+ dnssd_query_t *query = dp_query_generate(comm, question, false, &rcode);
+ const char *failnote = NULL;
+ if (!query) {
+ dp_simple_response(comm, rcode);
+ return;
+ }
+
+ // For regular DNS queries, copy the ID, etc.
+ query->response.id = comm->message->wire.id;
+ query->response.bitfield = comm->message->wire.bitfield;
+ dns_rcode_set(&query->response, dns_rcode_noerror);
+
+ // For DNS queries, we need to return the question.
+ query->response.qdcount = htons(1);
+ if (query->enclosing_domain != NULL) {
+ TOWIRE_CHECK("name", &query->towire, dns_name_to_wire(NULL, &query->towire, query->name));
+ TOWIRE_CHECK("enclosing_domain", &query->towire,
+ dns_full_name_to_wire(&query->enclosing_domain_pointer,
+ &query->towire, query->enclosing_domain));
+ } else {
+ TOWIRE_CHECK("full name", &query->towire, dns_full_name_to_wire(NULL, &query->towire, query->name));
+ }
+ TOWIRE_CHECK("TYPE", &query->towire, dns_u16_to_wire(&query->towire, question->type)); // TYPE
+ TOWIRE_CHECK("CLASS", &query->towire, dns_u16_to_wire(&query->towire, question->qclass)); // CLASS
+ if (failnote != NULL) {
+ ERROR("dp_dns_query: failure encoding question: %s", failnote);
+ goto fail;
+ }
+
+ // We should check for OPT RR, but for now assume it's there.
+ query->is_edns0 = true;
+
+ if (!dp_query_start(comm, query, &rcode, dns_query_callback)) {
+ fail:
+ dp_simple_response(comm, rcode);
+ free(query->name);
+ free(query);
+ return;
+ }
+
+ // XXX make sure that finalize frees this.
+ query->question = comm->message;
+ comm->message = NULL;
+}
+
+void dso_transport_finalize(comm_t *comm)
+{
+ dso_state_t *dso = comm->dso;
+ INFO("dso_transport_finalize: %s", dso->remote_name);
+ if (comm) {
+ ioloop_close(&comm->io);
+ }
+ free(dso);
+ comm->dso = NULL;
+}
+
+void dns_evaluate(comm_t *comm)
+{
+ dns_rr_t question;
+ unsigned offset = 0;
+
+ // Drop incoming responses--we're a server, so we only accept queries.
+ if (dns_qr_get(&comm->message->wire) == dns_qr_response) {
+ return;
+ }
+
+ // If this is a DSO message, see if we have a session yet.
+ switch(dns_opcode_get(&comm->message->wire)) {
+ case dns_opcode_dso:
+ if (!comm->tcp_stream) {
+ ERROR("DSO message received on non-tcp socket %s", comm->name);
+ dp_simple_response(comm, dns_rcode_notimp);
+ return;
+ }
+
+ if (!comm->dso) {
+ comm->dso = dso_create(true, 0, comm->name, dns_push_callback, comm, comm);
+ if (!comm->dso) {
+ ERROR("Unable to create a dso context for %s", comm->name);
+ dp_simple_response(comm, dns_rcode_servfail);
+ ioloop_close(&comm->io);
+ return;
+ }
+ comm->dso->transport_finalize = dso_transport_finalize;
+ }
+ dso_message_received(comm->dso, (uint8_t *)&comm->message->wire, comm->message->length);
+ break;
+
+ case dns_opcode_query:
+ // In theory this is permitted but it can't really be implemented because there's no way
+ // to say "here's the answer for this, and here's why that failed.
+ if (ntohs(comm->message->wire.qdcount) != 1) {
+ dp_simple_response(comm, dns_rcode_formerr);
+ return;
+ }
+ if (!dns_rr_parse(&question, comm->message->wire.data, comm->message->length, &offset, 0)) {
+ dp_simple_response(comm, dns_rcode_formerr);
+ return;
+ }
+ dp_dns_query(comm, &question);
+ dns_rrdata_free(&question);
+ break;
+
+ // No support for other opcodes yet.
+ default:
+ dp_simple_response(comm, dns_rcode_notimp);
+ break;
+ }
+}
+
+void dns_input(comm_t *comm)
+{
+ dns_evaluate(comm);
+ if (comm->message != NULL) {
+ message_free(comm->message);
+ comm->message = NULL;
+ }
+}
+
+static int
+usage(const char *progname)
+{
+ ERROR("usage: %s", progname);
+ ERROR("ex: dnssd-proxy");
+ return 1;
+}
+
+// Called whenever we get a connection.
+void
+connected(comm_t *comm)
+{
+ INFO("connection from %s", comm->name);
+ return;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int16_t port;
+ comm_t *tcp4_listener;
+ comm_t *udp4_listener;
+
+ port = htons(53);
+
+ // Read the configuration from the command line.
+ for (i = 1; i < argc; i++) {
+ return usage(argv[0]);
+ }
+
+ if (!ioloop_init()) {
+ return 1;
+ }
+
+ // Set up hardwired answers
+ dnssd_hardwired_setup();
+
+ // XXX Support IPv6!
+ tcp4_listener = setup_listener_socket(AF_INET, IPPROTO_TCP, port, "IPv4 DNS Push Listener", dns_input, connected, 0);
+ if (tcp4_listener == NULL) {
+ ERROR("TCPv4 listener: fail.");
+ return 1;
+ }
+
+ udp4_listener = setup_listener_socket(AF_INET, IPPROTO_UDP, port, "IPv4 DNS UDP Listener", dns_input, 0, 0);
+ if (udp4_listener == NULL) {
+ ERROR("UDP4 listener: fail.");
+ return 1;
+ }
+
+ do {
+ int something = 0;
+ something = ioloop_events(0);
+ INFO("dispatched %d events.", something);
+ } while (1);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* dnssd-proxy.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Discovery Proxy globals.
+ */
+
+void dp_formerr(comm_t *NONNULL comm);
+bool dp_served(dns_name_t *NONNULL name);
+void dp_query(comm_t *NONNULL comm, unsigned offset, dns_rr_t *NONNULL question);
+
+
+
--- /dev/null
+/* fromwire.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS wire-format functions.
+ *
+ * These are really simple functions for constructing DNS messages wire format.
+ * The flow is that there is a transaction structure which contains pointers to both
+ * a message output buffer and a response input buffer. The structure is initialized,
+ * and then the various wire format functions are called repeatedly to store data.
+ * If an error occurs during this process, it's okay to just keep going, because the
+ * error is recorded in the transaction; once all of the copy-in functions have been
+ * called, the error status can be checked once at the end.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "srp.h"
+#include "dns-msg.h"
+
+bool
+dns_opt_parse(dns_edns0_t *NONNULL *NULLABLE ret, dns_rr_t *rr)
+{
+ return true;
+}
+
+dns_label_t * NULLABLE
+dns_label_parse(const uint8_t *buf, unsigned mlen, unsigned *NONNULL offp)
+{
+ uint8_t llen = buf[*offp];
+ dns_label_t *rv;
+
+ // Make sure that we got the data this label claims to encompass.
+ if (*offp + llen + 1 > mlen) {
+ DEBUG("claimed length of label is too long: %u > %u.\n", *offp + llen + 1, mlen);
+ return NULL;
+ }
+
+ rv = calloc(llen + 1 - DNS_MAX_LABEL_SIZE + sizeof *rv, 1);
+ if (rv == NULL) {
+ DEBUG("memory allocation for %u byte label (%.*s) failed.\n",
+ *offp + llen + 1, *offp + llen + 1, &buf[*offp + 1]);
+ return NULL;
+ }
+
+ rv->len = llen;
+ memcpy(rv->data, &buf[*offp + 1], llen);
+ rv->data[llen] = 0; // We NUL-terminate the label for convenience
+ *offp += llen + 1;
+ return rv;
+}
+
+bool
+dns_name_parse(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *buf, unsigned len,
+ unsigned *NONNULL offp, unsigned base)
+{
+ dns_label_t *rv;
+
+ if (*offp == len) {
+ return false;
+ }
+
+ // A pointer?
+ if ((buf[*offp] & 0xC0) == 0xC0) {
+ unsigned pointer;
+ if (*offp + 2 > len) {
+ DEBUG("incomplete compression pointer: %u > %u", *offp + 2, len);
+ return false;
+ }
+ pointer = (((unsigned)buf[*offp] & 0x3f) << 8) | (unsigned)buf[*offp + 1];
+ *offp += 2;
+ if (pointer >= base) {
+ // Don't allow a pointer forward, or to a pointer we've already visited.
+ DEBUG("compression pointer points forward: %u >= %u.\n", pointer, base);
+ return false;
+ }
+ if (pointer < DNS_HEADER_SIZE) {
+ // Don't allow pointers into the header.
+ DEBUG("compression pointer points into header: %u.\n", pointer);
+ return false;
+ }
+ pointer -= DNS_HEADER_SIZE;
+ if (buf[pointer] & 0xC0) {
+ // If this is a pointer to a pointer, it's not valid.
+ DEBUG("compression pointer points into pointer: %u %02x%02x.\n", pointer,
+ buf[pointer], pointer + 1 < len ? buf[pointer + 1] : 0xFF);
+ return false;
+ }
+ if (buf[pointer] + pointer >= base || buf[pointer] + pointer >= *offp) {
+ // Possibly this isn't worth checking.
+ DEBUG("compression pointer points to something that goes past current position: %u %u\n",
+ pointer, buf[pointer]);
+ return false;
+ }
+ return dns_name_parse(ret, buf, len, &pointer, pointer);
+ }
+ // We don't support binary labels, which are historical, and at this time there are no other valid
+ // DNS label types.
+ if (buf[*offp] & 0xC0) {
+ DEBUG("invalid label type: %x\n", buf[*offp]);
+ return false;
+ }
+
+ rv = dns_label_parse(buf, len, offp);
+ if (rv == NULL) {
+ return false;
+ }
+
+ *ret = rv;
+
+ if (rv->len == 0) {
+ return true;
+ }
+ return dns_name_parse(&rv->next, buf, len, offp, base);
+}
+
+bool
+dns_u8_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint8_t *NONNULL ret)
+{
+ uint8_t rv;
+ if (*offp + 1 > len) {
+ DEBUG("dns_u8_parse: not enough room: %u > %u.\n", *offp + 1, len);
+ return false;
+ }
+
+ rv = buf[*offp];
+ *offp += 1;
+ *ret = rv;
+ return true;
+}
+
+bool
+dns_u16_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint16_t *NONNULL ret)
+{
+ uint16_t rv;
+ if (*offp + 2 > len) {
+ DEBUG("dns_u16_parse: not enough room: %u > %u.\n", *offp + 2, len);
+ return false;
+ }
+
+ rv = ((uint16_t)(buf[*offp]) << 8) | (uint16_t)(buf[*offp + 1]);
+ *offp += 2;
+ *ret = rv;
+ return true;
+}
+
+bool
+dns_u32_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint32_t *NONNULL ret)
+{
+ uint32_t rv;
+ if (*offp + 4 > len) {
+ DEBUG("dns_u32_parse: not enough room: %u > %u.\n", *offp + 4, len);
+ return false;
+ }
+
+ rv = (((uint32_t)(buf[*offp]) << 24) | ((uint32_t)(buf[*offp + 1]) << 16) |
+ ((uint32_t)(buf[*offp + 2]) << 8) | (uint32_t)(buf[*offp + 3]));
+ *offp += 4;
+ *ret = rv;
+ return true;
+}
+
+static void
+dns_name_dump(FILE *outfile, dns_label_t *name)
+{
+ char buf[DNS_MAX_NAME_SIZE_ESCAPED + 1];
+
+ dns_name_print(name, buf, sizeof buf);
+ fputs(buf, outfile);
+}
+
+static void
+dns_rrdata_dump(FILE *outfile, dns_rr_t *rr)
+{
+ int i;
+ char nbuf[80];
+ dns_txt_element_t *txt;
+
+ switch(rr->type) {
+ case dns_rrtype_key:
+ fprintf(outfile, "KEY <AC %d> <Z %d> <XT %d> <ZZ %d> <NAMTYPE %d> <ZZZZ %d> <ORY %d> %d %d ",
+ ((rr->data.key.flags & 0xC000) >> 14 & 3), ((rr->data.key.flags & 0x2000) >> 13) & 1,
+ ((rr->data.key.flags & 0x1000) >> 12) & 1, ((rr->data.key.flags & 0xC00) >> 10) & 3,
+ ((rr->data.key.flags & 0x300) >> 8) & 3, ((rr->data.key.flags & 0xF0) >> 4) & 15, rr->data.key.flags & 15,
+ rr->data.key.protocol, rr->data.key.algorithm);
+ for (i = 0; i < rr->data.key.len; i++) {
+ if (i == 0) {
+ fprintf(outfile, "%d [%02x", rr->data.key.len, rr->data.key.key[i]);
+ } else {
+ fprintf(outfile, " %02x", rr->data.key.key[i]);
+ }
+ }
+ fputc(']', outfile);
+ break;
+
+ case dns_rrtype_sig:
+ fprintf(outfile, "SIG %d %d %d %lu %lu %lu %d ",
+ rr->data.sig.type, rr->data.sig.algorithm, rr->data.sig.label,
+ (unsigned long)rr->data.sig.rrttl, (unsigned long)rr->data.sig.expiry,
+ (unsigned long)rr->data.sig.inception, rr->data.sig.key_tag);
+ dns_name_dump(outfile, rr->data.sig.signer);
+ for (i = 0; i < rr->data.sig.len; i++) {
+ if (i == 0) {
+ fprintf(outfile, "%d [%02x", rr->data.sig.len, rr->data.sig.signature[i]);
+ } else {
+ fprintf(outfile, " %02x", rr->data.sig.signature[i]);
+ }
+ }
+ fputc(']', outfile);
+ break;
+
+ case dns_rrtype_srv:
+ fprintf(outfile, "SRV %d %d %d ", rr->data.srv.priority, rr->data.srv.weight, rr->data.srv.port);
+ dns_name_dump(outfile, rr->data.ptr.name);
+ break;
+
+ case dns_rrtype_ptr:
+ fputs("PTR ", outfile);
+ dns_name_dump(outfile, rr->data.ptr.name);
+ break;
+
+ case dns_rrtype_cname:
+ fputs("CNAME ", outfile);
+ dns_name_dump(outfile, rr->data.ptr.name);
+ break;
+
+ case dns_rrtype_a:
+ fputs("A", outfile);
+ for (i = 0; i < rr->data.a.num; i++) {
+ inet_ntop(AF_INET, &rr->data.a.addrs[i], nbuf, sizeof nbuf);
+ putc(' ', outfile);
+ fputs(nbuf, outfile);
+ }
+ break;
+
+ case dns_rrtype_aaaa:
+ fputs("AAAA", outfile);
+ for (i = 0; i < rr->data.aaaa.num; i++) {
+ inet_ntop(AF_INET6, &rr->data.aaaa.addrs[i], nbuf, sizeof nbuf);
+ putc(' ', outfile);
+ fputs(nbuf, outfile);
+ }
+ break;
+
+ case dns_rrtype_txt:
+ fputs("TXT", outfile);
+ for (txt = rr->data.txt; txt; txt = txt->next) {
+ putc(' ', outfile);
+ putc('"', outfile);
+ for (i = 0; i < txt->len; i++) {
+ if (isascii(txt->data[i]) && isprint(txt->data[i])) {
+ putc(txt->data[i], outfile);
+ } else {
+ fprintf(outfile, "<%x>", txt->data[i]);
+ }
+ }
+ putc('"', outfile);
+ }
+ break;
+
+ default:
+ fprintf(outfile, "<rrtype %d>:", rr->type);
+ if (rr->data.unparsed.len == 0) {
+ fputs(" <none>", outfile);
+ } else {
+ for (i = 0; i < rr->data.unparsed.len; i++) {
+ fprintf(outfile, " %02x", rr->data.unparsed.data[i]);
+ }
+ }
+ break;
+ }
+}
+
+bool
+dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *buf, unsigned *NONNULL offp, unsigned target, unsigned rdlen, unsigned rrstart)
+{
+ uint16_t addrlen;
+ dns_txt_element_t *txt, **ptxt;
+
+ switch(rr->type) {
+ case dns_rrtype_key:
+ if (!dns_u16_parse(buf, target, offp, &rr->data.key.flags) ||
+ !dns_u8_parse(buf, target, offp, &rr->data.key.protocol) ||
+ !dns_u8_parse(buf, target, offp, &rr->data.key.algorithm)) {
+ return false;
+ }
+ rr->data.key.len = target - *offp;
+ rr->data.key.key = malloc(rr->data.key.len);
+ if (!rr->data.key.key) {
+ return false;
+ }
+ memcpy(rr->data.key.key, &buf[*offp], rr->data.key.len);
+ *offp += rr->data.key.len;
+ break;
+
+ case dns_rrtype_sig:
+ rr->data.sig.start = rrstart;
+ if (!dns_u16_parse(buf, target, offp, &rr->data.sig.type) ||
+ !dns_u8_parse(buf, target, offp, &rr->data.sig.algorithm) ||
+ !dns_u8_parse(buf, target, offp, &rr->data.sig.label) ||
+ !dns_u32_parse(buf, target, offp, &rr->data.sig.rrttl) ||
+ !dns_u32_parse(buf, target, offp, &rr->data.sig.expiry) ||
+ !dns_u32_parse(buf, target, offp, &rr->data.sig.inception) ||
+ !dns_u16_parse(buf, target, offp, &rr->data.sig.key_tag) ||
+ !dns_name_parse(&rr->data.sig.signer, buf, target, offp, *offp)) {
+ return false;
+ }
+ // The signature is what's left of the RRDATA. It covers the message up to the signature, so we
+ // remember where it starts so as to know what memory to cover to validate it.
+ rr->data.sig.len = target - *offp;
+ rr->data.sig.signature = malloc(rr->data.sig.len);
+ if (!rr->data.sig.signature) {
+ return false;
+ }
+ memcpy(rr->data.sig.signature, &buf[*offp], rr->data.sig.len);
+ *offp += rr->data.sig.len;
+ break;
+
+ case dns_rrtype_srv:
+ if (!dns_u16_parse(buf, target, offp, &rr->data.srv.priority) ||
+ !dns_u16_parse(buf, target, offp, &rr->data.srv.weight) ||
+ !dns_u16_parse(buf, target, offp, &rr->data.srv.port)) {
+ return false;
+ }
+ // This fallthrough assumes that the first element in the srv, ptr and cname structs is
+ // a pointer to a domain name.
+
+ case dns_rrtype_ptr:
+ case dns_rrtype_cname:
+ if (!dns_name_parse(&rr->data.ptr.name, buf, target, offp, *offp)) {
+ return false;
+ }
+ break;
+
+ // We assume below that the a and aaaa structures in the data union are exact aliases of
+ // each another.
+ case dns_rrtype_a:
+ addrlen = 4;
+ goto addr_parse;
+
+ case dns_rrtype_aaaa:
+ addrlen = 16;
+ addr_parse:
+ if (rdlen & (addrlen - 1)) {
+ DEBUG("dns_rdata_parse: %s rdlen not an even multiple of %u: %u",
+ addrlen == 4 ? "A" : "AAAA", addrlen, rdlen);
+ return false;
+ }
+ rr->data.a.addrs = malloc(rdlen);
+ if (rr->data.a.addrs == NULL) {
+ return false;
+ }
+ rr->data.a.num = rdlen / addrlen;
+ memcpy(rr->data.a.addrs, &buf[*offp], rdlen);
+ *offp = target;
+ break;
+
+ case dns_rrtype_txt:
+ ptxt = &rr->data.txt;
+ while (*offp < target) {
+ unsigned tlen = buf[*offp];
+ if (*offp + tlen + 1 > target) {
+ DEBUG("dns_rdata_parse: TXT RR length is larger than available space: %u %u",
+ *offp + tlen + 1, target);
+ *ptxt = NULL;
+ return false;
+ }
+ txt = malloc(tlen + 1 + sizeof *txt);
+ if (txt == NULL) {
+ DEBUG("dns_rdata_parse: no memory for TXT RR");
+ return false;
+ }
+ txt->len = tlen;
+ ++*offp;
+ memcpy(txt->data, &buf[*offp], tlen);
+ *offp += tlen;
+ txt->data[tlen] = 0;
+ *ptxt = txt;
+ ptxt = &txt->next;
+ }
+ break;
+
+ default:
+ if (rdlen > 0) {
+ rr->data.unparsed.data = malloc(rdlen);
+ if (rr->data.unparsed.data == NULL) {
+ return false;
+ }
+ memcpy(rr->data.unparsed.data, &buf[*offp], rdlen);
+ }
+ rr->data.unparsed.len = rdlen;
+ *offp = target;
+ break;
+ }
+ if (*offp != target) {
+ DEBUG("dns_rdata_parse: parse for rrtype %d not fully contained: %u %u", rr->type, target, *offp);
+ return false;
+ }
+ return true;
+}
+
+static bool
+dns_rdata_parse(dns_rr_t *NONNULL rr,
+ const uint8_t *buf, unsigned len, unsigned *NONNULL offp, unsigned rrstart)
+{
+ uint16_t rdlen;
+ unsigned target;
+
+ if (!dns_u16_parse(buf, len, offp, &rdlen)) {
+ return false;
+ }
+ target = *offp + rdlen;
+ if (target > len) {
+ return false;
+ }
+ return dns_rdata_parse_data(rr, buf, offp, target, rdlen, rrstart);
+}
+
+bool
+dns_rr_parse(dns_rr_t *NONNULL rr,
+ const uint8_t *buf, unsigned len, unsigned *NONNULL offp, bool rrdata_expected)
+{
+ int rrstart = *offp; // Needed to mark the start of the SIG RR for SIG(0).
+ memset(rr, 0, sizeof *rr);
+ if (!dns_name_parse(&rr->name, buf, len, offp, *offp)) {
+ return false;
+ }
+
+ if (!dns_u16_parse(buf, len, offp, &rr->type)) {
+ return false;
+ }
+
+ if (!dns_u16_parse(buf, len, offp, &rr->qclass)) {
+ return false;
+ }
+
+ if (rrdata_expected) {
+ if (!dns_u32_parse(buf, len, offp, &rr->ttl)) {
+ return false;
+ }
+ if (!dns_rdata_parse(rr, buf, len, offp, rrstart)) {
+ return false;
+ }
+ }
+
+ printf("rrtype: %u qclass: %u name: ", rr->type, rr->qclass);
+ dns_name_dump(stdout, rr->name);
+ if (rrdata_expected) {
+ printf(" rrdata: ");
+ dns_rrdata_dump(stdout, rr);
+ }
+ printf("\n");
+ return true;
+}
+
+void dns_name_free(dns_label_t *name)
+{
+ dns_label_t *next;
+ if (name == NULL) {
+ return;
+ }
+ next = name->next;
+ free(name);
+ return dns_name_free(next);
+}
+
+void
+dns_rrdata_free(dns_rr_t *rr)
+{
+ switch(rr->type) {
+ case dns_rrtype_key:
+ free(rr->data.key.key);
+ break;
+
+ case dns_rrtype_sig:
+ dns_name_free(rr->data.sig.signer);
+ free(rr->data.sig.signature);
+ break;
+
+ case dns_rrtype_srv:
+ case dns_rrtype_ptr:
+ case dns_rrtype_cname:
+ dns_name_free(rr->data.ptr.name);
+ rr->data.ptr.name = NULL;
+ break;
+
+ case dns_rrtype_a:
+ case dns_rrtype_aaaa:
+ free(rr->data.a.addrs);
+ rr->data.a.addrs = NULL;
+ break;
+
+ case dns_rrtype_txt:
+ default:
+ free(rr->data.unparsed.data);
+ rr->data.unparsed.data = NULL;
+ break;
+ }
+}
+
+void
+dns_message_free(dns_message_t *message)
+{
+ int i;
+
+#define FREE(count, sets) \
+ for (i = 0; i < message->count; i++) { \
+ dns_rr_t *set = &message->sets[i]; \
+ if (set->name) { \
+ dns_name_free(set->name); \
+ set->name = NULL; \
+ } \
+ dns_rrdata_free(set); \
+ } \
+ if (message->sets) { \
+ free(message->sets); \
+ }
+ FREE(qdcount, questions);
+ FREE(ancount, answers);
+ FREE(nscount, authority);
+ FREE(arcount, additional);
+#undef FREE
+}
+
+bool
+dns_wire_parse(dns_message_t *NONNULL *NULLABLE ret, dns_wire_t *message, unsigned len)
+{
+ unsigned offset = 0;
+ dns_message_t *rv = calloc(sizeof *rv, 1);
+ int i;
+
+ if (rv == NULL) {
+ return false;
+ }
+
+#define PARSE(count, sets, name, rrdata_expected) \
+ rv->count = ntohs(message->count); \
+ if (rv->count > 50) { \
+ dns_message_free(rv); \
+ return false; \
+ } \
+ \
+ if (rv->qdcount != 0) { \
+ rv->sets = calloc(sizeof *rv->sets, rv->count); \
+ if (rv->sets == NULL) { \
+ dns_message_free(rv); \
+ return false; \
+ } \
+ } \
+ \
+ for (i = 0; i < rv->count; i++) { \
+ if (!dns_rr_parse(&rv->sets[i], message->data, len, &offset, rrdata_expected)) { \
+ dns_message_free(rv); \
+ fprintf(stderr, name " %d RR parse failed.\n", i); \
+ return false; \
+ } \
+ }
+ PARSE(qdcount, questions, "question", false);
+ PARSE(ancount, answers, "answers", true);
+ PARSE(nscount, authority, "authority", true);
+ PARSE(arcount, additional, "additional", true);
+#undef PARSE
+
+ for (i = 0; i < rv->ancount; i++) {
+ // Parse EDNS(0)
+ if (rv->additional[i].type == dns_rrtype_opt) {
+ if (!dns_opt_parse(&rv->edns0, &rv->additional[i])) {
+ dns_message_free(rv);
+ return false;
+ }
+ }
+ }
+ *ret = rv;
+ return true;
+}
+
+const char *NONNULL
+dns_name_print(dns_name_t *NONNULL name, char *buf, int bufmax)
+{
+ dns_label_t *lp;
+ int ix = 0;
+ int i;
+
+ // Copy the labels in one at a time, putting a dot between each one; if there isn't room
+ // in the buffer (shouldn't be the case), copy as much as will fit, leaving room for a NUL
+ // termination.
+ for (lp = name; lp; lp = lp->next) {
+ if (ix != 0) {
+ if (ix + 2 >= bufmax) {
+ break;
+ }
+ buf[ix++] = '.';
+ }
+ for (i = 0; i < lp->len; i++) {
+ if (isascii(lp->data[i]) && isprint(lp->data[i])) {
+ if (ix + 2 >= bufmax) {
+ break;
+ }
+ buf[ix++] = lp->data[i];
+ } else {
+ if (ix + 5 >= bufmax) {
+ break;
+ }
+ buf[ix++] = '\\';
+ buf[ix++] = '0' + (lp->data[i] >> 6);
+ buf[ix++] = '0' + (lp->data[i] >> 3) & 3;
+ buf[ix++] = '0' + lp->data[i] & 3;
+ }
+ }
+ if (i != lp->len) {
+ break;
+ }
+ }
+ buf[ix++] = 0;
+ return buf;
+}
+
+bool
+labeleq(const char *label1, const char *label2, size_t len)
+{
+ int i;
+ for (i = 0; i < len; i++) {
+ if (isascii(label1[i]) && isascii(label2[i])) {
+ if (tolower(label1[i]) != tolower(label2[i])) {
+ return false;
+ }
+ }
+ else {
+ if (label1[i] != label2[i]) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool
+dns_names_equal(dns_label_t *NONNULL name1, dns_label_t *NONNULL name2)
+{
+ if (name1->len != name2->len) {
+ return false;
+ }
+ if (name1->len != 0 && !labeleq(name1->data, name2->data, name1->len) != 0) {
+ return false;
+ }
+ if (name1->next != NULL && name2->next != NULL) {
+ return dns_names_equal(name1->next, name2->next);
+ }
+ if (name1->next == NULL && name2->next == NULL) {
+ return true;
+ }
+ return false;
+}
+
+// Note that "foo.arpa" is not the same as "foo.arpa."
+bool
+dns_names_equal_text(dns_label_t *NONNULL name1, const char *NONNULL name2)
+{
+ const char *ndot;
+ ndot = strchr(name2, '.');
+ if (ndot == NULL) {
+ ndot = name2 + strlen(name2);
+ }
+ if (name1->len != ndot - name2) {
+ return false;
+ }
+ if (name1->len != 0 && !labeleq(name1->data, name2, name1->len) != 0) {
+ return false;
+ }
+ if (name1->next != NULL && *ndot == '.') {
+ return dns_names_equal_text(name1->next, ndot + 1);
+ }
+ if (name1->next == NULL && *ndot == 0) {
+ return true;
+ }
+ return false;
+}
+
+// Find the length of a name in uncompressed wire format.
+// This is in fromwire because we use it for validating signatures, and don't need it for
+// sending.
+static size_t
+dns_name_wire_length_in(dns_label_t *NONNULL name, size_t ret)
+{
+ // Root label.
+ if (name == NULL)
+ return ret;
+ return dns_name_wire_length_in(name->next, ret + name->len + 1);
+}
+
+size_t
+dns_name_wire_length(dns_label_t *NONNULL name)
+{
+ return dns_name_wire_length_in(name, 0);
+}
+
+// Copy a name we've parsed from a message out in canonical wire format so that we can
+// use it to verify a signature. As above, not actually needed for copying to a message
+// we're going to send, since in that case we want to try to compress.
+static size_t
+dns_name_to_wire_canonical_in(uint8_t *NONNULL buf, size_t max, size_t ret, dns_label_t *NONNULL name)
+{
+ INFO("dns_name_to_wire_canonical_in: buf %p max %zd ret %zd name = %p '%.*s'",
+ buf, max, ret, name, name ? name->len : 0, name ? name->data : "");
+ if (name == NULL) {
+ return ret;
+ }
+ if (max < name->len + 1) {
+ return 0;
+ }
+ *buf = name->len;
+ memcpy(buf + 1, name->data, name->len);
+ return dns_name_to_wire_canonical_in(buf + name->len + 1,
+ max - name->len - 1, ret + name->len + 1, name->next);
+}
+
+size_t
+dns_name_to_wire_canonical(uint8_t *NONNULL buf, size_t max, dns_label_t *NONNULL name)
+{
+ return dns_name_to_wire_canonical_in(buf, max, 0, name);
+}
+
+
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* dispatch.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Simple event dispatcher for DNS.
+ */
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/time.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+#include "ioloop.h"
+#include "dnssd-proxy.h"
+
+#define USE_SELECT
+#pragma mark Globals
+io_t *ios;
+int64_t ioloop_now;
+
+#ifdef USE_KQUEUE
+int kq;
+#endif
+
+int
+getipaddr(addr_t *addr, const char *p)
+{
+ if (inet_pton(AF_INET, p, &addr->sin.sin_addr)) {
+ addr->sa.sa_family = AF_INET;
+ return sizeof addr->sin;
+ } else if (inet_pton(AF_INET6, p, &addr->sin6.sin6_addr)) {
+ addr->sa.sa_family = AF_INET6;
+ return sizeof addr->sin6;
+ } else {
+ return 0;
+ }
+}
+
+int64_t
+ioloop_timenow()
+{
+ int64_t now;
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ now = (int64_t)tv.tv_sec * 1000 + (int64_t)tv.tv_usec / 1000;
+ return now;
+}
+
+message_t *
+message_allocate(size_t message_size)
+{
+ message_t *message = (message_t *)malloc(message_size + (sizeof (message_t)) - (sizeof (dns_wire_t)));
+ if (message)
+ memset(message, 0, (sizeof (message_t)) - (sizeof (dns_wire_t)));
+ return message;
+}
+
+void
+message_free(message_t *message)
+{
+ free(message);
+}
+
+void
+comm_free(comm_t *comm)
+{
+ if (comm->name) {
+ free(comm->name);
+ comm->name = NULL;
+ }
+ if (comm->message) {
+ message_free(comm->message);
+ comm->message = NULL;
+ comm->buf = NULL;
+ }
+ free(comm);
+}
+
+void
+ioloop_close(io_t *io)
+{
+ close(io->sock);
+ io->sock = -1;
+}
+
+void
+add_reader(io_t *io, io_callback_t callback, io_callback_t finalize)
+{
+ io->next = ios;
+ ios = io;
+ io->read_callback = callback;
+ io->finalize = finalize;
+#ifdef USE_SELECT
+ io->want_read = true;
+#endif
+#ifdef USE_EPOLL
+#endif
+#ifdef USE_KQUEUE
+ struct kevent ev;
+ int rv;
+ EV_SET(&ev, io->sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, io);
+ rv = kevent(kq, &ev, 1, NULL, 0, NULL);
+ if (rv < 0) {
+ ERROR("kevent add: %s", strerror(errno));
+ return;
+ }
+#endif // USE_EPOLL
+}
+
+bool
+ioloop_init(void)
+{
+ signal(SIGPIPE, SIG_IGN); // because why ever?
+#ifdef USE_KQUEUE
+ kq = kqueue();
+ if (kq < 0) {
+ ERROR("kqueue(): %s", strerror(errno));
+ return false;
+ }
+#endif
+ return true;
+}
+
+int
+ioloop_events(int64_t timeout_when)
+{
+ io_t *io, **iop;
+ int nev = 0, rv;
+ int64_t now = ioloop_timenow();
+ int64_t next_event = timeout_when;
+ int64_t timeout = 0;
+
+ INFO("%qd.%03qd seconds have passed on entry to ioloop_events", (now - ioloop_now) / 1000, (now - ioloop_now) % 1000);
+ ioloop_now = now;
+
+ // A timeout of zero means don't time out.
+ if (timeout_when == 0) {
+ next_event = INT64_MAX;
+ } else {
+ next_event = timeout_when;
+ }
+
+#ifdef USE_SELECT
+ int nfds = 0;
+ fd_set reads, writes, errors;
+ struct timeval tv;
+
+ FD_ZERO(&reads);
+ FD_ZERO(&writes);
+ FD_ZERO(&errors);
+
+#endif
+ iop = &ios;
+ while (*iop) {
+ io = *iop;
+ if (io->sock != -1 && io->wakeup_time != 0) {
+ if (io->wakeup_time <= ioloop_now) {
+ io->wakeup_time = 0;
+ io->wakeup(io);
+ ++nev;
+ } else if (io->wakeup_time < next_event) {
+ next_event = io->wakeup_time;
+ }
+ }
+
+ if (io->sock == -1) {
+ *iop = io->next;
+ if (io->finalize) {
+ io->finalize(io);
+ } else {
+ free(io);
+ }
+ continue;
+ }
+
+ // INFO("now: %qd io %d wakeup_time %qd next_event %qd", ioloop_now, io->sock, io->wakeup_time, next_event);
+
+ // If we were given a timeout in the future, or told to wait indefinitely, wait until the next event.
+ if (timeout_when == 0 || timeout_when > ioloop_now) {
+ timeout = next_event - ioloop_now;
+ // Don't choose a time so far in the future that it might overflow some math in the kernel.
+ if (timeout > IOLOOP_DAY * 100) {
+ timeout = IOLOOP_DAY * 100;
+ }
+#ifdef USE_SELECT
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+#endif
+#ifdef USE_KQUEUE
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000 * 1000;
+#endif
+ }
+ iop = &io->next;
+ }
+
+#ifdef USE_SELECT
+ for (io = ios; io; io = io->next) {
+ if (io->sock != -1 && (io->want_read || io->want_write)) {
+ if (io->sock >= nfds) {
+ nfds = io->sock + 1;
+ }
+ if (io->want_read) {
+ FD_SET(io->sock, &reads);
+ }
+ if (io->want_write) {
+ FD_SET(io->sock, &writes);
+ }
+ }
+ }
+#endif
+
+#ifdef USE_SELECT
+ INFO("waiting %ld %d seconds", tv.tv_sec, tv.tv_usec);
+ rv = select(nfds, &reads, &writes, &writes, &tv);
+ if (rv < 0) {
+ ERROR("select: %s", strerror(errno));
+ exit(1);
+ }
+ now = ioloop_timenow();
+ INFO("%qd.%03qd seconds passed waiting, got %d events", (now - ioloop_now) / 1000, (now - ioloop_now) % 1000, rv);
+ ioloop_now = now;
+ for (io = ios; io; io = io->next) {
+ if (io->sock != -1) {
+ if (FD_ISSET(io->sock, &reads)) {
+ io->read_callback(io);
+ } else if (FD_ISSET(io->sock, &writes)) {
+ io->write_callback(io);
+ }
+ }
+ }
+ nev += rv;
+#endif // USE_SELECT
+#ifdef USE_KQUEUE
+#define KEV_MAX 20
+ struct kevent evs[KEV_MAX];
+ int i, rv;
+ struct timespec ts;
+
+ INFO("waiting %qd/%qd seconds", ts.tv_sec, ts.tv_nsec);
+ do {
+ rv = kevent(kq, NULL, 0, evs, KEV_MAX, &ts);
+ now = ioloop_timenow();
+ INFO("%qd.%03qd seconds passed waiting, got %d events", (now - ioloop_now) / 1000, (now - ioloop_now) % 1000, rv);
+ ioloop_now = now;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ if (rv < 0) {
+ ERROR("kevent poll: %s", strerror(errno));
+ exit(1);
+ }
+ for (i = 0; i < nev; i++) {
+ io = evs[i].udata;
+ if (evs[i].filter == EVFILT_WRITE) {
+ io->write_callback(io);
+ } else if (evs[i].filter == EVFILT_READ) {
+ io->read_callback(io);
+ }
+ }
+ nev += rv;
+ } while (rv == KEV_MAX);
+#endif
+ return nev;
+}
+
+static void
+udp_read_callback(io_t *io)
+{
+ comm_t *connection = (comm_t *)io;
+ addr_t src;
+ int rv;
+ struct msghdr msg;
+ struct iovec bufp;
+ uint8_t msgbuf[DNS_MAX_UDP_PAYLOAD];
+ char cmsgbuf[128];
+ struct cmsghdr *cmh;
+ message_t *message;
+
+ bufp.iov_base = msgbuf;
+ bufp.iov_len = DNS_MAX_UDP_PAYLOAD;
+ msg.msg_iov = &bufp;
+ msg.msg_iovlen = 1;
+ msg.msg_name = &src;
+ msg.msg_namelen = sizeof src;
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = sizeof cmsgbuf;
+
+ rv = recvmsg(connection->io.sock, &msg, 0);
+ if (rv < 0) {
+ ERROR("udp_read_callback: %s", strerror(errno));
+ return;
+ }
+ message = message_allocate(rv);
+ if (!message) {
+ ERROR("udp_read_callback: out of memory");
+ return;
+ }
+ memcpy(&message->src, &src, sizeof src);
+ message->length = rv;
+ memcpy(&message->wire, msgbuf, rv);
+
+ // For UDP, we use the interface index as part of the validation strategy, so go get
+ // the interface index.
+ for (cmh = CMSG_FIRSTHDR(&msg); cmh; cmh = CMSG_NXTHDR(&msg, cmh)) {
+ if (cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_PKTINFO) {
+ struct in6_pktinfo pktinfo;
+
+ memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo);
+ message->ifindex = pktinfo.ipi6_ifindex;
+ } else if (cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO) {
+ struct in_pktinfo pktinfo;
+
+ memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo);
+ message->ifindex = pktinfo.ipi_ifindex;
+ }
+ }
+ connection->message = message;
+ connection->datagram_callback(connection);
+}
+
+static void
+tcp_read_callback(io_t *context)
+{
+ comm_t *connection = (comm_t *)context;
+ int rv;
+ if (connection->message_length_len < 2) {
+ rv = read(connection->io.sock, &connection->message_length_bytes[connection->message_length_len],
+ 2 - connection->message_length_len);
+ if (rv < 0) {
+ read_error:
+ ERROR("tcp_read_callback: %s", strerror(errno));
+ close(connection->io.sock);
+ connection->io.sock = -1;
+ // connection->io.finalize() will be called from the io loop.
+ return;
+ }
+ // If we read zero here, the remote endpoint has closed or shutdown the connection. Either case is
+ // effectively the same--if we are sensitive to read events, that means that we are done processing
+ // the previous message.
+ if (rv == 0) {
+ eof:
+ ERROR("tcp_read_callback: remote end (%s) closed connection on %d", connection->name, connection->io.sock);
+ close(connection->io.sock);
+ connection->io.sock = -1;
+ // connection->io.finalize() will be called from the io loop.
+ return;
+ }
+ connection->message_length_len += rv;
+ if (connection->message_length_len == 2) {
+ connection->message_length = (((uint16_t)connection->message_length_bytes[0] << 8) |
+ ((uint16_t)connection->message_length_bytes[1]));
+ }
+ return;
+ }
+
+ // If we only just got the length, we need to allocate a message
+ if (connection->message == NULL) {
+ connection->message = message_allocate(connection->message_length);
+ if (!connection->message) {
+ ERROR("udp_read_callback: out of memory");
+ return;
+ }
+ connection->buf = (uint8_t *)&connection->message->wire;
+ connection->message->length = connection->message_length;
+ memset(&connection->message->src, 0, sizeof connection->message->src);
+ }
+
+ rv = read(connection->io.sock, &connection->buf[connection->message_cur],
+ connection->message_length - connection->message_cur);
+ if (rv < 0) {
+ goto read_error;
+ }
+ if (rv == 0) {
+ goto eof;
+ }
+
+ connection->message_cur += rv;
+ if (connection->message_cur == connection->message_length) {
+ connection->datagram_callback(connection);
+ // Caller is expected to consume the message, we are immediately ready for the next read.
+ connection->message_length = connection->message_length_len = 0;
+ }
+}
+
+static void
+tcp_send_response(comm_t *comm, message_t *responding_to, struct iovec *iov, int iov_len)
+{
+ struct msghdr mh;
+ struct iovec iovec[4];
+ char lenbuf[2];
+ ssize_t status;
+ size_t payload_length = 0;
+ int i;
+
+ // We don't anticipate ever needing more than four hunks, but if we get more, handle then?
+ if (iov_len > 3) {
+ ERROR("tcp_send_response: too many io buffers");
+ close(comm->io.sock);
+ comm->io.sock = -1;
+ return;
+ }
+
+ iovec[0].iov_base = &lenbuf[0];
+ iovec[0].iov_len = 2;
+ for (i = 0; i < iov_len; i++) {
+ iovec[i + 1] = iov[i];
+ payload_length += iov[i].iov_len;
+ }
+ lenbuf[0] = payload_length / 256;
+ lenbuf[1] = payload_length & 0xff;
+ payload_length += 2;
+
+ memset(&mh, 0, sizeof mh);
+ mh.msg_iov = &iovec[0];
+ mh.msg_iovlen = iov_len + 1;
+ mh.msg_name = 0;
+
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+ status = sendmsg(comm->io.sock, &mh, MSG_NOSIGNAL);
+ if (status < 0 || status != payload_length) {
+ if (status < 0) {
+ ERROR("tcp_send_response: write failed: %s", strerror(errno));
+ } else {
+ ERROR("tcp_send_response: short write (%zd out of %zu bytes)", status, payload_length);
+ }
+ close(comm->io.sock);
+ comm->io.sock = -1;
+ }
+}
+
+static void
+udp_send_response(comm_t *comm, message_t *responding_to, struct iovec *iov, int iov_len)
+{
+ struct msghdr mh;
+ memset(&mh, 0, sizeof mh);
+ mh.msg_iov = iov;
+ mh.msg_iovlen = iov_len;
+ mh.msg_name = &responding_to->src;
+ if (responding_to->src.sa.sa_family == AF_INET) {
+ mh.msg_namelen = sizeof (struct sockaddr_in);
+ } else if (responding_to->src.sa.sa_family == AF_INET6) {
+ mh.msg_namelen = sizeof (struct sockaddr_in6);
+ } else {
+ ERROR("send_udp_response: unknown family %d", responding_to->src.sa.sa_family);
+ abort();
+ }
+ sendmsg(comm->io.sock, &mh, 0);
+}
+
+// When a communication is closed, scan the io event list to see if any other ios are referencing this one.
+void
+comm_finalize(io_t *io_in) {
+ io_t *io;
+
+ for (io = ios; io; io = io->next) {
+ if (io->cancel_on_close == io_in && io->cancel != NULL) {
+ io->cancel(io);
+ }
+ }
+}
+
+static void
+listen_callback(io_t *context)
+{
+ comm_t *listener = (comm_t *)context;
+ int rv;
+ addr_t addr;
+ socklen_t addr_len = sizeof addr;
+ comm_t *comm;
+ char addrbuf[INET6_ADDRSTRLEN + 7];
+ int addrlen;
+
+ rv = accept(listener->io.sock, &addr.sa, &addr_len);
+ if (rv < 0) {
+ ERROR("accept: %s", strerror(errno));
+ close(listener->io.sock);
+ listener->io.sock = -1;
+ return;
+ }
+ inet_ntop(addr.sa.sa_family, (addr.sa.sa_family == AF_INET
+ ? (void *)&addr.sin.sin_addr
+ : (void *)&addr.sin6.sin6_addr), addrbuf, sizeof addrbuf);
+ addrlen = strlen(addrbuf);
+ snprintf(&addrbuf[addrlen], (sizeof addrbuf) - addrlen, "%%%d",
+ (addr.sa.sa_family == AF_INET ? addr.sin.sin_port : addr.sin6.sin6_port));
+ comm = calloc(1, sizeof *comm);
+ comm->name = strdup(addrbuf);
+ comm->io.sock = rv;
+ comm->address = addr;
+ comm->datagram_callback = listener->datagram_callback;
+ comm->send_response = tcp_send_response;
+ comm->tcp_stream = true;
+
+ if (listener->connected) {
+ listener->connected(comm);
+ }
+ add_reader(&comm->io, tcp_read_callback, NULL);
+ comm->io.finalize = comm_finalize;
+
+#ifdef SO_NOSIGPIPE
+ int one = 1;
+ rv = setsockopt(comm->io.sock, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof one);
+ if (rv < 0) {
+ ERROR("SO_NOSIGPIPE failed: %s", strerror(errno));
+ }
+#endif
+}
+
+comm_t *
+setup_listener_socket(int family, int protocol, uint16_t port, const char *name,
+ comm_callback_t datagram_callback,
+ comm_callback_t connected, void *context)
+{
+ comm_t *listener;
+ socklen_t sl;
+ int rv;
+ int flag = 1;
+
+ listener = calloc(1, sizeof *listener);
+ if (listener == NULL) {
+ return NULL;
+ }
+ listener->name = strdup(name);
+ if (!listener->name) {
+ free(listener);
+ return NULL;
+ }
+ listener->io.sock = socket(family, protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, protocol);
+ if (listener->io.sock < 0) {
+ ERROR("Can't get socket: %s", strerror(errno));
+ comm_free(listener);
+ return NULL;
+ }
+ rv = setsockopt(listener->io.sock, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof flag);
+ if (rv < 0) {
+ ERROR("SO_REUSEPORT failed: %s", strerror(errno));
+ comm_free(listener);
+ return NULL;
+ }
+
+ if (family == AF_INET) {
+ sl = sizeof listener->address.sin;
+ listener->address.sin.sin_port = port ? port : htons(53);
+ } else {
+ sl = sizeof listener->address.sin6;
+ listener->address.sin6.sin6_port = port ? port : htons(53);
+ }
+ listener->address.sa.sa_family = family;
+ listener->address.sa.sa_len = sl;
+ if (bind(listener->io.sock, &listener->address.sa, sl) < 0) {
+ ERROR("Can't bind to 0#53/%s%s: %s",
+ protocol == IPPROTO_UDP ? "udp" : "tcp", family == AF_INET ? "v4" : "v6",
+ strerror(errno));
+ out:
+ close(listener->io.sock);
+ free(listener);
+ return NULL;
+ }
+
+ if (protocol == IPPROTO_TCP) {
+ if (listen(listener->io.sock, 5 /* xxx */) < 0) {
+ ERROR("Can't listen on 0#53/%s%s: %s.",
+ protocol == IPPROTO_UDP ? "udp" : "tcp", family == AF_INET ? "v4" : "v6",
+ strerror(errno));
+ goto out;
+ }
+ add_reader(&listener->io, listen_callback, NULL);
+ } else {
+ rv = setsockopt(listener->io.sock, family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
+ family == AF_INET ? IP_PKTINFO : IPV6_RECVPKTINFO, &flag, sizeof flag);
+ if (rv < 0) {
+ ERROR("Can't set %s: %s.", family == AF_INET ? "IP_PKTINFO" : "IPV6_RECVPKTINFO",
+ strerror(errno));
+ goto out;
+ }
+ add_reader(&listener->io, udp_read_callback, NULL);
+ listener->send_response = udp_send_response;
+ }
+ listener->datagram_callback = datagram_callback;
+ listener->connected = connected;
+ return listener;
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* ioloop.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ * Definitions for simple dispatch implementation.
+ */
+
+#ifndef __IOLOOP_H
+#define __IOLOOP_H
+
+#ifndef __DSO_H
+typedef struct dso_state dso_state_t;
+#endif
+
+typedef union addr addr_t;
+union addr {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+
+typedef struct message message_t;
+struct message {
+ addr_t src;
+ int ifindex;
+ size_t length;
+ dns_wire_t wire;
+};
+
+typedef struct dso_transport comm_t;
+typedef struct io io_t;
+typedef void (*io_callback_t)(io_t *NONNULL io);
+typedef void (*comm_callback_t)(comm_t *NONNULL comm);
+typedef void (*send_response_t)(comm_t *NONNULL comm, message_t *NONNULL responding_to, struct iovec *NONNULL iov, int count);
+
+#define IOLOOP_SECOND 1000LL
+#define IOLOOP_MINUTE 60 * IOLOOP_SECOND
+#define IOLOOP_HOUR 60 * IOLOOP_MINUTE
+#define IOLOOP_DAY 24 * IOLOOP_HOUR
+
+struct io {
+ io_t *NULLABLE next;
+ io_callback_t NULLABLE read_callback;
+ io_callback_t NULLABLE write_callback;
+ io_callback_t NULLABLE finalize;
+ io_callback_t NULLABLE wakeup;
+ io_callback_t NULLABLE cancel;
+ int sock;
+ int64_t wakeup_time;
+ io_t *NULLABLE cancel_on_close;
+ bool want_read : 1;
+ bool want_write : 1;
+};
+
+struct dso_transport {
+ io_t io;
+ char *NONNULL name;
+ void *NULLABLE context;
+ comm_callback_t NULLABLE datagram_callback;
+ comm_callback_t NULLABLE close_callback;
+ send_response_t NULLABLE send_response;
+ comm_callback_t NULLABLE connected;
+ message_t *NULLABLE message;
+ uint8_t *NULLABLE buf;
+ dso_state_t *NULLABLE dso;
+ addr_t address;
+ size_t message_length_len;
+ size_t message_length, message_cur;
+ uint8_t message_length_bytes[2];
+ bool tcp_stream: 1;
+};
+
+extern int64_t ioloop_now;
+int getipaddr(addr_t *NONNULL addr, const char *NONNULL p);
+int64_t ioloop_timenow(void);
+message_t *NULLABLE message_allocate(size_t message_size);
+void message_free(message_t *NONNULL message);
+void comm_free(comm_t *NONNULL comm);
+void ioloop_close(io_t *NONNULL io);
+void add_reader(io_t *NONNULL io, io_callback_t NONNULL callback, io_callback_t NULLABLE finalize);
+bool ioloop_init(void);
+int ioloop_events(int64_t timeout_when);
+comm_t *NULLABLE setup_listener_socket(int family, int protocol, uint16_t port, const char *NONNULL name,
+ comm_callback_t NONNULL datagram_callback,
+ comm_callback_t NULLABLE connected, void *NULLABLE context);
+#endif
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* keydump.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Dump the contents of a key file saved by e.g. srp-simple as a DNS key.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+int
+main(int argc, char **argv)
+{
+ const char *keyfile_name = "srp-simple.key";
+ srp_key_t *key;
+
+ key = srp_load_keypair(keyfile_name);
+ if (key == NULL) {
+ if (key == NULL) {
+ printf("Unable to load key from %s.", keyfile_name);
+ exit(1);
+ }
+ }
+
+ srp_print_key(key);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* sign.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS SIG(0) signature generation for DNSSD SRP using mbedtls.
+ *
+ * Functions required for loading, saving, and generating public/private keypairs, extracting the public key
+ * into KEY RR data, and computing signatures.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/random.h>
+#include <sys/errno.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#define SRP_CRYPTO_MBEDTLS_INTERNAL
+#include "srp-crypto.h"
+
+// For debugging
+#ifdef DEBUG_SHA256
+int
+srp_mbedtls_sha256_update_ret(mbedtls_sha256_context *sha, uint8_t *data, size_t len)
+{
+ int i;
+ fprintf(stderr, "data %lu: ", (unsigned long)len);
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%02x", data[i]);
+ }
+ fputs("\n", stderr);
+ return mbedtls_sha256_update_ret(sha, data, len);
+}
+
+int
+srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context *sha, uint8_t *hash)
+{
+ int i;
+ int status = mbedtls_sha256_finish_ret(sha, hash);
+ fprintf(stderr, "hash: ");
+ for (i = 0; i < ECDSA_SHA256_HASH_SIZE; i++) {
+ fprintf(stderr, "%02x", hash[i]);
+ }
+ fputs("\n", stderr);
+ return status;
+}
+#endif
+
+// Key is stored in an opaque data structure, for mbedtls this is an mbedtls_pk_context.
+// Function to read a public key from a KEY record
+// Function to validate a signature given some data and a public key (not required on client)
+
+// Function to free a key
+void
+srp_keypair_free(srp_key_t *key)
+{
+ mbedtls_pk_free(&key->key);
+ mbedtls_entropy_free(&key->entropy);
+ mbedtls_ctr_drbg_free(&key->ctr);
+ free(key);
+}
+
+// Needed to see the RNG with good entropy data.
+static int
+get_entropy(void *data, unsigned char *output, size_t len, size_t *outlen)
+{
+ int result = getentropy(output, len);
+ (void)data;
+
+ if (result != 0) {
+ ERROR("getentropy returned %s", strerror(errno));
+ return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+ }
+ *outlen = len;
+ return 0;
+}
+
+static srp_key_t *
+srp_key_setup(void)
+{
+ int status;
+ srp_key_t *key = calloc(sizeof *key, 1);
+ char errbuf[64];
+
+ if (key == NULL) {
+ return key;
+ }
+
+ mbedtls_pk_init(&key->key);
+ mbedtls_entropy_init(&key->entropy);
+ if ((status = mbedtls_entropy_add_source(&key->entropy, get_entropy,
+ NULL, 1, MBEDTLS_ENTROPY_SOURCE_STRONG)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_entropy_add_source failed: %s", errbuf);
+ } else if ((status = mbedtls_ctr_drbg_seed(&key->ctr, mbedtls_entropy_func, &key->entropy, NULL, 0)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_ctr_drbg_seed failed: %s", errbuf);
+ } else {
+ return key;
+ }
+ mbedtls_pk_free(&key->key);
+ mbedtls_entropy_free(&key->entropy);
+ free(key);
+ return NULL;
+}
+
+// Function to read a keypair from a file
+srp_key_t *
+srp_load_keypair(const char *file)
+{
+ int fd = open(file, O_RDONLY);
+ unsigned char buf[256];
+ ssize_t rv;
+ srp_key_t *key;
+ int status;
+ char errbuf[64];
+
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ ERROR("Unable to open srp.key: %s", strerror(errno));
+ return NULL;
+ }
+ return NULL;
+ }
+
+ // The key is of limited size, so there's no reason to get fancy.
+ rv = read(fd, buf, sizeof buf);
+ close(fd);
+ if (rv == sizeof buf) {
+ ERROR("key file is unreasonably large.");
+ return NULL;
+ }
+
+ key = srp_key_setup();
+ if (key == NULL) {
+ return NULL;
+ }
+
+ if ((status = mbedtls_pk_parse_key(&key->key, buf, rv, NULL, 0)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_pk_parse_key failed: %s", errbuf);
+ } else if (!mbedtls_pk_can_do(&key->key, MBEDTLS_PK_ECDSA)) {
+ ERROR("%s does not contain a usable ECDSA key.", file);
+ } else {
+ return key;
+ }
+ srp_keypair_free(key);
+ return NULL;
+}
+
+// Function to generate a key
+srp_key_t *
+srp_generate_key(void)
+{
+ int status;
+ char errbuf[64];
+ srp_key_t *key = srp_key_setup();
+ const mbedtls_pk_info_t *key_type = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
+
+ if (key == NULL || key_type == NULL) {
+ return NULL;
+ }
+
+ if ((status = mbedtls_pk_setup(&key->key, key_type)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_pk_setup failed: %s", errbuf);
+ } else if ((status = mbedtls_ecdsa_genkey(mbedtls_pk_ec(key->key), MBEDTLS_ECP_DP_SECP256R1,
+ mbedtls_ctr_drbg_random, &key->ctr)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_ecdsa_genkey failed: %s", errbuf);
+ } else {
+ return key;
+ }
+ srp_keypair_free(key);
+ return NULL;
+}
+
+// Function to write a keypair to a file
+int
+srp_write_key_to_file(const char *file, srp_key_t *key)
+{
+ int fd;
+ unsigned char buf[256];
+ ssize_t rv;
+ int len;
+ char errbuf[64];
+
+ len = mbedtls_pk_write_key_der(&key->key, buf, sizeof buf);
+ if (len <= 0) {
+ mbedtls_strerror(len, errbuf, sizeof errbuf);
+ ERROR("mbedtls_pk_write_key_der failed: %s", errbuf);
+ return 0;
+ }
+
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+ fd = open(file, O_CREAT | O_EXCL | O_WRONLY | O_DIRECT, 0700);
+ if (fd < 0) {
+ ERROR("Unable to create srp.key: %s", strerror(errno));
+ return 0;
+ }
+
+ rv = write(fd, &buf[sizeof buf - len], len);
+ close(fd);
+ if (rv != len) {
+ ERROR("key file write truncated.");
+ unlink(file);
+ return 0;
+ }
+
+ return 1;
+}
+
+// Function to get the length of the public key
+size_t
+srp_pubkey_length(srp_key_t *key)
+{
+ return ECDSA_KEY_SIZE;
+}
+
+int
+srp_key_algorithm(srp_key_t *key)
+{
+ return dnssec_keytype_ecdsa;
+}
+
+size_t
+srp_signature_length(srp_key_t *key)
+{
+ return ECDSA_KEY_SIZE;
+}
+
+// Function to copy out the public key as binary data
+int
+srp_pubkey_copy(uint8_t *buf, size_t max, srp_key_t *key)
+{
+ mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
+ char errbuf[64];
+ int status;
+
+ if (max < ECDSA_KEY_SIZE) {
+ return 0;
+ }
+
+ // Currently ECP only.
+ if ((status = mbedtls_mpi_write_binary(&ecp->Q.X, buf, ECDSA_KEY_PART_SIZE)) != 0 ||
+ (status = mbedtls_mpi_write_binary(&ecp->Q.Y, buf + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_mpi_write_binary: %s", errbuf);
+ return 0;
+ }
+
+#ifdef MBEDTLS_PUBKEY_DUMP
+ int i;
+ fprintf(stderr, "pubkey %d: ", ECDSA_KEY_SIZE);
+ for (i = 0; i < ECDSA_KEY_SIZE; i++) {
+ fprintf(stderr, "%02x", buf[i]);
+ }
+ putc('\n', stderr);
+#endif
+
+ return ECDSA_KEY_SIZE;
+}
+
+// Function to generate a signature given some data and a private key
+int
+srp_sign(uint8_t *output, size_t max, uint8_t *message, size_t msglen, uint8_t *rr, size_t rdlen, srp_key_t *key)
+{
+ int status;
+ unsigned char hash[ECDSA_SHA256_HASH_SIZE];
+ char errbuf[64];
+ mbedtls_sha256_context sha;
+ mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
+ mbedtls_mpi r, s;
+
+ if (max < ECDSA_SHA256_SIG_SIZE) {
+ ERROR("srp_sign: not enough space in output buffer (%lu) for signature (%d).",
+ (unsigned long)max, ECDSA_SHA256_SIG_SIZE);
+ return 0;
+ }
+
+ mbedtls_sha256_init(&sha);
+ memset(hash, 0, sizeof hash);
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_init(&s);
+
+ // Calculate the hash across first the SIG RR (minus the signature) and then the message
+ // up to but not including the SIG RR.
+ if ((status = mbedtls_sha256_starts_ret(&sha, 0)) != 0 ||
+ (status = srp_mbedtls_sha256_update_ret(&sha, rr, rdlen) != 0) ||
+ (status = srp_mbedtls_sha256_update_ret(&sha, message, msglen)) != 0 ||
+ (status = srp_mbedtls_sha256_finish_ret(&sha, hash)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_sha_256 hash failed: %s", errbuf);
+ return 0;
+ }
+
+ status = mbedtls_ecdsa_sign(&ecp->grp, &r, &s, &ecp->d, hash, sizeof hash,
+ mbedtls_ctr_drbg_random, &key->ctr);
+ if (status != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
+ return 0;
+ }
+
+ if ((status = mbedtls_mpi_write_binary(&r, output, ECDSA_SHA256_SIG_PART_SIZE)) != 0 ||
+ (status = mbedtls_mpi_write_binary(&s, output + ECDSA_SHA256_SIG_PART_SIZE,
+ ECDSA_SHA256_SIG_PART_SIZE)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
+ return 0;
+ }
+ return 1;
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* srp-key.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS SIG(0) signature generation for DNSSD SRP using mbedtls.
+ *
+ * Functions required for loading, saving, and generating public/private keypairs, extracting the public key
+ * into KEY RR data, and computing signatures.
+ */
+
+#ifndef __SRP_CRYPTO_H
+#define __SRP_CRYPTO_H
+// Anonymous key structure, depends on the target.
+typedef struct srp_key srp_key_t;
+
+#ifdef SRP_CRYPTO_MBEDTLS_INTERNAL
+#include <mbedtls/error.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/ecdsa.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/base64.h>
+
+// The SRP key includes both the ecdsa key and the pseudo-random number generator context, so that we can
+// use the PRNG for signing as well as generating keys. The PRNG is seeded with a high-entropy data source.
+// This structure assumes that we are just using this one key; if we want to support multiple keys then
+// the entropy source and PRNG should be shared by all keys (of course, that's not thread-safe, so...)
+struct srp_key {
+ mbedtls_pk_context key;
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr;
+};
+
+#ifdef DEBUG_SHA256
+int srp_mbedtls_sha256_update_ret(mbedtls_sha256_context *NONNULL sha, uint8_t *NONNULL message, size_t msglen);
+int srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context *NONNULL sha, uint8_t *NONNULL hash);
+#else
+#define srp_mbedtls_sha256_update_ret mbedtls_sha256_update_ret
+#define srp_mbedtls_sha256_finish_ret mbedtls_sha256_finish_ret
+#endif // DEBUG_SHA256
+#endif // SRP_CRYPTO_MBEDTLS_INTERNAL
+
+#define ECDSA_KEY_SIZE 64
+#define ECDSA_KEY_PART_SIZE 32
+#define ECDSA_SHA256_HASH_SIZE 32
+#define ECDSA_SHA256_SIG_SIZE 64
+#define ECDSA_SHA256_SIG_PART_SIZE 32
+
+#define SIG_HEADERLEN 11
+#define SIG_STATIC_RDLEN 18
+
+
+#define dnssec_keytype_ecdsa 13
+
+// sign_*.c:
+void srp_keypair_free(srp_key_t *NONNULL key);
+srp_key_t *NULLABLE srp_load_keypair(const char *NONNULL file);
+srp_key_t *NULLABLE srp_generate_key(void);
+int srp_write_key_to_file(const char *NONNULL file, srp_key_t *NONNULL key);
+int srp_key_algorithm(srp_key_t *NONNULL key);
+size_t srp_pubkey_length(srp_key_t *NONNULL key);
+size_t srp_signature_length(srp_key_t *NONNULL key);
+int srp_pubkey_copy(uint8_t *NONNULL buf, size_t max, srp_key_t *NONNULL key);
+int srp_sign(uint8_t *NONNULL output, size_t max,
+ uint8_t *NONNULL message, size_t msglen, uint8_t *NONNULL rdata, size_t rdlen, srp_key_t *NONNULL key);
+
+// verify_*.c:
+bool srp_sig0_verify(dns_wire_t *NONNULL message, dns_rr_t *NONNULL key, dns_rr_t *NONNULL signature);
+void srp_print_key(srp_key_t *NONNULL key);
+
+#endif // __SRP_CRYPTO_H
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* srp-gw.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * This is a DNSSD Service Registration Protocol gateway. The purpose of this is to make it possible
+ * for SRP clients to update DNS servers that don't support SRP.
+ *
+ * The way it works is that this gateway listens on port ANY:53 and forwards either to another port on
+ * the same host (not recommended) or to any port (usually 53) on a different host. Requests are accepted
+ * over both TCP and UDP in principle, but UDP requests should be from constrained nodes, and rely on
+ * network topology for authentication.
+ *
+ * Note that this is not a full DNS proxy, so you can't just put it in front of a DNS server.
+ */
+
+// Get DNS server IP address
+// Get list of permitted source subnets for TCP updates
+// Get list of permitted source subnet/interface tuples for UDP updates
+// Set up UDP listener
+// Set up TCP listener (no TCP Fast Open)
+// Event loop
+// Transaction processing:
+// 1. If UDP, validate that it's from a subnet that is valid for the interface on which it was received.
+// 2. If TCP, validate that it's from a permitted subnet
+// 3. Check that the message is a valid SRP update according to the rules
+// 4. Check the signature
+// 5. Do a DNS Update with prerequisites to prevent overwriting a host record with the same owner name but
+// a different key.
+// 6. Send back the response
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/time.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+#include "ioloop.h"
+#include "dnssd-proxy.h"
+
+#pragma mark structures
+
+typedef struct subnet subnet_t;
+struct subnet {
+ subnet_t *NULLABLE next;
+ uint8_t preflen;
+ uint8_t family;
+ char bytes[8];
+};
+
+typedef struct udp_validator udp_validator_t;
+struct udp_validator {
+ udp_validator_t *NULLABLE next;
+ char *NONNULL ifname;
+ int ifindex;
+ subnet_t *subnets;
+};
+
+static int
+usage(const char *progname)
+{
+ ERROR("usage: %s -s <addr> <port> -t <subnet> ... -u <ifname> <subnet> ...", progname);
+ ERROR(" -s can only appear once.");
+ ERROR(" -t can only appear once, and is followed by one or more subnets.");
+ ERROR(" -u can appear more than once, is followed by one interface name, and");
+ ERROR(" one or more subnets.");
+ ERROR(" <addr> is an IPv4 address or IPv6 address.");
+ ERROR(" <port> is a UDP port number.");
+ ERROR(" <subnet> is an IP address followed by a slash followed by the prefix width.");
+ ERROR(" <ifname> is the printable name of the interface.");
+ ERROR("ex: srp-gw -s 2001:DB8::1 53 -t 2001:DB8:1300::/48 -u en0 2001:DB8:1300:1100::/56");
+ return 1;
+}
+
+typedef struct delete delete_t;
+struct delete {
+ delete_t *next;
+ dns_name_t *name;
+};
+
+typedef struct dns_host_description dns_host_description_t;
+struct dns_host_description {
+ dns_name_t *name;
+ dns_rr_t *a, *aaaa, *key;
+ delete_t *delete;
+ int num_instances;
+};
+
+typedef struct service_instance service_instance_t;
+struct service_instance {
+ service_instance_t *next;
+ dns_host_description_t *host_description;
+ dns_name_t *name;
+ delete_t *delete;
+ int num_instances;
+ dns_rr_t *srv, *txt;
+};
+
+typedef struct service service_t;
+struct service {
+ service_t *next;
+ service_instance_t *instance;
+ dns_name_t *name;
+ dns_rr_t *rr;
+};
+
+bool
+srp_relay(comm_t *comm, dns_message_t *message)
+{
+ dns_name_t *update_zone;
+ bool updating_services_dot_arpa = false;
+ int i;
+ dns_host_description_t *host_description = NULL;
+ delete_t *deletes = NULL, *dp, **dpp = &deletes;
+ service_instance_t *service_instances = NULL, *sip, **sipp = &service_instances;
+ service_t *services = NULL, *sp, **spp = &services;
+ dns_rr_t *signature;
+ char namebuf[DNS_MAX_NAME_SIZE + 1], namebuf1[DNS_MAX_NAME_SIZE + 1];
+ bool ret = false;
+ struct timeval now;
+
+ // Update requires a single SOA record as the question
+ if (message->qdcount != 1) {
+ ERROR("srp_relay: update received with qdcount > 1");
+ return false;
+ }
+
+ // Update should contain zero answers.
+ if (message->ancount != 0) {
+ ERROR("srp_relay: update received with ancount > 0");
+ return false;
+ }
+
+ if (message->questions[0].type != dns_rrtype_soa) {
+ ERROR("srp_relay: update received with rrtype %d instead of SOA in question section.",
+ message->questions[0].type);
+ return false;
+ }
+ update_zone = message->questions[0].name;
+
+ // What zone are we updating?
+ if (dns_names_equal_text(update_zone, "services.arpa")) {
+ updating_services_dot_arpa = true;
+ }
+
+ // Scan over the authority RRs; do the delete consistency check. We can't do other consistency checks
+ // because we can't assume a particular order to the records other than that deletes have to come before
+ // adds.
+ for (i = 0; i < message->nscount; i++) {
+ dns_rr_t *rr = &message->authority[i];
+
+ // If this is a delete for all the RRs on a name, record it in the list of deletes.
+ if (rr->type == dns_rrtype_any && rr->qclass == dns_qclass_any && rr->ttl == 0) {
+ for (dp = deletes; dp; dp = dp->next) {
+ if (dns_names_equal(dp->name, rr->name)) {
+ ERROR("srp_relay: two deletes for the same name: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ }
+ dp = calloc(sizeof *dp, 1);
+ if (!dp) {
+ ERROR("srp_relay: no memory.");
+ goto out;
+ }
+ dp->name = rr->name;
+ *dpp = dp;
+ dpp = &dp->next;
+ }
+
+ // Otherwise if it's an A or AAAA record, it's part of a hostname entry.
+ else if (rr->type == dns_rrtype_a || rr->type == dns_rrtype_aaaa || rr->type == dns_rrtype_key) {
+ // Allocate the hostname record
+ if (!host_description) {
+ host_description = calloc(sizeof *host_description, 1);
+ if (!host_description) {
+ ERROR("srp_relay: no memory");
+ goto out;
+ }
+ }
+
+ // Make sure it's preceded by a deletion of all the RRs on the name.
+ if (!host_description->delete) {
+ for (dp = deletes; dp; dp = dp->next) {
+ if (dns_names_equal(dp->name, rr->name)) {
+ break;
+ }
+ }
+ if (dp == NULL) {
+ ERROR("srp_relay: ADD for hostname %s without a preceding delete.",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ host_description->delete = dp;
+ host_description->name = dp->name;
+ }
+
+ if (rr->type == dns_rrtype_a) {
+ if (host_description->a != NULL) {
+ ERROR("srp_relay: more than one A rrset received for name: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ host_description->a = rr;
+ } else if (rr->type == dns_rrtype_aaaa) {
+ if (host_description->aaaa != NULL) {
+ ERROR("srp_relay: more than one AAAA rrset received for name: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ host_description->aaaa = rr;
+ } else if (rr->type == dns_rrtype_key) {
+ if (host_description->key != NULL) {
+ ERROR("srp_relay: more than one KEY rrset received for name: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ host_description->key = rr;
+ }
+ }
+
+ // Otherwise if it's an SRV entry, that should be a service instance name.
+ else if (rr->type == dns_rrtype_srv || rr->type == dns_rrtype_txt) {
+ // Should be a delete that precedes this service instance.
+ for (dp = deletes; dp; dp = dp->next) {
+ if (dns_names_equal(dp->name, rr->name)) {
+ break;
+ }
+ }
+ if (dp == NULL) {
+ ERROR("srp_relay: ADD for service instance not preceded by delete: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ for (sip = service_instances; sip; sip = sip->next) {
+ if (dns_names_equal(sip->name, rr->name)) {
+ break;
+ }
+ }
+ if (!sip) {
+ sip = calloc(sizeof *sip, 1);
+ if (sip == NULL) {
+ ERROR("srp_relay: no memory");
+ goto out;
+ }
+ sip->delete = dp;
+ sip->name = dp->name;
+ *sipp = sip;
+ sipp = &sip->next;
+ }
+ if (rr->type == dns_rrtype_srv) {
+ if (sip->srv != NULL) {
+ ERROR("srp_relay: more than one SRV rr received for service instance: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ sip->srv = rr;
+ } else if (rr->type == dns_rrtype_txt) {
+ if (sip->txt != NULL) {
+ ERROR("srp_relay: more than one SRV rr received for service instance: %s",
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ }
+ sip->txt = rr;
+ }
+ }
+
+ // Otherwise if it's a PTR entry, that should be a service name
+ else if (rr->type == dns_rrtype_ptr) {
+ sp = calloc(sizeof *sp, 1);
+ if (sp == NULL) {
+ ERROR("srp_relay: no memory");
+ goto out;
+ }
+ sp->rr = rr;
+ *spp = sp;
+ spp = &sp->next;
+ }
+
+ // Otherwise it's not a valid update
+ else {
+ ERROR("srp_relay: unexpected rrtype %d on %s in update.", rr->type,
+ dns_name_print(rr->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ }
+
+ // Now that we've scanned the whole update, do the consistency checks for updates that might
+ // not have come in order.
+
+ // First, make sure there's a host description.
+ if (host_description == NULL) {
+ ERROR("srp_relay: SRP update does not include a host description.");
+ goto out;
+ }
+
+ // Make sure that each service add references a service instance that's in the same update.
+ for (sp = services; sp; sp = sp->next) {
+ for (sip = service_instances; sip; sip = sip->next) {
+ if (dns_names_equal(sip->name, sp->rr->data.ptr.name)) {
+ // Note that we have already verified that there is only one service instance
+ // with this name, so this could only ever happen once in this loop even without
+ // the break statement.
+ sp->instance = sip;
+ sip->num_instances++;
+ break;
+ }
+ }
+ // If this service doesn't point to a service instance that's in the update, then the
+ // update fails validation.
+ if (sip == NULL) {
+ ERROR("srp_relay: service %s points to an instance that's not included: %s",
+ dns_name_print(sp->name, namebuf, sizeof namebuf),
+ dns_name_print(sip->name, namebuf1, sizeof namebuf1));
+ goto out;
+ }
+ }
+
+ for (sip = service_instances; sip; sip = sip->next) {
+ // For each service instance, make sure that at least one service references it
+ if (sip->num_instances == 0) {
+ ERROR("srp_relay: service instance update for %s is not referenced by a service update.",
+ dns_name_print(sip->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+
+ // For each service instance, make sure that it references the host description
+ if (dns_names_equal(host_description->name, sip->srv->data.srv.name)) {
+ sip->host_description = host_description;
+ host_description->num_instances++;
+ }
+ }
+
+ // Make sure that at least one service instance references the host description
+ if (host_description->num_instances == 0) {
+ ERROR("srp_relay: host description %s is not referenced by any service instances.",
+ dns_name_print(host_description->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+
+ // Make sure the host description has at least one address record.
+ if (host_description->a == NULL && host_description->aaaa == NULL) {
+ ERROR("srp_relay: host description %s doesn't contain any IP addresses.",
+ dns_name_print(host_description->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+ // And make sure it has a key record
+ if (host_description->key == NULL) {
+ ERROR("srp_relay: host description %s doesn't contain a key.",
+ dns_name_print(host_description->name, namebuf, sizeof namebuf));
+ goto out;
+ }
+
+ // The signature should be the last thing in the additional section. Even if the signature
+ // is valid, if it's not at the end we reject it. Note that we are just checking for SIG(0)
+ // so if we don't find what we're looking for, we forward it to the DNS auth server which
+ // will either accept or reject it.
+ if (message->arcount < 1) {
+ ERROR("srp_relay: signature not present");
+ goto out;
+ }
+ signature = &message->additional[message->arcount -1];
+ if (signature->type != dns_rrtype_sig) {
+ ERROR("srp_relay: signature is not at the end or is not present");
+ goto out;
+ }
+
+ // Make sure that the signer name is the hostname. If it's not, it could be a legitimate
+ // update with a different key, but it's not an SRP update, so we pass it on.
+ if (!dns_names_equal(signature->data.sig.signer, host_description->name)) {
+ ERROR("srp_relay: signer %s doesn't match host %s",
+ dns_name_print(signature->data.sig.signer, namebuf, sizeof namebuf),
+ dns_name_print(host_description->name, namebuf1, sizeof namebuf1));
+ goto out;
+ }
+
+ // Make sure we're in the time limit for the signature. Zeroes for the inception and expiry times
+ // mean the host that send this doesn't have a working clock. One being zero and the other not isn't
+ // valid unless it's 1970.
+ if (signature->data.sig.inception != 0 || signature->data.sig.expiry != 0) {
+ gettimeofday(&now, NULL);
+ // The sender does the bracketing, so we can just do a simple comparison.
+ if (now.tv_sec > signature->data.sig.expiry || now.tv_sec < signature->data.sig.inception) {
+ ERROR("signature is not timely: %lu < %lu < %lu does not hold",
+ (unsigned long)signature->data.sig.inception, (unsigned long)now.tv_sec,
+ (unsigned long)signature->data.sig.expiry);
+ goto badsig;
+ }
+ }
+
+ // Now that we have the key, we can validate the signature. If the signature doesn't validate,
+ // there is no need to pass the message on.
+ if (!srp_sig0_verify(message->wire, host_description->key, signature)) {
+ ERROR("signature is not valid");
+ goto badsig;
+ }
+
+badsig:
+ // True means we consumed it, not that it was valid.
+ ret = true;
+
+out:
+ // free everything we allocated but (it turns out) aren't going to use
+ for (dp = deletes; dp; ) {
+ delete_t *next = dp->next;
+ free(dp);
+ dp = next;
+ }
+ for (sip = service_instances; sip; ) {
+ service_instance_t *next = sip->next;
+ free(sip);
+ sip = next;
+ }
+ for (sp = services; sp; ) {
+ service_t *next = sp->next;
+ free(sp);
+ sp = next;
+ }
+ if (host_description != NULL) {
+ free(host_description);
+ }
+ return ret;
+}
+
+void
+dns_evaluate(comm_t *comm)
+{
+ dns_message_t *message;
+
+ // Drop incoming responses--we're a server, so we only accept queries.
+ if (dns_qr_get(&comm->message->wire) == dns_qr_response) {
+ return;
+ }
+
+ // Forward incoming messages that are queries but not updates.
+ // XXX do this later--for now we operate only as a translator, not a proxy.
+ if (dns_opcode_get(&comm->message->wire) != dns_opcode_update) {
+ return;
+ }
+
+ // Parse the UPDATE message.
+ if (!dns_wire_parse(&message, &comm->message->wire, comm->message->length)) {
+ ERROR("dns_wire_parse failed.");
+ return;
+ }
+
+ // We need the wire message to validate the signature...
+ message->wire = &comm->message->wire;
+ if (!srp_relay(comm, message)) {
+ // The message wasn't invalid, but wasn't an SRP message.
+ // dns_forward(comm)
+ }
+ // But we don't save it.
+ message->wire = NULL;
+
+ //dns_message_free(message);
+}
+
+void dns_input(comm_t *comm)
+{
+ dns_evaluate(comm);
+ message_free(comm->message);
+ comm->message = NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ subnet_t *tcp_validators = NULL;
+ udp_validator_t *udp_validators = NULL;
+ udp_validator_t *NULLABLE *NONNULL up = &udp_validators;
+ subnet_t *NULLABLE *NONNULL nt = &tcp_validators;
+ subnet_t *NULLABLE *NONNULL sp;
+ addr_t server, pref;
+ uint16_t port;
+ socklen_t len, prefalen;
+ char *s, *p;
+ int width;
+ uint16_t listen_port;
+
+ listen_port = htons(53);
+
+ // Read the configuration from the command line.
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-s")) {
+ if (i++ == argc) {
+ ERROR("-s is missing server IP address.");
+ return usage(argv[0]);
+ }
+ len = getipaddr(&server, argv[i]);
+ if (!len) {
+ ERROR("Invalid IP address: %s.", argv[i]);
+ return usage(argv[0]);
+ }
+ server.sa.sa_len = len;
+ if (i++ == argc) {
+ ERROR("-s is missing server port.");
+ return usage(argv[0]);
+ }
+ port = strtol(argv[i], &s, 10);
+ if (s == argv[i] || s[0] != '\0') {
+ ERROR("Invalid port number: %s", argv[i]);
+ return usage(argv[0]);
+ }
+ if (server.sa.sa_family == AF_INET) {
+ server.sin.sin_port = htons(port);
+ } else {
+ server.sin6.sin6_port = htons(port);
+ }
+ i += 2;
+ } else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "-u")) {
+ if (!strcmp(argv[i], "-u")) {
+ if (i++ == argc) {
+ ERROR("-u is missing interface name.");
+ return usage(argv[0]);
+ }
+ *up = calloc(1, sizeof **up);
+ if (*up == NULL) {
+ ERROR("udp_validators: out of memory.");
+ return usage(argv[0]);
+ }
+ (*up)->ifname = strdup(argv[i]);
+ if ((*up)->ifname == NULL) {
+ ERROR("udp validators: ifname: out of memory.");
+ return usage(argv[0]);
+ }
+ sp = &((*up)->subnets);
+ } else {
+ sp = nt;
+ }
+
+ if (i++ == argc) {
+ ERROR("%s requires at least one prefix.", argv[i - 1]);
+ return usage(argv[0]);
+ }
+ s = strchr(argv[i], '/');
+ if (s == NULL) {
+ ERROR("%s is not a prefix.", argv[i]);
+ return usage(argv[0]);
+ }
+ *s = 0;
+ ++s;
+ prefalen = getipaddr(&pref, argv[i]);
+ if (!prefalen) {
+ ERROR("%s is not a valid prefix address.", argv[i]);
+ return usage(argv[0]);
+ }
+ width = strtol(s, &p, 10);
+ if (s == p || p[0] != '\0') {
+ ERROR("%s (prefix width) is not a number.", p);
+ return usage(argv[0]);
+ }
+ if (width < 0 ||
+ (pref.sa.sa_family == AF_INET && width > 32) ||
+ (pref.sa.sa_family == AF_INET6 && width > 64)) {
+ ERROR("%s is not a valid prefix length for %s", p,
+ pref.sa.sa_family == AF_INET ? "IPv4" : "IPv6");
+ return usage(argv[0]);
+ }
+
+ *nt = calloc(1, sizeof **nt);
+ if (!*nt) {
+ ERROR("tcp_validators: out of memory.");
+ return 1;
+ }
+
+ (*nt)->preflen = width;
+ (*nt)->family = pref.sa.sa_family;
+ if (pref.sa.sa_family == AF_INET) {
+ memcpy((*nt)->bytes, &pref.sin.sin_addr, 4);
+ } else {
+ memcpy((*nt)->bytes, &pref.sin6.sin6_addr, 8);
+ }
+
+ // *up will be non-null for -u and null for -t.
+ if (*up) {
+ up = &((*up)->next);
+ } else {
+ nt = sp;
+ }
+ }
+ }
+
+ if (!ioloop_init()) {
+ return 1;
+ }
+
+ // Set up listeners
+ if (!setup_listener_socket(AF_INET, IPPROTO_UDP, listen_port, "UDPv4 listener", dns_input, 0, 0)) {
+ ERROR("UDPv4 listener: fail.");
+ return 1;
+ }
+ if (!setup_listener_socket(AF_INET6, IPPROTO_UDP, listen_port, "UDPv6 listener", dns_input, 0, 0)) {
+ ERROR("UDPv6 listener: fail.");
+ return 1;
+ }
+ if (!setup_listener_socket(AF_INET, IPPROTO_TCP, listen_port, "TCPv4 listener", dns_input, 0, 0)) {
+ ERROR("TCPv4 listener: fail.");
+ return 1;
+ }
+ if (!setup_listener_socket(AF_INET6, IPPROTO_TCP, listen_port, "TCPv6 listener", dns_input, 0, 0)) {
+ ERROR("TCPv4 listener: fail.");
+ return 1;
+ }
+
+ do {
+ int something = 0;
+ something = ioloop_events(0);
+ INFO("dispatched %d events.", something);
+ } while (1);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* srp-simple.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Simple Service Registration Protocol Client
+ *
+ * This is intended for the constrained node solution for SRP. It's intended to be flexible and
+ * understandable while linking in the minimum possible support code to reduce code size. It does
+ * no mallocs, does not put anything big on the stack, and doesn't require an event loop.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+static void
+dns_response_callback(dns_transaction_t *txn)
+{
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *host_name = "thread-demo";
+ const char *zone_name = "default.service.arpa";
+ const char *host_fqdn = "thread-demo.default.service.arpa";
+ const char *service_type = "_ipps._tcp";
+ const char *a_record = "127.0.0.1";
+ const char *aaaa_record = "::1";
+ const char *txt_record = "0";
+ const char *anycast_address = "127.0.0.1";
+// const char *anycast_address = "73.186.137.119"; // cer.fugue.com
+ const char *keyfile_name = "srp-simple.key";
+ int port = 9992;
+ srp_key_t *key;
+ dns_wire_t message, response;
+ uint16_t key_tag;
+ static dns_transaction_t txn;
+ dns_towire_state_t *towire = &txn.towire;
+ dns_name_pointer_t p_host_name;
+ dns_name_pointer_t p_zone_name;
+ dns_name_pointer_t p_service_name;
+ dns_name_pointer_t p_service_instance_name;
+ int line;
+
+ key = srp_load_keypair(keyfile_name);
+ if (key == NULL) {
+ key = srp_generate_key();
+ if (key == NULL) {
+ printf("Unable to load or generate a key.");
+ exit(1);
+ }
+ if (!srp_write_key_to_file(keyfile_name, key)) {
+ printf("Unable to safe generated key.");
+ exit(1);
+ }
+ }
+
+#define CH if (towire->error) { line = __LINE__; goto fail; }
+
+ // Generate a random UUID.
+#ifdef NOTYET
+ message.id = srp_random16();
+#else
+ srandomdev();
+ message.id = (uint32_t)(random()) & 65535;
+#endif
+ message.bitfield = 0;
+ dns_qr_set(&message, dns_qr_query);
+ dns_opcode_set(&message, dns_opcode_update);
+
+ // Message data...
+ memset(&txn, 0, sizeof txn);
+ towire->p = &message.data[0]; // We start storing RR data here.
+ towire->lim = &message.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
+ towire->message = &message;
+ txn.response = &response;
+ txn.response_length = (int)(sizeof response);
+
+ message.qdcount = htons(1); // ZOCOUNT = 1
+ // Copy in Zone name (and save pointer)
+ // ZTYPE = SOA
+ // ZCLASS = IN
+ dns_full_name_to_wire(&p_zone_name, towire, zone_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_soa); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+
+ message.ancount = 0;
+ // PRCOUNT = 0
+
+ message.nscount = 0;
+ // UPCOUNT = ...
+
+ // Host Description:
+ // * Delete all RRsets from <hostname>; remember the pointer to hostname
+ // NAME = hostname label followed by pointer to SOA name.
+ // TYPE = ANY
+ // CLASS = ANY
+ // TTL = 0
+ // RDLENGTH = 0
+ dns_name_to_wire(&p_host_name, towire, host_name); CH;
+ dns_pointer_to_wire(&p_host_name, towire, &p_zone_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_any); CH;
+ dns_u16_to_wire(towire, dns_qclass_any); CH;
+ dns_ttl_to_wire(towire, 0); CH;
+ dns_u16_to_wire(towire, 0); CH;
+ message.nscount++;
+ // * Add either or both of an A or AAAA RRset, each of which contains one
+ // or more A or AAAA RRs.
+ // NAME = pointer to hostname from Delete (above)
+ // TYPE = A or AAAA
+ // CLASS = IN
+ // TTL = 3600 ?
+ // RDLENGTH = number of RRs * RR length (4 or 16)
+ // RDATA = <the data>
+ dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_a); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+ dns_ttl_to_wire(towire, 3600); CH;
+ dns_rdlength_begin(towire); CH;
+ dns_rdata_a_to_wire(towire, a_record); CH;
+ dns_rdlength_end(towire); CH;
+ message.nscount++;
+
+ dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_aaaa); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+ dns_ttl_to_wire(towire, 3600); CH;
+ dns_rdlength_begin(towire); CH;
+ dns_rdata_aaaa_to_wire(towire, aaaa_record); CH;
+ dns_rdlength_end(towire); CH;
+ message.nscount++;
+
+ // * Exactly one KEY RR:
+ // NAME = pointer to hostname from Delete (above)
+ // TYPE = KEY
+ // CLASS = IN
+ // TTL = 3600
+ // RDLENGTH = length of key + 4 (32 bits)
+ // RDATA = <flags(16) = 0000 0010 0000 0001, protocol(8) = 3, algorithm(8) = 8?, public key(variable)>
+ dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_key); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+ dns_ttl_to_wire(towire, 3600); CH;
+ dns_rdlength_begin(towire); CH;
+ key_tag = dns_rdata_key_to_wire(towire, 0, 2, 1, key); CH;
+ dns_rdlength_end(towire); CH;
+ message.nscount++;
+
+ // Service Discovery:
+ // * Update PTR RR
+ // NAME = service name (_a._b.service.arpa)
+ // TYPE = PTR
+ // CLASS = IN
+ // TTL = 3600
+ // RDLENGTH = 2
+ // RDATA = service instance name
+ dns_name_to_wire(&p_service_name, towire, service_type); CH;
+ dns_pointer_to_wire(&p_service_name, towire, &p_zone_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_ptr); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+ dns_ttl_to_wire(towire, 3600); CH;
+ dns_rdlength_begin(towire); CH;
+ dns_name_to_wire(&p_service_instance_name, towire, host_name); CH;
+ dns_pointer_to_wire(&p_service_instance_name, towire, &p_service_name); CH;
+ dns_rdlength_end(towire); CH;
+ message.nscount++;
+
+ // Service Description:
+ // * Delete all RRsets from service instance name
+ // NAME = service instance name (save pointer to service name, which is the second label)
+ // TYPE = ANY
+ // CLASS = ANY
+ // TTL = 0
+ // RDLENGTH = 0
+ dns_pointer_to_wire(NULL, towire, &p_service_instance_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_any); CH;
+ dns_u16_to_wire(towire, dns_qclass_any); CH;
+ dns_ttl_to_wire(towire, 0); CH;
+ dns_u16_to_wire(towire, 0); CH;
+ message.nscount++;
+
+ // * Add one SRV RRset pointing to Host Description
+ // NAME = pointer to service instance name from above
+ // TYPE = SRV
+ // CLASS = IN
+ // TTL = 3600
+ // RDLENGTH = 8
+ // RDATA = <priority(16) = 0, weight(16) = 0, port(16) = service port, target = pointer to hostname>
+ dns_pointer_to_wire(NULL, towire, &p_service_instance_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_srv); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+ dns_ttl_to_wire(towire, 3600); CH;
+ dns_rdlength_begin(towire); CH;
+ dns_u16_to_wire(towire, 0); // priority CH;
+ dns_u16_to_wire(towire, 0); // weight CH;
+ dns_u16_to_wire(towire, port); // port CH;
+ dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+ dns_rdlength_end(towire); CH;
+ message.nscount++;
+
+ // * Add one or more TXT records
+ // NAME = pointer to service instance name from above
+ // TYPE = TXT
+ // CLASS = IN
+ // TTL = 3600
+ // RDLENGTH = <length of text>
+ // RDATA = <text>
+ dns_pointer_to_wire(NULL, towire, &p_service_instance_name); CH;
+ dns_u16_to_wire(towire, dns_rrtype_txt); CH;
+ dns_u16_to_wire(towire, dns_qclass_in); CH;
+ dns_ttl_to_wire(towire, 3600); CH;
+ dns_rdlength_begin(towire); CH;
+ dns_rdata_txt_to_wire(towire, txt_record); CH;
+ dns_rdlength_end(towire); CH;
+ message.nscount++;
+ message.nscount = htons(message.nscount);
+
+ // What about services with more than one name? Are these multiple service descriptions?
+
+ // ARCOUNT = 2
+ // EDNS(0) options
+ // ...
+ // SIG(0)
+
+ message.arcount = htons(1);
+ dns_edns0_header_to_wire(towire, DNS_MAX_UDP_PAYLOAD, 0, 0, 1); CH; // XRCODE = 0; VERSION = 0; DO=1
+ dns_rdlength_begin(towire); CH;
+ dns_u16_to_wire(towire, dns_opt_update_lease); CH; // OPTION-CODE
+ dns_edns0_option_begin(towire); CH; // OPTION-LENGTH
+ dns_u32_to_wire(towire, 3600); CH; // LEASE (1 hour)
+ dns_u32_to_wire(towire, 604800); CH; // KEY-LEASE (7 days)
+ dns_edns0_option_end(towire); CH; // Now we know OPTION-LENGTH
+ dns_rdlength_end(towire); CH;
+
+ dns_sig0_signature_to_wire(towire, key, key_tag, &p_host_name, host_fqdn); CH;
+ // The signature is computed before counting the signature RR in the header counts.
+ message.arcount = htons(ntohs(message.arcount) + 1);
+
+ // Send the update
+ if (dns_send_to_server(&txn, anycast_address, 53, dns_response_callback) < 0) {
+ line = __LINE__;
+ fail:
+ printf("dns_send_to_server failed: %s at line %d\n", strerror(towire->error), line);
+ }
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* srp.c
+ *
+ * Service Registration Protocol Client
+ *
+ * Discover the service registration domain
+ * Construct a DNS update
+ * Include:
+ * Service Name: PTR Record
+ * Service Instance Name: SRV record
+ * Hostname: A, AAAA, KEY records
+ * Sign with key using SIG(0)
+ */
+
+int
+main(int argc, char *argv)
+{
+ char *host_name = "thread-demo";
+ char *service_type "_printer._tcp";
+ char *a_record = "127.0.0.1";
+ char *aaaa_Record = "::1";
+ int prKeyLen = 0;
+ int puKeyLen = 0;
+ uint8_t *prKey = NULL;
+ uint8_t *puKey = NULL;
+ dns_message_t *update;
+ dns_name_t *hostname;
+ dns_name_t *service_name;
+ dns_name_t *service_instance_name;
+ dns_wire_t message;
+
+ message.id = srp_random16();
+ message.bitfield = 0;
+ dns_qr_set(message, dns_qr_query);
+ dns_opcode_set(message, dns_opcode_update);
+ message.qdcount = message.ancount = message.nscount = message.arcount = 0;
+
+ update = dns_message_create();
+ tld = dns_make_fqdn(update, "services.arpa");
+ dns_update_initialize(update, tld, "2001:1::3");
+ hostname = dns_make_fqdn(update, service_name, "services.arpa.");
+ service_name = dns_make_fqdn(message, service_type, "services.arpa.");
+ service_instance_name = dns_make_fqdn(message, service_name, service_name);
+
+ // _printer._tcp.services.arpa IN PTR thread-demo._printer._tcp.services.arpa
+ // thread-demo._printer._tcp.services.arpa IN SRV 0 0 80 thread-demo.services.arpa
+ // thread-demo.services.arpa IN A 127.0.0.1
+ // IN AAAA ::1
+ // IN KEY ojwefoijweojfwoeijfoiwejfoiwejfoiejf
+
+ dns_update_add(update, hostname, dns_make_a_rr(a_record));
+ dns_update_add(update, hostname, dns_make_a_rr(aaaa_record));
+ dns_update_add(update, service_instance_name, dns_make_srv_rr(0, 0, 80, hostname));
+ dns_update_add(update, service_name, dns_make_ptr_rr(service_instance_name));
+ dns_update_add(update, service_name, dns_make_key_rr(puKey, puKeyLen));
+ dns_message_to_wire(update);
+ dns_message_sign(update, prKey, prKeyLen, puKey, puKeyLen);
+ dns_message_send(update);
+ dns_message_await_response(update);
+
+ // Get the service name and type
+ // Get the hostname
+ // Get the key
+ // Discover the registration domain (not for Thread)
+ // Discover the SRP server (not for Thread)
+ // Generate the update
+ // Sign the update
+ // Send the update
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* srp.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Service Registration Protocol common definitions
+ */
+
+#ifndef __SRP_H
+#define __SRP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __clang__
+#define NULLABLE _Nullable
+#define NONNULL _Nonnull
+#else
+#define NULLABLE
+#define NONNULL
+#endif
+
+#define ERROR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+#define INFO(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+#define DEBUG(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+
+typedef struct srp_key srp_key_t;
+#endif
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* wire.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS wire-format functions.
+ *
+ * These are really simple functions for constructing DNS messages wire format.
+ * The flow is that there is a transaction structure which contains pointers to both
+ * a message output buffer and a response input buffer. The structure is initialized,
+ * and then the various wire format functions are called repeatedly to store data.
+ * If an error occurs during this process, it's okay to just keep going, because the
+ * error is recorded in the transaction; once all of the copy-in functions have been
+ * called, the error status can be checked once at the end.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+#ifndef NO_CLOCK
+#include <sys/time.h>
+#endif
+
+// Convert a name to wire format. Does not store the root label (0) at the end. Does not support binary labels.
+void
+dns_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+ dns_towire_state_t *NONNULL txn,
+ const char *NONNULL name)
+{
+ const char *next, *cur, *end;
+ dns_name_pointer_t np;
+ if (!txn->error) {
+ memset(&np, 0, sizeof np);
+ np.message_start = (u_int8_t *)txn->message;
+ np.name_start = txn->p;
+
+ cur = name;
+ do {
+ end = strchr(cur, '.');
+ if (end == NULL) {
+ end = cur + strlen(cur);
+ if (end == cur) {
+ break;
+ }
+ next = NULL;
+ } else {
+ if (end == cur) {
+ break;
+ }
+ next = end + 1;
+ }
+
+ // Is there no space?
+ if (txn->p + (1 + end - cur) >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+
+ // Is the label too long?
+ if (end - cur > DNS_MAX_LABEL_SIZE) {
+ txn->error = ENAMETOOLONG;
+ return;
+ }
+
+ // Store the label length
+ *txn->p++ = (uint8_t)(end - cur);
+
+ // Store the label.
+ memcpy(txn->p, cur, end - cur);
+ txn->p += (end - cur);
+ np.num_labels++;
+ np.length += 1 + (end - cur);
+
+ cur = next;
+ } while (next != NULL);
+
+ if (np.length > DNS_MAX_NAME_SIZE) {
+ txn->error = ENAMETOOLONG;
+ return;
+ }
+ if (r_pointer != NULL) {
+ *r_pointer = np;
+ }
+ }
+}
+
+// Like dns_name_to_wire, but includes the root label at the end.
+void
+dns_full_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+ dns_towire_state_t *NONNULL txn,
+ const char *NONNULL name)
+{
+ dns_name_pointer_t np;
+ if (!txn->error) {
+ memset(&np, 0, sizeof np);
+ dns_name_to_wire(&np, txn, name);
+ if (!txn->error) {
+ if (txn->p + 1 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ *txn->p++ = 0;
+ np.num_labels++;
+ np.length += 1;
+ if (np.length > DNS_MAX_NAME_SIZE) {
+ txn->error = ENAMETOOLONG;
+ return;
+ }
+ if (r_pointer) {
+ *r_pointer = np;
+ }
+ }
+ }
+}
+
+// Store a pointer to a name that's already in the message.
+void
+dns_pointer_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+ dns_towire_state_t *NONNULL txn,
+ dns_name_pointer_t *NONNULL pointer)
+{
+ if (!txn->error) {
+ u_int16_t offset = pointer->name_start - pointer->message_start;
+ if (offset > DNS_MAX_POINTER) {
+ txn->error = ETOOMANYREFS;
+ return;
+ }
+ if (txn->p + 2 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ *txn->p++ = 0xc0 | (offset >> 8);
+ *txn->p++ = offset & 0xff;
+ if (r_pointer) {
+ r_pointer->num_labels += pointer->num_labels;
+ r_pointer->length += pointer->length + 1;
+ if (r_pointer->length > DNS_MAX_NAME_SIZE) {
+ txn->error = ENAMETOOLONG;
+ return;
+ }
+ }
+ }
+}
+
+void
+dns_u8_to_wire(dns_towire_state_t *NONNULL txn,
+ uint8_t val)
+{
+ if (!txn->error) {
+ if (txn->p + 1 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ *txn->p++ = val;
+ }
+}
+
+// Store a 16-bit integer in network byte order
+void
+dns_u16_to_wire(dns_towire_state_t *NONNULL txn,
+ uint16_t val)
+{
+ if (!txn->error) {
+ if (txn->p + 2 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ *txn->p++ = val >> 8;
+ *txn->p++ = val & 0xff;
+ }
+}
+
+void
+dns_u32_to_wire(dns_towire_state_t *NONNULL txn,
+ uint32_t val)
+{
+ if (!txn->error) {
+ if (txn->p + 4 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ *txn->p++ = val >> 24;
+ *txn->p++ = (val >> 16) & 0xff;
+ *txn->p++ = (val >> 8) & 0xff;
+ *txn->p++ = val & 0xff;
+ }
+}
+
+void
+dns_ttl_to_wire(dns_towire_state_t *NONNULL txn,
+ int32_t val)
+{
+ if (!txn->error) {
+ if (val < 0) {
+ txn->error = EINVAL;
+ return;
+ }
+ dns_u32_to_wire(txn, (uint32_t)val);
+ }
+}
+
+void
+dns_rdlength_begin(dns_towire_state_t *NONNULL txn)
+{
+ if (!txn->error) {
+ if (txn->p + 2 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ if (txn->p_rdlength != NULL) {
+ txn->error = EINVAL;
+ return;
+ }
+ txn->p_rdlength = txn->p;
+ txn->p += 2;
+ }
+}
+
+void
+dns_rdlength_end(dns_towire_state_t *NONNULL txn)
+{
+ int rdlength;
+ if (!txn->error) {
+ if (txn->p_rdlength == NULL) {
+ txn->error = EINVAL;
+ return;
+ }
+ rdlength = txn->p - txn->p_rdlength - 2;
+ txn->p_rdlength[0] = rdlength >> 8;
+ txn->p_rdlength[1] = rdlength & 0xff;
+ txn->p_rdlength = NULL;
+ }
+}
+
+void
+dns_rdata_a_to_wire(dns_towire_state_t *NONNULL txn,
+ const char *NONNULL ip_address)
+{
+ if (!txn->error) {
+ if (txn->p + 4 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ if (!inet_pton(AF_INET, ip_address, txn->p)) {
+ txn->error = EINVAL;
+ }
+ txn->p += 4;
+ }
+}
+
+void
+dns_rdata_aaaa_to_wire(dns_towire_state_t *NONNULL txn,
+ const char *NONNULL ip_address)
+{
+ if (!txn->error) {
+ if (txn->p + 16 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ if (!inet_pton(AF_INET6, ip_address, txn->p)) {
+ txn->error = EINVAL;
+ }
+ txn->p += 16;
+ }
+}
+
+uint16_t
+dns_rdata_key_to_wire(dns_towire_state_t *NONNULL txn,
+ unsigned key_type,
+ unsigned name_type,
+ unsigned signatory,
+ srp_key_t *key)
+{
+ int key_len = srp_pubkey_length(key);
+ uint8_t *rdata = txn->p;
+ uint32_t key_tag;
+ int i, rdlen;
+
+ if (!txn->error) {
+ if (key_type > 3 || name_type > 3 || signatory > 15) {
+ txn->error = EINVAL;
+ return 0;
+ }
+ if (txn->p + key_len + 4 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return 0;
+ }
+ *txn->p++ = (key_type << 6) | name_type;
+ *txn->p++ = signatory;
+ *txn->p++ = 3; // protocol type is always 3
+ *txn->p++ = srp_key_algorithm(key);
+ srp_pubkey_copy(txn->p, key_len, key);
+ txn->p += key_len;
+ }
+ rdlen = txn->p - rdata;
+
+ // Compute the key tag
+ key_tag = 0;
+ for (i = 0; i < rdlen; i++) {
+ key_tag += (i & 1) ? rdata[i] : rdata[i] << 8;
+ }
+ key_tag += (key_tag >> 16) & 0xFFFF;
+ return (uint16_t)(key_tag & 0xFFFF);
+}
+
+void
+dns_rdata_txt_to_wire(dns_towire_state_t *NONNULL txn,
+ const char *NONNULL txt_record)
+{
+ if (!txn->error) {
+ unsigned len = strlen(txt_record);
+ if (txn->p + len + 1 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ if (len > 255) {
+ txn->error = ENAMETOOLONG;
+ return;
+ }
+ *txn->p++ = (u_int8_t)len;
+ memcpy(txn->p, txt_record, len);
+ txn->p += len;
+ }
+}
+
+void
+dns_rdata_raw_data_to_wire(dns_towire_state_t *NONNULL txn, const void *NONNULL raw_data, size_t length)
+{
+ if (!txn->error) {
+ if (txn->p + length >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ memcpy(txn->p, raw_data, length);
+ txn->p += length;
+ }
+}
+
+void
+dns_edns0_header_to_wire(dns_towire_state_t *NONNULL txn,
+ int mtu,
+ int xrcode,
+ int version,
+ int DO)
+{
+ if (!txn->error) {
+ if (txn->p + 9 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ *txn->p++ = 0; // root label
+ dns_u16_to_wire(txn, dns_rrtype_opt);
+ dns_u16_to_wire(txn, mtu);
+ *txn->p++ = xrcode;
+ *txn->p++ = version;
+ *txn->p++ = DO << 7; // flags (usb)
+ *txn->p++ = 0; // flags (lsb, mbz)
+ }
+}
+
+void
+dns_edns0_option_begin(dns_towire_state_t *NONNULL txn)
+{
+ if (!txn->error) {
+ if (txn->p + 2 >= txn->lim) {
+ txn->error = ENOBUFS;
+ return;
+ }
+ if (txn->p_opt != NULL) {
+ txn->error = EINVAL;
+ return;
+ }
+ txn->p_opt = txn->p;
+ txn->p += 2;
+ }
+}
+
+void
+dns_edns0_option_end(dns_towire_state_t *NONNULL txn)
+{
+ int opt_length;
+ if (!txn->error) {
+ if (txn->p_opt == NULL) {
+ txn->error = EINVAL;
+ return;
+ }
+ opt_length = txn->p - txn->p_opt - 2;
+ txn->p_opt[0] = opt_length >> 8;
+ txn->p_opt[1] = opt_length & 0xff;
+ txn->p_opt = NULL;
+ }
+}
+
+void
+dns_sig0_signature_to_wire(dns_towire_state_t *NONNULL txn,
+ srp_key_t *key,
+ uint16_t key_tag,
+ dns_name_pointer_t *NONNULL signer,
+ const char *NONNULL signer_fqdn)
+{
+ int siglen = srp_signature_length(key);
+ uint8_t *start, *p_signer, *p_signature, *rrstart = txn->p;
+#ifndef NO_CLOCK
+ struct timeval now;
+#endif
+
+ // 1 name (root)
+ // 2 type (SIG)
+ // 2 class (0)
+ // 4 TTL (0)
+ // 18 SIG RDATA up to signer name
+ // 2 signer name (always a pointer)
+ // 29 bytes so far
+ // signature data (depends on algorithm, e.g. 64 for ECDSASHA256)
+ // so e.g. 93 bytes total
+
+ if (!txn->error) {
+ dns_u8_to_wire(txn, 0); // root label
+ dns_u16_to_wire(txn, dns_rrtype_sig);
+ dns_u16_to_wire(txn, 0); // class
+ dns_ttl_to_wire(txn, 0); // SIG RR TTL
+ dns_rdlength_begin(txn);
+ start = txn->p;
+ dns_u16_to_wire(txn, 0); // type = 0 for transaction signature
+ dns_u8_to_wire(txn, srp_key_algorithm(key));
+ dns_u8_to_wire(txn, 0); // labels field doesn't apply for transaction signature
+ dns_ttl_to_wire(txn, 0); // original ttl doesn't apply
+#ifdef NO_CLOCK
+ dns_u32_to_wire(txn, 0); // Indicate that we have no clock: set expiry and inception times to zero
+ dns_u32_to_wire(txn, 0);
+#else
+ gettimeofday(&now, NULL);
+ dns_u32_to_wire(txn, now.tv_sec + 300); // signature expiration time is five minutes from now
+ dns_u32_to_wire(txn, now.tv_sec - 300); // signature inception time, five minutes in the past
+#endif
+ dns_u16_to_wire(txn, key_tag);
+ p_signer = txn->p;
+ // We store the name in uncompressed form because that's what we have to sign
+ dns_full_name_to_wire(NULL, txn, signer_fqdn);
+ // And that means we're going to have to copy the signature back earlier in the packet.
+ p_signature = txn->p;
+
+ // Sign the message, signature RRDATA (less signature) first.
+ srp_sign(txn->p, siglen, (uint8_t *)txn->message, rrstart - (uint8_t *)txn->message,
+ start, txn->p - start, key);
+
+ // Now that it's signed, back up and store the pointer to the name, because we're trying
+ // to be as compact as possible.
+ txn->p = p_signer;
+ dns_pointer_to_wire(NULL, txn, signer); // Pointer to the owner name the key is attached to
+ // And move the signature earlier in the packet.
+ memmove(txn->p, p_signature, siglen);
+
+ txn->p += siglen;
+ dns_rdlength_end(txn);
+ }
+}
+
+int
+dns_send_to_server(dns_transaction_t *NONNULL txn,
+ const char *NONNULL anycast_address, uint16_t port,
+ dns_response_callback_t NONNULL callback)
+{
+ union {
+ struct sockaddr_storage s;
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr, from;
+ socklen_t len, fromlen;
+ ssize_t rv, datasize;
+
+ if (!txn->towire.error) {
+ memset(&addr, 0, sizeof addr);
+
+ // Try IPv4 first because IPv6 addresses are never valid IPv4 addresses
+ if (inet_pton(AF_INET, anycast_address, &addr.sin.sin_addr)) {
+ addr.sin.sin_family = AF_INET;
+ addr.sin.sin_port = htons(port);
+ len = sizeof addr.sin;
+ } else if (inet_pton(AF_INET6, anycast_address, &addr.sin6.sin6_addr)) {
+ addr.sin6.sin6_family = AF_INET6;
+ addr.sin6.sin6_port = htons(port);
+ len = sizeof addr.sin6;
+ } else {
+ txn->towire.error = EPROTONOSUPPORT;
+ return -1;
+ }
+//#ifdef HAVE_SA_LEN
+ addr.sa.sa_len = len;
+//#endif
+
+ txn->sock = socket(addr.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
+ if (txn->sock < 0) {
+ txn->towire.error = errno;
+ return -1;
+ }
+
+#if 0
+ memset(&myaddr, 0, sizeof myaddr);
+ myaddr.sin.sin_port = htons(9999);
+ myaddr.sa.sa_len = len;
+ myaddr.sa.sa_family = addr.sa.sa_family;
+ rv = bind(txn->sock, &myaddr.sa, len);
+ if (rv < 0) {
+ txn->towire.error = errno;
+ return -1;
+ }
+#endif
+
+ datasize = txn->towire.p - ((u_int8_t *)txn->towire.message);
+ rv = sendto(txn->sock, txn->towire.message, datasize, 0, &addr.sa, len);
+ if (rv < 0) {
+ txn->towire.error = errno;
+ goto out;
+ }
+ if (rv != datasize) {
+ txn->towire.error = EMSGSIZE;
+ goto out;
+ }
+ fromlen = sizeof from;
+ rv = recvfrom(txn->sock, txn->response, sizeof *txn->response, 0, &from.sa, &fromlen);
+ if (rv < 0) {
+ txn->towire.error = errno;
+ goto out;
+ }
+ txn->response_length = rv;
+ }
+out:
+ close(txn->sock);
+ txn->sock = 0;
+
+ if (txn->towire.error) {
+ return -1;
+ }
+ return 0;
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
--- /dev/null
+/* verify_mbedtls.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS SIG(0) signature verification for DNSSD SRP using mbedtls.
+ *
+ * Provides functions for generating a public key validating context based on SIG(0) KEY RR data, and
+ * validating a signature using a context generated with that public key. Currently only ECDSASHA256 is
+ * supported.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "srp.h"
+#define SRP_CRYPTO_MBEDTLS_INTERNAL
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+
+// Given a DNS message, a signature, and a public key, validate the message
+bool
+srp_sig0_verify(dns_wire_t *message, dns_rr_t *key, dns_rr_t *signature)
+{
+ mbedtls_ecp_point pubkey;
+ mbedtls_ecp_group group;
+ mbedtls_sha256_context sha;
+ int status;
+ char errbuf[128];
+ uint8_t hash[ECDSA_SHA256_HASH_SIZE];
+ mbedtls_mpi r, s;
+ uint8_t *rdata;
+ size_t rdlen;
+
+ // The key algorithm and the signature algorithm have to match or we can't validate the signature.
+ if (key->data.key.algorithm != signature->data.sig.algorithm) {
+ return false;
+ }
+
+ // Key must be the right length (DNS ECDSA KEY isn't compressed).
+ if (key->data.key.len != ECDSA_KEY_SIZE) {
+ return false;
+ }
+
+ // Currently only support ecdsa
+ if (signature->data.sig.algorithm != dnssec_keytype_ecdsa) {
+ return false;
+ }
+
+ // Make sure the signature is the right size.
+ if (signature->data.sig.len != ECDSA_SHA256_SIG_SIZE) {
+ return false;
+ }
+
+ // Take the KEY RR and turn it into a public key we can use to check the signature.
+ // Initialize the ECP group (SECP256).
+ mbedtls_ecp_point_init(&pubkey);
+ mbedtls_ecp_group_init(&group);
+ mbedtls_ecp_group_load(&group, MBEDTLS_ECP_DP_SECP256R1);
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_init(&s);
+ mbedtls_sha256_init(&sha);
+ memset(hash, 0, sizeof hash);
+
+ if ((status = mbedtls_mpi_read_binary(&pubkey.X, key->data.key.key, ECDSA_KEY_PART_SIZE)) != 0 ||
+ (status = mbedtls_mpi_read_binary(&pubkey.Y, key->data.key.key + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_mpi_read_binary: reading key: %s", errbuf);
+ }
+ mbedtls_mpi_lset(&pubkey.Z, 1);
+
+ if ((status = mbedtls_mpi_read_binary(&r, signature->data.sig.signature, ECDSA_SHA256_SIG_PART_SIZE)) != 0 ||
+ (status = mbedtls_mpi_read_binary(&s, signature->data.sig.signature + ECDSA_SHA256_SIG_PART_SIZE,
+ ECDSA_SHA256_SIG_PART_SIZE)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_mpi_read_binary: reading signature: %s", errbuf);
+ }
+
+ // The hash is across the message _before_ the SIG RR is added, so we have to decrement arcount before
+ // computing it.
+ message->arcount = htons(ntohs(message->arcount) - 1);
+
+ // And the SIG RRDATA that we hash includes the canonical version of the name, not whatever bits
+ // are in the actual wire format message, so we have to just make a copy of it.
+ rdlen = SIG_STATIC_RDLEN + dns_name_wire_length(signature->data.sig.signer);
+ rdata = malloc(rdlen);
+ if (rdata == NULL) {
+ ERROR("no memory for SIG RR canonicalization");
+ return 0;
+ }
+ memcpy(rdata, &message->data[signature->data.sig.start + SIG_HEADERLEN], SIG_STATIC_RDLEN);
+ if (!dns_name_to_wire_canonical(rdata + SIG_STATIC_RDLEN, rdlen - SIG_STATIC_RDLEN,
+ signature->data.sig.signer)) {
+ // Should never happen.
+ ERROR("dns_name_wire_length and dns_name_to_wire_canonical got different lengths!");
+ return 0;
+ }
+
+ // First compute the hash across the SIG RR, then hash the message up to the SIG RR
+ if ((status = mbedtls_sha256_starts_ret(&sha, 0)) != 0 ||
+ (status = srp_mbedtls_sha256_update_ret(&sha, rdata, rdlen)) != 0 ||
+ (status = srp_mbedtls_sha256_update_ret(&sha, (uint8_t *)message,
+ signature->data.sig.start +
+ (sizeof *message) - DNS_DATA_SIZE)) != 0 ||
+ (status = srp_mbedtls_sha256_finish_ret(&sha, hash)) != 0) {
+ // Put it back
+ message->arcount = htons(ntohs(message->arcount) + 1);
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_sha_256 hash failed: %s", errbuf);
+ return 0;
+ }
+ message->arcount = htons(ntohs(message->arcount) + 1);
+ free(rdata);
+
+ // Now check the signature against the hash
+ status = mbedtls_ecdsa_verify(&group, hash, sizeof hash, &pubkey, &r, &s);
+ if (status != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_ecdsa_verify failed: %s", errbuf);
+ return 0;
+ }
+ return 1;
+}
+
+// Function to copy out the public key as binary data
+void
+srp_print_key(srp_key_t *key)
+{
+ mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
+ char errbuf[64];
+ uint8_t buf[ECDSA_KEY_SIZE];
+ uint8_t b64buf[((ECDSA_KEY_SIZE * 4) / 3) + 6];
+ size_t b64len;
+ int status;
+
+ // Currently ECP only.
+ if ((status = mbedtls_mpi_write_binary(&ecp->Q.X, buf, ECDSA_KEY_PART_SIZE)) != 0 ||
+ (status = mbedtls_mpi_write_binary(&ecp->Q.Y, buf + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_mpi_write_binary: %s", errbuf);
+ return;
+ }
+
+ status = mbedtls_base64_encode(b64buf, sizeof b64buf, &b64len, buf, ECDSA_KEY_SIZE);
+ if (status != 0) {
+ mbedtls_strerror(status, errbuf, sizeof errbuf);
+ ERROR("mbedtls_mpi_write_binary: %s", errbuf);
+ return;
+ }
+ fputs("thread-demo.default.service.arpa. IN KEY 513 3 13 ", stdout);
+ fwrite(b64buf, b64len, 1, stdout);
+ putc('\n', stdout);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2012 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2011-2019 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.
if (func->Create)
{
mStatus err;
- ctx = mDNSPlatformMemAllocate(sizeof(AlgContext));
+ ctx = (AlgContext *) mDNSPlatformMemAllocateClear(sizeof(*ctx));
if (!ctx) return mDNSNULL;
// Create expects ctx->alg to be initialized
ctx->alg = alg;
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
#define mDNS_InstantiateInlines 1
#include "DNSCommon.h"
#include "CryptoAlg.h"
-#include "anonymous.h"
-
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
// Disable certain benign warnings with Microsoft compilers
#if (defined(_MSC_VER))
mDNSexport const mDNSInterfaceID mDNSInterface_Any = 0;
mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1;
mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
-mDNSexport const mDNSInterfaceID mDNSInterface_Unicast = (mDNSInterfaceID)-3;
-mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-4;
-mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-5;
-mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-6;
+mDNSexport const mDNSInterfaceID mDNSInterface_P2P = (mDNSInterfaceID)-3;
+mDNSexport const mDNSInterfaceID uDNSInterfaceMark = (mDNSInterfaceID)-4;
+mDNSexport const mDNSInterfaceID mDNSInterface_BLE = (mDNSInterfaceID)-5;
// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
-mDNSexport const mDNSOpaque16 SubscribeFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Subscribe, 0 } };
-mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_UnSubscribe, 0 } };
mDNSexport const mDNSOpaque64 zeroOpaque64 = { { 0 } };
mDNSexport const mDNSOpaque128 zeroOpaque128 = { { 0 } };
+extern mDNS mDNSStorage;
+
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
(addr->b[0] == 192 && addr->b[1] == 168)); // 192.168/16
}
+mDNSexport const char *DNSScopeToString(mDNSu32 scope)
+{
+ switch (scope)
+ {
+ case kScopeNone:
+ return "Unscoped";
+ case kScopeInterfaceID:
+ return "InterfaceScoped";
+ case kScopeServiceID:
+ return "ServiceScoped";
+ default:
+ return "Unknown";
+ }
+}
+
mDNSexport void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out)
{
out->l[0] = 0;
// 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"
- if (!name && type)
+ if (!name)
{
const mDNSu8 *s0 = type->c;
if (s0[0] && s0[0] < 0x40) // If legal first label (at least one character, and no more than 63)
return mStatus_NoError;
}
-mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
- const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen)
-{
- AlgContext *ctx;
- unsigned int i;
- unsigned int iterations;
- domainname lname;
- mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
- const mDNSu8 *digest;
- int digestlen;
- mDNSBool first = mDNStrue;
-
- if (DNSNameToLowerCase((domainname *)name, &lname) != mStatus_NoError)
- {
- LogMsg("NSEC3HashName: ERROR!! DNSNameToLowerCase failed");
- return mDNSNULL;
- }
-
- digest = lname.c;
- digestlen = DomainNameLength(&lname);
-
- // Note that it is "i <=". The first iteration is for digesting the name and salt.
- // The iteration count does not include that.
- iterations = swap16(nsec3->iterations);
- for (i = 0; i <= iterations; i++)
- {
- ctx = AlgCreate(DIGEST_ALG, nsec3->alg);
- if (!ctx)
- {
- LogMsg("NSEC3HashName: ERROR!! Cannot allocate context");
- return mDNSNULL;
- }
-
- AlgAdd(ctx, digest, digestlen);
- if (nsec3->saltLength)
- AlgAdd(ctx, p, nsec3->saltLength);
- if (AnonDataLen)
- AlgAdd(ctx, AnonData, AnonDataLen);
- if (first)
- {
- first = mDNSfalse;
- digest = hash;
- digestlen = AlgLength(ctx);
- }
- AlgFinal(ctx, (void *)digest, digestlen);
- AlgDestroy(ctx);
- }
- *dlen = digestlen;
- return digest;
-}
-
// Notes on UTF-8:
// 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
// 10xxxxxx is a continuation byte of a multi-byte character
rr->resrec.rrclass = kDNSClass_IN;
rr->resrec.rroriginalttl = ttl;
rr->resrec.rDNSServer = mDNSNULL;
- rr->resrec.AnonInfo = mDNSNULL;
// rr->resrec.rdlength = MUST set by client and/or in mDNS_Register_internal
// rr->resrec.rdestimate = set in mDNS_Register_internal
// rr->resrec.rdata = MUST be set by client
{
q->InterfaceID = InterfaceID;
q->flags = 0;
- q->Target = zeroAddr;
AssignDomainName(&q->qname, name);
q->qtype = qtype;
q->qclass = kDNSClass_IN;
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNSfalse;
q->SuppressUnusable = mDNSfalse;
- q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
- q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = mDNSfalse;
+ q->UseBackgroundTraffic = mDNSfalse;
q->ValidationRequired = 0;
q->ValidatingResponse = 0;
q->ProxyQuestion = 0;
- q->qnameOrig = mDNSNULL;
- q->AnonInfo = mDNSNULL;
q->pid = mDNSPlatformGetPID();
q->euid = 0;
- q->DisallowPID = mDNSfalse;
+ q->BlockedByPolicy = mDNSfalse;
q->ServiceID = -1;
q->QuestionCallback = callback;
q->QuestionContext = context;
sum = DomainNameHashValue((domainname *)rdb->data);
ptr += dlen;
len -= dlen;
+ fallthrough();
/* FALLTHROUGH */
}
// In cases where we know in advance that the names match it's especially advantageous to skip the
// SameDomainName() call because that's precisely the time when it's most expensive and least useful.
-mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSlocal mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
{
mDNSBool checkType = mDNStrue;
LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
return mDNSfalse;
}
- if (QuerySuppressed(q))
+ if (q->Suppressed)
return mDNSfalse;
if (rr->InterfaceID &&
rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
// Resource record received via unicast, the resolver group ID should match ?
- if (!rr->InterfaceID)
+ if (!isAuthRecord && !rr->InterfaceID)
{
+ if (mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
if (idr != idq) return(mDNSfalse);
return mDNSfalse;
#endif // APPLE_OSX_mDNSResponder
- if (!AnonInfoAnswersQuestion(rr, q))
- return mDNSfalse;
-
return(mDNStrue);
}
-mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSexport mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
+{
+ return SameNameRecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
+}
+
+mDNSlocal mDNSBool RecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
{
- if (!SameNameRecordAnswersQuestion(rr, q))
+ if (!SameNameRecordAnswersQuestion(rr, isAuthRecord, q))
return mDNSfalse;
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
+mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+{
+ return RecordAnswersQuestion(rr, mDNSfalse, q);
+}
+
+mDNSexport mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
+{
+ return RecordAnswersQuestion(&ar->resrec, mDNStrue, q);
+}
+
+mDNSexport mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
+{
+ return RecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
+}
+
// We have a separate function to handle LocalOnly AuthRecords because they can be created with
// a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
// multicast resource records (which has a valid InterfaceID) which can't be used to answer
// *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
// mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
// the InterfaceID in the resource record.
- //
- // mDNSInterface_Unicast does not indicate any scope and hence treat them like mDNSInterface_Any.
if (rr->InterfaceID &&
- q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_Unicast &&
- rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+ q->InterfaceID != mDNSInterface_LocalOnly &&
+ ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) ||
+ (!q->InterfaceID && rr->InterfaceID != mDNSInterface_LocalOnly))) return(mDNSfalse);
// Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
// may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
- if (!AnonInfoAnswersQuestion(rr, q))
- return mDNSfalse;
-
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
-mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
{
+ const ResourceRecord *const rr = &ar->resrec;
// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
// are handled in LocalOnlyRecordAnswersQuestion
if (LocalOnlyOrP2PInterface(rr->InterfaceID))
const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
if (idr != idq) return(mDNSfalse);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!mDNSPlatformValidRecordForInterface(ar, q->InterfaceID)) return(mDNSfalse);
+#endif
}
// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
- if (!AnonInfoAnswersQuestion(rr, q))
- return mDNSfalse;
-
return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
}
{
mDNSBool checkType = mDNStrue;
- if (QuerySuppressed(q))
+ if (q->Suppressed)
return mDNSfalse;
// For resource records created using multicast, the InterfaceIDs have to match
return end;
}
-mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
-{
- if (authInfo && authInfo->AutoTunnel)
- {
- AuthRecord hinfo;
- mDNSu8 *h = hinfo.rdatastorage.u.data;
- mDNSu16 len = 2 + m->HIHardware.c[0] + m->HISoftware.c[0];
- mDNSu8 *newptr;
- mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- AppendDomainLabel(&hinfo.namestorage, &m->hostlabel);
- AppendDomainName (&hinfo.namestorage, &authInfo->domain);
- hinfo.resrec.rroriginalttl = 0;
- mDNSPlatformMemCopy(h, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
- h += 1 + (int)h[0];
- mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
- hinfo.resrec.rdlength = len;
- hinfo.resrec.rdestimate = len;
- newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
- return newptr;
- }
- else
- return end;
-}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
// This function is called with "msg" when we receive a DNS message and needs to parse a single resource record
// pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded
-// (domainnames are expanded to 255 bytes) when stored in memory.
+// (domainnames are expanded to 256 bytes) when stored in memory.
//
// This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
// The caller can do this only if the names in the resource records are not compressed and validity of the
{
CacheRecord *const rr = &largecr->r;
mDNSu16 pktrdlength;
+ mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
if (largecr == &m->rec && m->rec.r.resrec.RecordType)
LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
rr->resrec.rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]);
rr->resrec.rrclass = (mDNSu16)(((mDNSu16)ptr[2] << 8 | ptr[3]) & kDNSClass_Mask);
rr->resrec.rroriginalttl = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
- if (rr->resrec.rroriginalttl > mDNSMaximumTTLSeconds && (mDNSs32)rr->resrec.rroriginalttl != -1)
- rr->resrec.rroriginalttl = mDNSMaximumTTLSeconds;
+ if (rr->resrec.rroriginalttl > maxttl && (mDNSs32)rr->resrec.rroriginalttl != -1)
+ rr->resrec.rroriginalttl = maxttl;
// Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
// us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
(X) == kDNSFlag0_OP_Unused3 ? "Unused3 " : \
(X) == kDNSFlag0_OP_Notify ? "Notify " : \
(X) == kDNSFlag0_OP_Update ? "Update " : \
- (X) == kDNSFlag0_OP_Subscribe? "Subscribe": \
- (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " )
+ (X) == kDNSFlag0_OP_DSO ? "DSO " : "?? " )
#define DNS_RC_Name(X) ( \
- (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
- (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" : \
- (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \
- (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \
- (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \
- (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \
- (X) == kDNSFlag1_RC_NotZone ? "NotZone" : "??" )
-
-mDNSlocal void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
+ (X) == kDNSFlag1_RC_NoErr ? "NoErr" : \
+ (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" : \
+ (X) == kDNSFlag1_RC_YXDomain ? "YXDomain" : \
+ (X) == kDNSFlag1_RC_YXRRSet ? "YXRRSet" : \
+ (X) == kDNSFlag1_RC_NXRRSet ? "NXRRSet" : \
+ (X) == kDNSFlag1_RC_NotAuth ? "NotAuth" : \
+ (X) == kDNSFlag1_RC_NotZone ? "NotZone" : \
+ (X) == kDNSFlag1_RC_DSOTypeNI ? "DSOTypeNI" : "??" )
+
+mDNSexport void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
{
va_list args;
mDNSu32 buflen, n;
(((mDNSu32)((mDNSu8 *)(PTR))[2]) << 8) | \
((mDNSu32)((mDNSu8 *)(PTR))[3])))
-mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const end, char *buffer, mDNSu32 buflen)
+mDNSlocal void DNSMessageDumpToLog(const DNSMessage *const msg, const mDNSu8 *const end)
{
- domainname *name;
- const mDNSu8 *ptr;
+ domainname *name = mDNSNULL;
+ const mDNSu8 *ptr = msg->data;
domainname nameStorage[2];
- char *dst = buffer;
- const char *const lim = &buffer[buflen];
- mDNSu32 i;
- const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
- mDNS_snprintf_add(&dst, lim, "DNS %s%s (%lu) (flags %02X%02X) RCODE: %s (%d)%s%s%s%s%s%s ID: %u:",
- DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
- (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
- (unsigned long)(end - (const mDNSu8 *)msg),
- msg->h.flags.b[0], msg->h.flags.b[1],
- DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
- msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
- (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "",
- (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "",
- (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "",
- (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "",
- (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "",
- (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "",
- mDNSVal16(msg->h.id));
-
- name = mDNSNULL;
- ptr = msg->data;
- for (i = 0; i < msg->h.numQuestions; i++)
+ char questions[512];
+ questions[0] = '\0';
+ char *questions_dst = questions;
+ const char *const questions_lim = &questions[512];
+ for (mDNSu32 i = 0; i < msg->h.numQuestions; i++)
{
mDNSu16 qtype, qclass;
qclass = ReadField16(&ptr[2]);
ptr += 4;
- mDNS_snprintf_add(&dst, lim, " %##s %s", name->c, DNSTypeString(qtype));
- if (qclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", qclass);
- mDNS_snprintf_add(&dst, lim, "?");
+ mDNS_snprintf_add(&questions_dst, questions_lim, " %##s %s", name->c, DNSTypeString(qtype));
+ if (qclass != kDNSClass_IN) mDNS_snprintf_add(&questions_dst, questions_lim, "/%u", qclass);
+ mDNS_snprintf_add(&questions_dst, questions_lim, "?");
}
- mDNS_snprintf_add(&dst, lim, " %u/%u/%u", msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals);
- for (i = 0; i < rrcount; i++)
+ char rrs[512];
+ rrs[0] = '\0';
+ char *rrs_dst = rrs;
+ const char *const rrs_lim = &rrs[512];
+ const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
+ for (mDNSu32 i = 0; i < rrcount; i++)
{
mDNSu16 rrtype, rrclass, rdlength;
mDNSu32 ttl;
if ((end - ptr) < rdlength) goto exit;
rdata = ptr;
- if (i > 0) mDNS_snprintf_add(&dst, lim, ",");
- if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&dst, lim, " %##s", name);
+ if (i > 0) mDNS_snprintf_add(&rrs_dst, rrs_lim, ",");
+ if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&rrs_dst, rrs_lim, " %##s", name);
- mDNS_snprintf_add(&dst, lim, " %s", DNSTypeString(rrtype));
- if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", rrclass);
- mDNS_snprintf_add(&dst, lim, " ");
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, " %s", DNSTypeString(rrtype));
+ if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&rrs_dst, rrs_lim, "/%u", rrclass);
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, " ");
handled = mDNSfalse;
switch (rrtype)
{
- case kDNSType_A:
- if (rdlength == 4)
- {
- mDNS_snprintf_add(&dst, lim, "%.4a", rdata);
- handled = mDNStrue;
- }
- break;
+ case kDNSType_A:
+ if (rdlength == 4)
+ {
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.4a", rdata);
+ handled = mDNStrue;
+ }
+ break;
- case kDNSType_AAAA:
- if (rdlength == 16)
- {
- mDNS_snprintf_add(&dst, lim, "%.16a", rdata);
- handled = mDNStrue;
- }
- break;
+ case kDNSType_AAAA:
+ if (rdlength == 16)
+ {
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.16a", rdata);
+ handled = mDNStrue;
+ }
+ break;
- case kDNSType_CNAME:
- ptr = getDomainName(msg, rdata, end, name);
- if (!ptr) goto exit;
+ case kDNSType_CNAME:
+ ptr = getDomainName(msg, rdata, end, name);
+ if (!ptr) goto exit;
- mDNS_snprintf_add(&dst, lim, "%##s", name);
- handled = mDNStrue;
- break;
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s", name);
+ handled = mDNStrue;
+ break;
- case kDNSType_SOA:
- {
- mDNSu32 serial, refresh, retry, expire, minimum;
- domainname *const mname = &nameStorage[0];
- domainname *const rname = &nameStorage[1];
- name = mDNSNULL;
+ case kDNSType_SOA:
+ {
+ mDNSu32 serial, refresh, retry, expire, minimum;
+ domainname *const mname = &nameStorage[0];
+ domainname *const rname = &nameStorage[1];
+ name = mDNSNULL;
- ptr = getDomainName(msg, rdata, end, mname);
- if (!ptr) goto exit;
+ ptr = getDomainName(msg, rdata, end, mname);
+ if (!ptr) goto exit;
- ptr = getDomainName(msg, ptr, end, rname);
- if (!ptr) goto exit;
+ ptr = getDomainName(msg, ptr, end, rname);
+ if (!ptr) goto exit;
- if ((end - ptr) < 20) goto exit;
- serial = ReadField32(&ptr[0]);
- refresh = ReadField32(&ptr[4]);
- retry = ReadField32(&ptr[8]);
- expire = ReadField32(&ptr[12]);
- minimum = ReadField32(&ptr[16]);
+ if ((end - ptr) < 20) goto exit;
+ serial = ReadField32(&ptr[0]);
+ refresh = ReadField32(&ptr[4]);
+ retry = ReadField32(&ptr[8]);
+ expire = ReadField32(&ptr[12]);
+ minimum = ReadField32(&ptr[16]);
- mDNS_snprintf_add(&dst, lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
- (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
+ (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
- handled = mDNStrue;
- break;
- }
+ handled = mDNStrue;
+ break;
+ }
- default:
- break;
+ default:
+ break;
}
- if (!handled) mDNS_snprintf_add(&dst, lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
- mDNS_snprintf_add(&dst, lim, " (%lu)", (unsigned long)ttl);
+ if (!handled) mDNS_snprintf_add(&rrs_dst, rrs_lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
+ mDNS_snprintf_add(&rrs_dst, rrs_lim, " (%lu)", (unsigned long)ttl);
ptr = rdata + rdlength;
}
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] DNS " PUB_S PUB_S " (%lu) (flags %02X%02X) RCODE: " PUB_S " (%d)" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S ":"
+ PRI_S " %u/%u/%u " PRI_S,
+ mDNSVal16(msg->h.id),
+ DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
+ (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
+ (unsigned long)(end - (const mDNSu8 *)msg),
+ msg->h.flags.b[0], msg->h.flags.b[1],
+ DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
+ msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
+ (msg->h.flags.b[0] & kDNSFlag0_AA) ? " AA" : "",
+ (msg->h.flags.b[0] & kDNSFlag0_TC) ? " TC" : "",
+ (msg->h.flags.b[0] & kDNSFlag0_RD) ? " RD" : "",
+ (msg->h.flags.b[1] & kDNSFlag1_RA) ? " RA" : "",
+ (msg->h.flags.b[1] & kDNSFlag1_AD) ? " AD" : "",
+ (msg->h.flags.b[1] & kDNSFlag1_CD) ? " CD" : "",
+ questions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, rrs);
+
exit:
return;
}
// Note: DumpPacket expects the packet header fields in host byte order, not network byte order
-mDNSexport void DumpPacket(mStatus status, mDNSBool sent, char *transport,
- const mDNSAddr *srcaddr, mDNSIPPort srcport,
- const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
+mDNSexport void DumpPacket(mStatus status, mDNSBool sent, const char *transport,
+ const mDNSAddr *srcaddr, mDNSIPPort srcport,const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg,
+ const mDNSu8 *const end, mDNSInterfaceID interfaceID)
{
- char buffer[512];
- char *dst = buffer;
- const char *const lim = &buffer[512];
-
- buffer[0] = '\0';
- if (!status) mDNS_snprintf_add(&dst, lim, sent ? "Sent" : "Received");
- else mDNS_snprintf_add(&dst, lim, "ERROR %d %sing", status, sent ? "Send" : "Receiv");
-
- mDNS_snprintf_add(&dst, lim, " %s DNS Message %u bytes from ", transport, (unsigned long)(end - (const mDNSu8 *)msg));
-
- if (sent) mDNS_snprintf_add(&dst, lim, "port %d", mDNSVal16(srcport));
- else mDNS_snprintf_add(&dst, lim, "%#a:%d", srcaddr, mDNSVal16(srcport));
-
- if (dstaddr || !mDNSIPPortIsZero(dstport)) mDNS_snprintf_add(&dst, lim, " to %#a:%d", dstaddr, mDNSVal16(dstport));
-
- LogInfo("%s", buffer);
-
- buffer[0] = '\0';
- DNSMessageDump(msg, end, buffer, (mDNSu32)sizeof(buffer));
- LogInfo("%s", buffer);
+ const mDNSAddr zeroIPv4Addr = { mDNSAddrType_IPv4, {{{ 0 }}} };
+ char action[32];
+ if (!status) mDNS_snprintf(action, sizeof(action), sent ? "Sent" : "Received");
+ else mDNS_snprintf(action, sizeof(action), "ERROR %d %sing", status, sent ? "Send" : "Receiv");
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] " PUB_S " " PUB_S " DNS Message %lu bytes from " PRI_IP_ADDR ":%d to " PRI_IP_ADDR ":%d via " PUB_S " (%p)",
+ mDNSVal16(msg->h.id), action, transport, (unsigned long)(end - (const mDNSu8 *)msg),
+ srcaddr ? srcaddr : &zeroIPv4Addr, mDNSVal16(srcport), dstaddr ? dstaddr : &zeroIPv4Addr, mDNSVal16(dstport),
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ InterfaceNameForID(&mDNSStorage, interfaceID),
+#else
+ "interface",
+#endif
+ interfaceID);
+ DNSMessageDumpToLog(msg, end);
}
// ***************************************************************************
#pragma mark - Packet Sending Functions
#endif
-#ifdef UNIT_TEST
-// Run the unit test of mDNSSendDNSMessage
-UNITTEST_SENDDNSMESSAGE
-#else
// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
-struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
// Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
struct UDPSocket_struct { mDNSIPPort port; /* ... */ };
// Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
// is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
- mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
- mDNSBool useBackgroundTrafficClass)
+ mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
+ mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass)
{
mStatus status = mStatus_NoError;
const mDNSu16 numAdditionals = msg->h.numAdditionals;
- mDNSu8 *newend;
- mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
#if APPLE_OSX_mDNSResponder
// maintain outbound packet statistics
return mStatus_BadParamErr;
}
- newend = putHINFO(m, msg, end, authInfo, limit);
- if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
- else end = newend;
-
// Put all the integer values in IETF byte-order (MSB first, LSB second)
SwapDNSHeaderBytes(msg);
else
{
// Send the packet on the wire
- if (!sock)
- status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport, useBackgroundTrafficClass);
+ if (!tcpSrc)
+ status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, udpSrc, dst, dstport, useBackgroundTrafficClass);
else
{
mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
long nsent;
// Try to send them in one packet if we can allocate enough memory
- buf = mDNSPlatformMemAllocate(msglen + 2);
+ buf = (char *) mDNSPlatformMemAllocate(msglen + 2);
if (buf)
{
buf[0] = lenbuf[0];
buf[1] = lenbuf[1];
mDNSPlatformMemCopy(buf+2, msg, msglen);
- nsent = mDNSPlatformWriteTCP(sock, buf, msglen+2);
+ nsent = mDNSPlatformWriteTCP(tcpSrc, buf, msglen+2);
if (nsent != (msglen + 2))
{
LogMsg("mDNSSendDNSMessage: write message failed %d/%d", nsent, msglen);
}
else
{
- nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
+ nsent = mDNSPlatformWriteTCP(tcpSrc, (char*)lenbuf, 2);
if (nsent != 2)
{
LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2);
}
else
{
- nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+ nsent = mDNSPlatformWriteTCP(tcpSrc, (char *)msg, msglen);
if (nsent != msglen)
{
LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen);
// Dump the packet with the HINFO and TSIG
if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
- DumpPacket(status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
+ {
+ char *transport = "UDP";
+ mDNSIPPort portNumber = udpSrc ? udpSrc->port : MulticastDNSPort;
+ if (tcpSrc)
+ {
+ if (tcpSrc->flags)
+ transport = "TLS";
+ else
+ transport = "TCP";
+ portNumber = tcpSrc->port;
+ }
+ DumpPacket(status, mDNStrue, transport, mDNSNULL, portNumber, dst, dstport, msg, end, InterfaceID);
+ }
// put the number of additionals back the way it was
msg->h.numAdditionals = numAdditionals;
return(status);
}
-#endif // UNIT_TEST
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
if (e - m->NextScheduledSPS > 0) e = m->NextScheduledSPS;
if (e - m->NextScheduledKA > 0) e = m->NextScheduledKA;
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
-#endif // BONJOUR_ON_DEMAND
+#endif
// NextScheduledSPRetry only valid when DelaySleep not set
if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
case 'p': F.havePrecision = F.lSize = 1;
F.precision = sizeof(void*) * 2; // 8 characters on 32-bit; 16 characters on 64-bit
+ fallthrough();
case 'X': digits = kHexDigitsUppercase;
goto hexadecimal;
case 'x': digits = kHexDigitsLowercase;
default: s = mDNS_VACB;
i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+ break;
case '%': *sbuffer++ = (char)c;
if (++nwritten >= buflen) goto exit;
if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero.
return(lastID);
}
+
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
kDNSFlag0_QR_Query = 0x00,
kDNSFlag0_QR_Response = 0x80,
- kDNSFlag0_OP_Mask = 0x78, // Operation type
- kDNSFlag0_OP_StdQuery = 0x00,
- kDNSFlag0_OP_Subscribe = 0x06,
- kDNSFlag0_OP_UnSubscribe = 0x07,
- kDNSFlag0_OP_Iquery = 0x08,
- kDNSFlag0_OP_Status = 0x10,
- kDNSFlag0_OP_Unused3 = 0x18,
- kDNSFlag0_OP_Notify = 0x20,
- kDNSFlag0_OP_Update = 0x28,
+ kDNSFlag0_OP_Mask = 0xF << 3, // Operation type
+ kDNSFlag0_OP_StdQuery = 0x0 << 3,
+ kDNSFlag0_OP_Iquery = 0x1 << 3,
+ kDNSFlag0_OP_Status = 0x2 << 3,
+ kDNSFlag0_OP_Unused3 = 0x3 << 3,
+ kDNSFlag0_OP_Notify = 0x4 << 3,
+ kDNSFlag0_OP_Update = 0x5 << 3,
+ kDNSFlag0_OP_DSO = 0x6 << 3,
kDNSFlag0_QROP_Mask = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
kDNSFlag1_RC_YXRRSet = 0x07,
kDNSFlag1_RC_NXRRSet = 0x08,
kDNSFlag1_RC_NotAuth = 0x09,
- kDNSFlag1_RC_NotZone = 0x0A
+ kDNSFlag1_RC_NotZone = 0x0A,
+ kDNSFlag1_RC_DSOTypeNI = 0x0B
} DNS_Flags;
typedef enum
// We set the maximum allowable TTL to one hour.
// With the 25% correction factor to avoid the DNS Zeno's paradox bug, that gives us an actual maximum lifetime of 75 minutes.
-#define mDNSMaximumTTLSeconds (mDNSu32)3600
+#define mDNSMaximumMulticastTTLSeconds (mDNSu32)4500
+#define mDNSMaximumUnicastTTLSeconds (mDNSu32)3600
#define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
extern mDNSu32 RDataHashValue(const ResourceRecord *const rr);
extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename);
-extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
+extern mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, 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 mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q);
+extern mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q);
+extern mDNSBool AnyTypeRecordAnswersQuestion (const AuthRecord *const ar, const DNSQuestion *const q);
extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q);
extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease);
extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit);
-extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr, DomainAuthInfo *authInfo, mDNSu8 *limit);
extern mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit);
extern int baseEncode(char *buffer, int blen, const mDNSu8 *data, int len, int encAlg);
extern void NSEC3Parse(const ResourceRecord *const rr, mDNSu8 **salt, int *hashLength, mDNSu8 **nxtName, int *bitmaplen, mDNSu8 **bitmap);
-extern const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
- const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen);
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
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 mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease);
-extern void DumpPacket(mStatus status, mDNSBool sent, char *transport,
- const mDNSAddr *srcaddr, mDNSIPPort srcport,
- const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
+extern void DumpPacket(mStatus status, mDNSBool sent, const char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport,
+ const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end,
+ mDNSInterfaceID interfaceID);
extern mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type);
extern mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type);
extern mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type);
#pragma mark -
#pragma mark - Packet Sending Functions
#endif
-
extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,
- mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
- mDNSBool useBackgroundTrafficClass);
+ mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
+ mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass);
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
extern void ShowTaskSchedulingError(mDNS *const m);
extern void mDNS_Lock_(mDNS *const m, const char * const functionname);
extern void mDNS_Unlock_(mDNS *const m, const char * const functionname);
-
+
#if defined(_WIN32)
#define __func__ __FUNCTION__
#endif
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
l|=(((unsigned long)(*((c)++)))<< 8), \
l|=(((unsigned long)(*((c)++))) ), \
l)
-#define HOST_p_c2l(c,l,n) { \
- switch (n) { \
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
case 0: l =((unsigned long)(*((c)++)))<<24; \
+ fallthrough(); \
case 1: l|=((unsigned long)(*((c)++)))<<16; \
+ fallthrough(); \
case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+ fallthrough(); \
case 3: l|=((unsigned long)(*((c)++))); \
} }
#define HOST_p_c2l_p(c,l,sc,len) { \
- switch (sc) { \
+ switch (sc) { \
case 0: l =((unsigned long)(*((c)++)))<<24; \
- if (--len == 0) break; \
+ if (--len == 0) break; \
+ fallthrough(); \
case 1: l|=((unsigned long)(*((c)++)))<<16; \
- if (--len == 0) break; \
+ if (--len == 0) break; \
+ fallthrough(); \
case 2: l|=((unsigned long)(*((c)++)))<< 8; \
} }
/* NOTE the pointer is not incremented at the end of this */
-#define HOST_c2l_p(c,l,n) { \
- l=0; (c)+=n; \
- switch (n) { \
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
case 3: l =((unsigned long)(*(--(c))))<< 8; \
+ fallthrough(); \
case 2: l|=((unsigned long)(*(--(c))))<<16; \
+ fallthrough(); \
case 1: l|=((unsigned long)(*(--(c))))<<24; \
} }
#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
l|=(((unsigned long)(*((c)++)))<<16), \
l|=(((unsigned long)(*((c)++)))<<24), \
l)
-#define HOST_p_c2l(c,l,n) { \
- switch (n) { \
+#define HOST_p_c2l(c,l,n) { \
+ switch (n) { \
case 0: l =((unsigned long)(*((c)++))); \
+ fallthrough(); \
case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ fallthrough(); \
case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ fallthrough(); \
case 3: l|=((unsigned long)(*((c)++)))<<24; \
} }
#define HOST_p_c2l_p(c,l,sc,len) { \
- switch (sc) { \
+ switch (sc) { \
case 0: l =((unsigned long)(*((c)++))); \
- if (--len == 0) break; \
+ if (--len == 0) break; \
+ fallthrough(); \
case 1: l|=((unsigned long)(*((c)++)))<< 8; \
- if (--len == 0) break; \
+ if (--len == 0) break; \
+ fallthrough(); \
case 2: l|=((unsigned long)(*((c)++)))<<16; \
} }
/* NOTE the pointer is not incremented at the end of this */
-#define HOST_c2l_p(c,l,n) { \
- l=0; (c)+=n; \
- switch (n) { \
+#define HOST_c2l_p(c,l,n) { \
+ l=0; (c)+=n; \
+ switch (n) { \
case 3: l =((unsigned long)(*(--(c))))<<16; \
+ fallthrough(); \
case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+ fallthrough(); \
case 1: l|=((unsigned long)(*(--(c)))); \
} }
#define _HOST_l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
{
const unsigned char *data=(const unsigned char *)data_;
+ const unsigned char * const data_end=(const unsigned char *)data_;
register HASH_LONG * p;
register unsigned long l;
int sw,sc,ew,ec;
if ((c->num+len) >= HASH_CBLOCK)
{
l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
- for (; sw<HASH_LBLOCK; sw++)
+ for (; (sw < HASH_LBLOCK) && ((data_end - data) >= 4); sw++)
{
HOST_c2l(data,l); p[sw]=l;
}
l=p[sw];
HOST_p_c2l(data,l,sc);
p[sw++]=l;
- for (; sw < ew; sw++)
+ for (; (sw < ew) && ((data_end - data) >= 4); sw++)
{
HOST_c2l(data,l); p[sw]=l;
}
c->num = (int)len;
ew=(int)(len>>2); /* words to copy */
ec=(int)(len&0x03);
- for (; ew; ew--,p++)
+ for (; ew && ((data_end - data) >= 4); ew--,p++)
{
HOST_c2l(data,l); *p=l;
}
C=c->C;
D=c->D;
+#if defined(__clang_analyzer__)
+ // Get rid of false positive analyzer warning.
+ for (const unsigned char *_ptr = data; _ptr < &data[num * HASH_CBLOCK]; ++_ptr) {}
+#endif
for (; num--;)
{
HOST_c2l(data,l); X( 0)=l; HOST_c2l(data,l); X( 1)=l;
#define HMAC_OPAD 0x5c
#define MD5_LEN 16
-#define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
+#define HMAC_MD5_AlgName "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int"
// Adapted from Appendix, RFC 2104
mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len)
MD5_Update(&c, (mDNSu8 *)&tsig.resrec.rroriginalttl, sizeof(tsig.resrec.rroriginalttl));
// alg name
- AssignDomainName(&tsig.resrec.rdata->u.name, &HMAC_MD5_AlgName);
- len = DomainNameLength(&HMAC_MD5_AlgName);
+ AssignConstStringDomainName(&tsig.resrec.rdata->u.name, HMAC_MD5_AlgName);
+ len = DomainNameLengthLimit((domainname *)HMAC_MD5_AlgName, (mDNSu8 *)HMAC_MD5_AlgName + sizeof HMAC_MD5_AlgName);
rdata = tsig.resrec.rdata->u.data + len;
- MD5_Update(&c, HMAC_MD5_AlgName.c, len);
+ MD5_Update(&c, (mDNSu8 *)HMAC_MD5_AlgName, len);
// time
// get UTC (universal time), convert to 48-bit unsigned in network byte order
algo = (domainname*) ptr;
- if (!SameDomainName(algo, &HMAC_MD5_AlgName))
+ if (!SameDomainName(algo, (domainname *)HMAC_MD5_AlgName))
{
LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c);
*rcode = kDNSFlag1_RC_NotAuth;
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mDNSEmbeddedAPI.h"
-#include "CryptoAlg.h"
-#include "anonymous.h"
-#include "DNSCommon.h"
-
-// Define ANONYMOUS_DISABLED to remove all the anonymous functionality
-// and use the stub functions implemented later in this file.
-
-#ifndef ANONYMOUS_DISABLED
-
-#define ANON_NSEC3_ITERATIONS 1
-
-struct AnonInfoResourceRecord_struct
-{
- ResourceRecord resrec;
- RData rdatastorage;
-};
-
-typedef struct AnonInfoResourceRecord_struct AnonInfoResourceRecord;
-
-mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonData, int len, mDNSu32 salt)
-{
- const mDNSu8 *ptr;
- rdataNSEC3 *nsec3 = (rdataNSEC3 *)rr->rdata->u.data;
- mDNSu8 *tmp, *nxt;
- unsigned short iter = ANON_NSEC3_ITERATIONS;
- int hlen;
- const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
-
- // Construct the RDATA first and construct the owner name based on that.
- ptr = (const mDNSu8 *)&salt;
- debugf("InitializeNSEC3Record: %x%x%x%x, name %##s", ptr[0], ptr[1], ptr[2], ptr[3], rr->name->c);
-
- // Set the RDATA
- nsec3->alg = SHA1_DIGEST_TYPE;
- nsec3->flags = 0;
- nsec3->iterations = swap16(iter);
- nsec3->saltLength = 4;
- tmp = (mDNSu8 *)&nsec3->salt;
- *tmp++ = ptr[0];
- *tmp++ = ptr[1];
- *tmp++ = ptr[2];
- *tmp++ = ptr[3];
-
- // hashLength, nxt, bitmap
- *tmp++ = SHA1_HASH_LENGTH; // hash length
- nxt = tmp;
- tmp += SHA1_HASH_LENGTH;
- *tmp++ = 0; // window number
- *tmp++ = NSEC_MCAST_WINDOW_SIZE; // window length
- mDNSPlatformMemZero(tmp, NSEC_MCAST_WINDOW_SIZE);
- tmp[kDNSType_PTR >> 3] |= 128 >> (kDNSType_PTR & 7);
-
- // Hash the base service name + salt + AnonData
- if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen))
- {
- LogMsg("InitializeNSEC3Record: NSEC3HashName failed for %##s", rr->name->c);
- return mDNSfalse;
- }
- if (hlen != SHA1_HASH_LENGTH)
- {
- LogMsg("InitializeNSEC3Record: hlen wrong %d", hlen);
- return mDNSfalse;
- }
- mDNSPlatformMemCopy(nxt, hashName, hlen);
-
- return mDNStrue;
-}
-
-mDNSlocal ResourceRecord *ConstructNSEC3Record(const domainname *service, const mDNSu8 *AnonData, int len, mDNSu32 salt)
-{
- ResourceRecord *rr;
- int dlen;
- domainname *name;
-
- // We are just allocating an RData which has StandardAuthRDSize
- if (StandardAuthRDSize < MCAST_NSEC3_RDLENGTH)
- {
- LogMsg("ConstructNSEC3Record: StandardAuthRDSize %d smaller than MCAST_NSEC3_RDLENGTH %d", StandardAuthRDSize, MCAST_NSEC3_RDLENGTH);
- return mDNSNULL;
- }
-
- dlen = DomainNameLength(service);
-
- // Allocate space for the name and RData.
- rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + dlen + sizeof(RData));
- if (!rr)
- return mDNSNULL;
- name = (domainname *)((mDNSu8 *)rr + sizeof(ResourceRecord));
- rr->RecordType = kDNSRecordTypePacketAuth;
- rr->InterfaceID = mDNSInterface_Any;
- rr->name = (const domainname *)name;
- rr->rrtype = kDNSType_NSEC3;
- rr->rrclass = kDNSClass_IN;
- rr->rroriginalttl = kStandardTTL;
- rr->rDNSServer = mDNSNULL;
- rr->rdlength = MCAST_NSEC3_RDLENGTH;
- rr->rdestimate = MCAST_NSEC3_RDLENGTH;
- rr->rdata = (RData *)((mDNSu8 *)rr->name + dlen);
-
- AssignDomainName(name, service);
- if (!InitializeNSEC3Record(rr, AnonData, len, salt))
- {
- mDNSPlatformMemFree(rr);
- return mDNSNULL;
- }
- return rr;
-}
-
-mDNSlocal ResourceRecord *CopyNSEC3ResourceRecord(AnonymousInfo *si, const ResourceRecord *rr)
-{
- AnonInfoResourceRecord *anonRR;
- domainname *name;
- mDNSu32 neededLen;
- mDNSu32 extraLen;
-
- if (rr->rdlength < MCAST_NSEC3_RDLENGTH)
- {
- LogMsg("CopyNSEC3ResourceRecord: rdlength %d smaller than MCAST_NSEC3_RDLENGTH %d", rr->rdlength, MCAST_NSEC3_RDLENGTH);
- return mDNSNULL;
- }
- // Allocate space for the name and the rdata along with the ResourceRecord
- neededLen = rr->rdlength + DomainNameLength(rr->name);
- extraLen = (neededLen > sizeof(RDataBody)) ? (neededLen - sizeof(RDataBody)) : 0;
- anonRR = (AnonInfoResourceRecord *)mDNSPlatformMemAllocate(sizeof(AnonInfoResourceRecord) + extraLen);
- if (!anonRR)
- return mDNSNULL;
-
- anonRR->resrec = *rr;
-
- anonRR->rdatastorage.MaxRDLength = rr->rdlength;
- mDNSPlatformMemCopy(anonRR->rdatastorage.u.data, rr->rdata->u.data, rr->rdlength);
-
- name = (domainname *)(anonRR->rdatastorage.u.data + rr->rdlength);
- AssignDomainName(name, rr->name);
-
- anonRR->resrec.name = name;
- anonRR->resrec.rdata = &anonRR->rdatastorage;
-
- si->nsec3RR = (ResourceRecord *)anonRR;
-
- return si->nsec3RR;
-}
-
-// When a service is started or a browse is started with the Anonymous data, we allocate a new random
-// number and based on that allocate a new NSEC3 resource record whose hash is a function of random number (salt) and
-// the anonymous data.
-//
-// If we receive a packet with the NSEC3 option, we need to cache that along with the resource record so that we can
-// check against the question to see whether it answers them or not. In that case, we pass the "rr" that we received.
-mDNSexport AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *data, int len, const ResourceRecord *rr)
-{
- AnonymousInfo *ai;
- ai = (AnonymousInfo *)mDNSPlatformMemAllocate(sizeof(AnonymousInfo));
- if (!ai)
- {
- return mDNSNULL;
- }
- mDNSPlatformMemZero(ai, sizeof(AnonymousInfo));
- if (rr)
- {
- if (!CopyNSEC3ResourceRecord(ai, rr))
- {
- mDNSPlatformMemFree(ai);
- return mDNSNULL;
- }
- return ai;
- }
- ai->salt = mDNSRandom(0xFFFFFFFF);
- ai->AnonData = mDNSPlatformMemAllocate(len);
- if (!ai->AnonData)
- {
- mDNSPlatformMemFree(ai);
- return mDNSNULL;
- }
- ai->AnonDataLen = len;
- mDNSPlatformMemCopy(ai->AnonData, data, len);
- ai->nsec3RR = ConstructNSEC3Record(service, data, len, ai->salt);
- if (!ai->nsec3RR)
- {
- mDNSPlatformMemFree(ai);
- return mDNSNULL;
- }
- return ai;
-}
-
-mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
-{
- if (ai->nsec3RR)
- mDNSPlatformMemFree(ai->nsec3RR);
- if (ai->AnonData)
- mDNSPlatformMemFree(ai->AnonData);
- mDNSPlatformMemFree(ai);
-}
-
-mDNSexport void ReInitAnonInfo(AnonymousInfo **AnonInfo, const domainname *name)
-{
- if (*AnonInfo)
- {
- AnonymousInfo *ai = *AnonInfo;
- *AnonInfo = AllocateAnonInfo(name, ai->AnonData, ai->AnonDataLen, mDNSNULL);
- if (!(*AnonInfo))
- *AnonInfo = ai;
- else
- FreeAnonInfo(ai);
- }
-}
-
-// This function should be used only if you know that the question and
-// the resource record belongs to the same set. The main usage is
-// in ProcessQuery where we find the question to be part of the same
-// set as the resource record, but it needs the AnonData to be
-// initialized so that it can walk the cache records to see if they
-// answer the question.
-mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
-{
- if (!q->AnonInfo || !rr->AnonInfo)
- {
- LogMsg("SetAnonData: question %##s(%p), rr %##s(%p), NULL", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
- return;
- }
-
- debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
- if (ForQuestion)
- {
- if (q->AnonInfo->AnonDataLen < rr->AnonInfo->AnonDataLen)
- {
- mDNSPlatformMemFree(q->AnonInfo->AnonData);
- q->AnonInfo->AnonData = mDNSNULL;
- }
-
- if (!q->AnonInfo->AnonData)
- {
- q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen);
- if (!q->AnonInfo->AnonData)
- return;
- }
- mDNSPlatformMemCopy(q->AnonInfo->AnonData, rr->AnonInfo->AnonData, rr->AnonInfo->AnonDataLen);
- q->AnonInfo->AnonDataLen = rr->AnonInfo->AnonDataLen;
- }
- else
- {
- if (rr->AnonInfo->AnonDataLen < q->AnonInfo->AnonDataLen)
- {
- mDNSPlatformMemFree(rr->AnonInfo->AnonData);
- rr->AnonInfo->AnonData = mDNSNULL;
- }
-
- if (!rr->AnonInfo->AnonData)
- {
- rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen);
- if (!rr->AnonInfo->AnonData)
- return;
- }
- mDNSPlatformMemCopy(rr->AnonInfo->AnonData, q->AnonInfo->AnonData, q->AnonInfo->AnonDataLen);
- rr->AnonInfo->AnonDataLen = q->AnonInfo->AnonDataLen;
- }
-}
-
-// returns -1 if the caller should ignore the result
-// returns 1 if the record answers the question
-// returns 0 if the record does not answer the question
-mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
- mDNSexport mDNS mDNSStorage;
- ResourceRecord *nsec3RR;
- int i;
- AnonymousInfo *qai, *rai;
- mDNSu8 *AnonData;
- int AnonDataLen;
- rdataNSEC3 *nsec3;
- int hlen;
- int nxtLength;
- mDNSu8 *nxtName;
- mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
- mDNSPlatformMemZero(hashName, sizeof(hashName));
-
- debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c);
-
- // Currently only PTR records can have anonymous information
- if (q->qtype != kDNSType_PTR)
- {
- return -1;
- }
-
- // We allow anonymous questions to be answered by both normal services (without the
- // anonymous information) and anonymous services that are part of the same set. And
- // normal questions discover normal services and all anonymous services.
- //
- // The three cases have been enumerated clearly even though they all behave the
- // same way.
- if (!q->AnonInfo)
- {
- debugf("AnonInfoAnswersQuestion: not a anonymous type question");
- if (!rr->AnonInfo)
- {
- // case 1
- return -1;
- }
- else
- {
- // case 2
- debugf("AnonInfoAnswersQuestion: Question %##s not answered using anonymous record %##s", q->qname.c, rr->name->c);
- return -1;
- }
- }
- else
- {
- // case 3
- if (!rr->AnonInfo)
- {
- debugf("AnonInfoAnswersQuestion: not a anonymous type record");
- return -1;
- }
- }
-
- // case 4: We have the anonymous information both in the question and the record. We need
- // two sets of information to validate.
- //
- // 1) Anonymous data that identifies the set/group
- // 2) NSEC3 record that contains the hash and the salt
- //
- // If the question is a remote one, it does not have the anonymous information to validate (just
- // the NSEC3 record) and hence the anonymous data should come from the local resource record. If the
- // question is local, it can come from either of them and if there is a mismatch between the
- // question and record, it won't validate.
-
- qai = q->AnonInfo;
- rai = rr->AnonInfo;
-
- if (qai->AnonData && rai->AnonData)
- {
- // Before a cache record is created, if there is a matching question i.e., part
- // of the same set, then when the cache is created we also set the anonymous
- // information. Otherwise, the cache record contains just the NSEC3 record and we
- // won't be here for that case.
- //
- // It is also possible that a local question is matched against the local AuthRecord
- // as that is also the case for which the AnonData would be non-NULL for both.
- // We match questions against AuthRecords (rather than the cache) for LocalOnly case and
- // to see whether a .local query should be suppressed or not. The latter never happens
- // because PTR queries are never suppressed.
-
- // If they don't belong to the same anonymous set, then no point in validating.
- if ((qai->AnonDataLen != rai->AnonDataLen) ||
- mDNSPlatformMemCmp(qai->AnonData, rai->AnonData, qai->AnonDataLen) != 0)
- {
- debugf("AnonInfoAnswersQuestion: AnonData mis-match for record %s question %##s ",
- RRDisplayString(&mDNSStorage, rr), q->qname.c);
- return 0;
- }
- // AnonData matches i.e they belong to the same group and the same service.
- LogInfo("AnonInfoAnswersQuestion: Answering qname %##s, rname %##s, without validation", q->qname.c,
- rr->name->c);
- return 1;
- }
- else
- {
- debugf("AnonInfoAnswersQuestion: question %p, record %p", qai->AnonData, rai->AnonData);
- }
-
- if (qai->AnonData)
- {
- // If there is AnonData, then this is a local question. The
- // NSEC3 RR comes from the resource record which could be part
- // of the cache or local auth record. The cache entry could
- // be from a remote host or created when we heard our own
- // announcements. In any case, we use that to see if it matches
- // the question.
- AnonData = qai->AnonData;
- AnonDataLen = qai->AnonDataLen;
- nsec3RR = rai->nsec3RR;
- }
- else
- {
- // Remote question or hearing our own question back
- AnonData = rai->AnonData;
- AnonDataLen = rai->AnonDataLen;
- nsec3RR = qai->nsec3RR;
- }
-
- if (!AnonData || !nsec3RR)
- {
- // AnonData can be NULL for the cache entry and if we are hearing our own question back, AnonData is NULL for
- // that too and we can end up here for that case.
- debugf("AnonInfoAnswersQuestion: AnonData %p or nsec3RR %p, NULL for question %##s, record %s", AnonData, nsec3RR,
- q->qname.c, RRDisplayString(&mDNSStorage, rr));
- return 0;
- }
- debugf("AnonInfoAnswersQuestion: Validating question %##s, ResourceRecord %s", q->qname.c, RRDisplayString(&mDNSStorage, nsec3RR));
-
-
- nsec3 = (rdataNSEC3 *)nsec3RR->rdata->u.data;
-
- if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen))
- {
- LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for %##s", nsec3RR->name->c);
- return mDNSfalse;
- }
- if (hlen != SHA1_HASH_LENGTH)
- {
- LogMsg("AnonInfoAnswersQuestion: hlen wrong %d", hlen);
- return mDNSfalse;
- }
-
- NSEC3Parse(nsec3RR, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
-
- if (hlen != nxtLength)
- {
- LogMsg("AnonInfoAnswersQuestion: ERROR!! hlen %d not same as nxtLength %d", hlen, nxtLength);
- return mDNSfalse;
- }
-
- for (i = 0; i < nxtLength; i++)
- {
- if (nxtName[i] != hashName[i])
- {
- debugf("AnonInfoAnswersQuestion: mismatch output %x, digest %x, i %d", nxtName[i+1], hashName[i], i);
- return 0;
- }
- }
- LogInfo("AnonInfoAnswersQuestion: ResourceRecord %s matched question %##s (%s)", RRDisplayString(&mDNSStorage, nsec3RR), q->qname.c, DNSTypeName(q->qtype));
- return 1;
-}
-
-// Find a matching NSEC3 record for the name. We parse the questions and the records in the packet in order.
-// Similarly we also parse the NSEC3 records in order and this mapping to the questions and records
-// respectively.
-mDNSlocal CacheRecord *FindMatchingNSEC3ForName(mDNS *const m, CacheRecord **nsec3, const domainname *name)
-{
- CacheRecord *cr;
- CacheRecord **prev = nsec3;
-
- (void) m;
-
- for (cr = *nsec3; cr; cr = cr->next)
- {
- if (SameDomainName(cr->resrec.name, name))
- {
- debugf("FindMatchingNSEC3ForName: NSEC3 record %s matched %##s", CRDisplayString(m, cr), name->c);
- *prev = cr->next;
- cr->next = mDNSNULL;
- return cr;
- }
- prev = &cr->next;
- }
- return mDNSNULL;
-}
-
-mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
-{
- CacheRecord *nsec3CR;
-
- if (q->qtype != kDNSType_PTR)
- return;
-
- nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, &q->qname);
- if (nsec3CR)
- {
- q->AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
- if (q->AnonInfo)
- {
- debugf("InitializeAnonInfoForQuestion: Found a matching NSEC3 record %s, for %##s (%s)",
- RRDisplayString(m, q->AnonInfo->nsec3RR), q->qname.c, DNSTypeName(q->qtype));
- }
- ReleaseCacheRecord(m, nsec3CR);
- }
-}
-
-mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
-{
- CacheRecord *nsec3CR;
-
- if (!(*McastNSEC3Records))
- return;
-
- // If already initialized or not a PTR type, we don't have to do anything
- if (cr->resrec.AnonInfo || cr->resrec.rrtype != kDNSType_PTR)
- return;
-
- nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, cr->resrec.name);
- if (nsec3CR)
- {
- cr->resrec.AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
- if (cr->resrec.AnonInfo)
- {
- debugf("InitializeAnonInfoForCR: Found a matching NSEC3 record %s, for %##s (%s)",
- RRDisplayString(m, cr->resrec.AnonInfo->nsec3RR), cr->resrec.name->c,
- DNSTypeName(cr->resrec.rrtype));
- }
- ReleaseCacheRecord(m, nsec3CR);
- }
-}
-
-mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
-{
- // if a1 is NULL and a2 is not NULL AND vice-versa
- // return false as there is a change.
- if ((a1 != mDNSNULL) != (a2 != mDNSNULL))
- return mDNSfalse;
-
- // Both could be NULL or non-NULL
- if (a1 && a2)
- {
- // The caller already verified that the owner name is the same.
- // Check whether the RData is same.
- if (!IdenticalSameNameRecord(a1->nsec3RR, a2->nsec3RR))
- {
- debugf("IdenticalAnonInfo: nsec3RR mismatch");
- return mDNSfalse;
- }
- }
- return mDNStrue;
-}
-
-mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
-{
- AnonymousInfo *aifrom = crfrom->resrec.AnonInfo;
- AnonymousInfo *aito = crto->resrec.AnonInfo;
-
- (void) m;
-
- if (!aifrom)
- return;
-
- if (aito)
- {
- crto->resrec.AnonInfo = aifrom;
- FreeAnonInfo(aito);
- crfrom->resrec.AnonInfo = mDNSNULL;
- }
- else
- {
- FreeAnonInfo(aifrom);
- crfrom->resrec.AnonInfo = mDNSNULL;
- }
-}
-
-#else // !ANONYMOUS_DISABLED
-
-mDNSexport void ReInitAnonInfo(AnonymousInfo **si, const domainname *name)
-{
- (void)si;
- (void)name;
-}
-
-mDNSexport AnonymousInfo * AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr)
-{
- (void)service;
- (void)AnonData;
- (void)len;
- (void)rr;
-
- return mDNSNULL;
-}
-
-mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
-{
- (void)ai;
-}
-
-mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
-{
- (void)q;
- (void)rr;
- (void)ForQuestion;
-}
-
-mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
- (void)rr;
- (void)q;
-
- return mDNSfalse;
-}
-
-mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
-{
- (void)m;
- (void)McastNSEC3Records;
- (void)q;
-}
-
-mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
-{
- (void)m;
- (void)McastNSEC3Records;
- (void)cr;
-}
-
-mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
-{
- (void)m;
- (void)crto;
- (void)crfrom;
-}
-
-mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
-{
- (void)a1;
- (void)a2;
-
- return mDNStrue;
-}
-
-#endif // !ANONYMOUS_DISABLED
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __ANONYMOUS_H_
-#define __ANONYMOUS_H_
-
-extern void ReInitAnonInfo(AnonymousInfo **si, const domainname *name);
-extern AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr);
-extern void FreeAnonInfo(AnonymousInfo *ai);
-extern void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion);
-extern int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr);
-extern void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q);
-extern void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom);
-extern mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2);
-
-#endif
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2019 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.
#ifndef UNICAST_DISABLED
-mDNSexport mDNS mDNSStorage;
+extern mDNS mDNSStorage;
// Implementation Notes
//
pc->q.ValidatingResponse = 1;
for (cr = cg->members; cr; cr = cr->next)
{
- if (SameNameRecordAnswersQuestion(&cr->resrec, &pc->q))
+ if (SameNameCacheRecordAnswersQuestion(cr, &pc->q))
{
if (first)
{
if (!pc->tcp)
{
- mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, (UDPSocket *)pc->socket, &pc->addr, pc->port, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, mDNSNULL, (UDPSocket *)pc->socket, &pc->addr, pc->port, mDNSNULL, mDNSfalse);
}
else
{
- mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, mDNSNULL, &pc->addr, pc->port, (TCPSocket *)pc->socket, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, (TCPSocket *)pc->socket, mDNSNULL, &pc->addr, pc->port, mDNSNULL, mDNSfalse);
}
done:
if (!tcp)
{
- mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, socket, dstaddr, dstport, mDNSNULL, mDNSNULL,
- mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, mDNSNULL, socket, dstaddr, dstport, mDNSNULL, mDNSfalse);
}
else
{
- mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, mDNSNULL, dstaddr, dstport, (TCPSocket *)socket,
- mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, (TCPSocket *)socket, mDNSNULL, dstaddr, dstport, mDNSNULL, mDNSfalse);
}
mDNSPlatformDisposeProxyContext(context);
}
LogInfo("ProxyCallbackCommon: Found a duplicate for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
return;
}
- pc = mDNSPlatformMemAllocate(sizeof(DNSProxyClient));
+ pc = (DNSProxyClient *) mDNSPlatformMemAllocateClear(sizeof(*pc));
if (!pc)
{
LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
return;
}
- mDNSPlatformMemZero(pc, sizeof(DNSProxyClient));
pc->addr = *srcaddr;
pc->port = srcport;
pc->msgid = msg->h.id;
}
else
{
- pc->optRR = mDNSPlatformMemAllocate(optLen);
+ pc->optRR = (mDNSu8 *) mDNSPlatformMemAllocate(optLen);
if (!pc->optRR)
{
LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2019 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.
return 0;
}
-// Initialize the question enough so that it can be answered from the cache using SameNameRecordAnswersQuestion or
+// Initialize the question enough so that it can be answered from the cache using SameNameCacheRecordAnswersQuestion or
// ResourceRecordAnswersQuestion.
mDNSexport void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname,
mDNSu16 qtype, mDNSQuestionCallback *callback, void *context)
{
DNSSECVerifier *dv;
- dv = (DNSSECVerifier *)mDNSPlatformMemAllocate(sizeof(DNSSECVerifier));
+ dv = (DNSSECVerifier *) mDNSPlatformMemAllocateClear(sizeof(*dv));
if (!dv) { LogMsg("AllocateDNSSECVerifier: ERROR!! memory alloc failed"); return mDNSNULL; }
- mDNSPlatformMemZero(dv, sizeof(*dv));
LogDNSSEC("AllocateDNSSECVerifier called %p", dv);
while (ae)
{
- ac = mDNSPlatformMemAllocate(sizeof(AuthChain));
+ ac = (AuthChain *) mDNSPlatformMemAllocateClear(sizeof(*ac));
if (!ac)
{
LogMsg("AuthChainCopy: AuthChain alloc failure");
if (retac)
FreeDNSSECAuthChainInfo(retac);
- return mDNSfalse;
+ return mDNSNULL;
}
ac->next = mDNSNULL;
{
RRVerifier *r;
- r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + from->rdlength);
+ r = (RRVerifier *) mDNSPlatformMemAllocate(sizeof(*r) + from->rdlength);
if (!r)
{
LogMsg("CopyRRVerifier: memory failure");
{
RRVerifier *r;
- r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + rr->rdlength);
+ r = (RRVerifier *) mDNSPlatformMemAllocateClear(sizeof(*r) + rr->rdlength);
if (!r)
{
LogMsg("AllocateRRVerifier: memory failure");
nrrsets++;
tmp = rrset;
- start = ptr = mDNSPlatformMemAllocate(nrrsets * sizeof (rdataComp));
+ start = ptr = (rdataComp *) mDNSPlatformMemAllocateClear(nrrsets * sizeof(rdataComp));
debugdnssec("ValidateSignatureWithKey: start %p, nrrsets %d", start, nrrsets);
if (ptr)
{
- // Need to initialize for failure case below
- mDNSPlatformMemZero(ptr, nrrsets * (sizeof (rdataComp)));
while (tmp)
{
ptr->rdlength = tmp->rdlength;
ptr->rrtype = tmp->rrtype;
if (ptr->rdlength)
{
- ptr->rdata = mDNSPlatformMemAllocate(ptr->rdlength);
+ ptr->rdata = (mDNSu8 *) mDNSPlatformMemAllocate(ptr->rdlength);
if (ptr->rdata)
{
mDNSPlatformMemCopy(ptr->rdata, tmp->rdata, tmp->rdlength);
return mDNSfalse;
}
- ae = mDNSPlatformMemAllocate(sizeof(AuthChain));
+ ae = (AuthChain *) mDNSPlatformMemAllocateClear(sizeof(*ae));
if (!ae)
{
LogMsg("AuthChainAdd: AuthChain alloc failure");
}
for (rr = cg->members; rr; rr = rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
+ if (SameNameCacheRecordAnswersQuestion(rr, &question))
{
// originalttl is never touched. The actual TTL is derived based on when it was
// received.
// Find the RRset and set its TTL
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
- if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
+ if (SameNameCacheRecordAnswersQuestion(rr, &question))
{
LogDNSSEC("SetTTLRRSet: Setting the TTL %d for %s, question %##s (%s)", rrTTL, CRDisplayString(m, rr),
question.qname.c, DNSTypeName(rr->resrec.rrtype));
// RRSIGs that can match the original question
for (cr = cg->members; cr; cr = cr->next)
{
- if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
+ if (SameNameCacheRecordAnswersQuestion(cr, &dv->q))
{
answer = &cr->resrec;
break;
dv->q.ValidatingResponse = mDNSfalse;
for (cr = cg->members; cr; cr = cr->next)
{
- if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
+ if (SameNameCacheRecordAnswersQuestion(cr, &dv->q))
{
if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
DNSSECNegativeValidationCB(m, dv, cg, &cr->resrec, status);
// Walk the cache and get all the rrsets for verification.
for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(rr, q))
{
// We also get called for RRSIGs which matches qtype. We don't need that here as we are
// building rrset for matching q->qname. Checking for RRSIG type is important as otherwise
if (ic == mDNSNULL)
{
- ic = (InsecureContext *)mDNSPlatformMemAllocate(sizeof(InsecureContext));
+ ic = (InsecureContext *) mDNSPlatformMemAllocateClear(sizeof(*ic));
if (!ic)
{
- LogMsg("mDNSPlatformMemAllocate: ERROR!! memory alloc failed for ic");
+ LogMsg("mDNSPlatformMemAllocateClear: ERROR!! memory alloc failed for ic");
return;
}
#define __DNSSEC_H
#include "CryptoAlg.h"
-#include "mDNSDebug.h"
typedef enum
{
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
#include "uDNS.h" // Defines entry points into unicast-specific routines
#include "nsec.h"
#include "dnssec.h"
-#include "anonymous.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#include "SymptomReporter.h"
+#endif
// Disable certain benign warnings with Microsoft compilers
#if (defined(_MSC_VER))
#include "dns_sd_internal.h"
#if APPLE_OSX_mDNSResponder
-#include <WebFilterDNS/WebFilterDNS.h>
-
// Delay in seconds before disabling multicast after there are no active queries or registrations.
#define BONJOUR_DISABLE_DELAY 60
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
-#if !NO_WCF
WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
+#endif
-// Do we really need to define a macro for "if"?
-#define CHECK_WCF_FUNCTION(X) if (X)
-#endif // ! NO_WCF
-
-#else
-
-#define NO_WCF 1
-#endif // APPLE_OSX_mDNSResponder
-
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
#include "Metrics.h"
#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
#include "DNS64.h"
#endif
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
-
// Forward declarations
mDNSlocal void BeginSleepProcessing(mDNS *const m);
mDNSlocal void RetrySPSRegistrations(mDNS *const m);
mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSAddr *laddr, mDNSAddr *raddr, mDNSEthAddr *eth,
mDNSu32 *seq, mDNSu32 *ack, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu16 *win);
-mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m);
-mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m);
+typedef mDNSu32 DeadvertiseFlags;
+#define kDeadvertiseFlag_NormalHostname (1U << 0)
+#define kDeadvertiseFlag_RandHostname (1U << 1)
+#define kDeadvertiseFlag_All (kDeadvertiseFlag_NormalHostname | kDeadvertiseFlag_RandHostname)
+
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags);
+mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set);
mDNSlocal void FreeNSECRecords(mDNS *const m, CacheRecord *NSECRecords);
mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
const mDNSInterfaceID InterfaceID, CacheRecord **NSEC3Records);
mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *eth);
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark - Program Constants
// To Turn OFF mDNS_Tracer set MDNS_TRACER to 0 or undef it
#define MDNS_TRACER 1
-#define NO_HINFO 1
-
// Any records bigger than this are considered 'large' records
#define SmallRecordLimit 1024
#pragma mark - General Utility Functions
#endif
+#if MDNS_MALLOC_DEBUGGING
+// When doing memory allocation debugging, this function traverses all lists in the mDNS query
+// structures and caches and checks each entry in the list to make sure it's still good.
+mDNSlocal void mDNS_ValidateLists(void *context)
+{
+ mDNS *m = context;
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ mDNSu32 NumAllInterfaceRecords = 0;
+ mDNSu32 NumAllInterfaceQuestions = 0;
+#endif
+
+ // Check core mDNS lists
+ AuthRecord *rr;
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+ if (rr->resrec.name != &rr->namestorage)
+ LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+ rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
+#endif
+ }
+
+ for (rr = m->DuplicateRecords; rr; rr=rr->next)
+ {
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
+#endif
+ }
+
+ rr = m->NewLocalRecords;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ rr = m->CurrentRecord;
+ if (rr)
+ if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+ LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
+
+ DNSQuestion *q;
+ for (q = m->Questions; q; q=q->next)
+ {
+ if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
+ LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
+ if (q->DuplicateOf && q->LocalSocket)
+ LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID))
+ NumAllInterfaceQuestions++;
+#endif
+ }
+
+ CacheGroup *cg;
+ CacheRecord *cr;
+ mDNSu32 slot;
+ FORALL_CACHERECORDS(slot, cg, cr)
+ {
+ if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
+ LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
+ if (cr->CRActiveQuestion)
+ {
+ for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
+ if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
+ }
+ }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ if (m->NumAllInterfaceRecords != NumAllInterfaceRecords)
+ LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords);
+
+ if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions)
+ LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+}
+#endif // MDNS_MALLOC_DEBUGGING
+
// Returns true if this is a unique, authoritative LocalOnly record that answers questions of type
// A, AAAA , CNAME, or PTR. The caller should answer the question with this record and not send out
// the question on the wire if LocalOnlyRecordAnswersQuestion() also returns true.
mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e)
{
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
unsigned int i;
for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
#endif
// free them all individually which normally happens when we parse /etc/hosts into
// AuthHash where we add the "new" entries and discard (free) the already added
// entries. If we allocate as chunks, we can't free them individually.
- AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity));
+ AuthEntity *storage = (AuthEntity *) mDNSPlatformMemAllocateClear(sizeof(*storage));
storage->next = mDNSNULL;
r->rrauth_free = storage;
}
ag->rrauth_tail = &ag->members;
ag->NewLocalOnlyRecords = mDNSNULL;
if (namelen > sizeof(ag->namestorage))
- ag->name = mDNSPlatformMemAllocate(namelen);
+ ag->name = (domainname *) mDNSPlatformMemAllocate(namelen);
else
ag->name = (domainname*)ag->namestorage;
if (!ag->name)
}
// Caller should hold the lock
-mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc)
+mDNSlocal void GenerateNegativeResponseEx(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc, mDNSBool noData)
{
DNSQuestion *q;
if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; }
q = m->CurrentQuestion;
- LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] GenerateNegativeResponse: Generating negative response for question " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, InterfaceID, mDNSNULL);
+ m->rec.r.resrec.negativeRecordType = noData ? kNegativeRecordType_NoData : kNegativeRecordType_Unspecified;
// We need to force the response through in the following cases
//
// Don't touch the question after this
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
}
+#define GenerateNegativeResponse(M, INTERFACE_ID, QC) GenerateNegativeResponseEx(M, INTERFACE_ID, QC, mDNSfalse)
mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr)
{
const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name);
if (q->CNAMEReferrals >= 10 || selfref)
{
- LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s",
- q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") NOT following CNAME referral %d" PUB_S " for " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+ q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
+
}
else
{
const mDNSu32 c = q->CNAMEReferrals + 1; // Stash a copy of the new q->CNAMEReferrals value
UDPSocket *sock = q->LocalSocket;
mDNSOpaque16 id = q->TargetQID;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
uDNSMetrics metrics;
#endif
// 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.
- LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s",
- q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") following CNAME referral %d for " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+ q->CNAMEReferrals, RRDisplayString(m, rr));
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName)
{
domainname * qName;
qNameLen = DomainNameLength(&q->qname);
if ((qNameLen > 0) && (qNameLen <= MAX_DOMAIN_NAME))
{
- qName = mDNSPlatformMemAllocate(qNameLen);
+ qName = (domainname *) mDNSPlatformMemAllocate(qNameLen);
if (qName)
{
mDNSPlatformMemCopy(qName->c, q->qname.c, qNameLen);
// to try this as unicast query even though it is a .local name
if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname))
{
- LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s",
- q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr));
- q->InterfaceID = mDNSInterface_Unicast;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p " PRI_DM_NAME " (" PUB_S ") Record " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), RRDisplayString(m, rr));
+ q->IsUnicastDotLocal = mDNStrue;
}
mDNS_StartQuery_internal(m, q); // start new query
// Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
// because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
q->CNAMEReferrals = c;
-#if AWD_METRICS
- metrics.expiredAnswerState = q->metrics.expiredAnswerState; // We want the newly initialized state for this value
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ metrics.expiredAnswerState = q->metrics.expiredAnswerState; // We want the newly initialized state for this value
+ metrics.dnsOverTCPState = q->metrics.dnsOverTCPState; // We want the newly initialized state for this value
q->metrics = metrics;
#endif
if (sock)
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
-mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
{
if (m->CurrentQuestion)
LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)",
{
mDNSBool answered;
DNSQuestion *q = m->CurrentQuestion;
- if (RRAny(rr))
- answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
+ if (RRAny(ar))
+ answered = AuthRecordAnswersQuestion(ar, q);
else
- answered = LocalOnlyRecordAnswersQuestion(rr, q);
+ answered = LocalOnlyRecordAnswersQuestion(ar, q);
if (answered)
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again
+ AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord); // MUST NOT dereference q again
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
// and by mDNS_Deregister_internal()
-mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
{
if (m->CurrentQuestion)
LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
mDNSBool answered;
DNSQuestion *q = m->CurrentQuestion;
// We are called with both LocalOnly/P2P record or a regular AuthRecord
- if (RRAny(rr))
- answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
+ if (RRAny(ar))
+ answered = AuthRecordAnswersQuestion(ar, q);
else
- answered = LocalOnlyRecordAnswersQuestion(rr, q);
+ answered = LocalOnlyRecordAnswersQuestion(ar, q);
if (answered)
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord); // MUST NOT dereference q again
+ AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord); // MUST NOT dereference q again
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
m->CurrentQuestion = mDNSNULL;
// If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
- if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P)
- AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord);
+ if (ar->ARType == AuthRecordLocalOnly || ar->ARType == AuthRecordP2P)
+ AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, ar, AddRecord);
}
#define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
-#define ResourceRecordIsValidAnswer(RR) ( ((RR)->resrec.RecordType & kDNSRecordTypeActiveMask) && \
- ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
- ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
- ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)) )
+mDNSlocal mDNSBool ResourceRecordIsValidAnswer(const AuthRecord *const rr)
+{
+ if ((rr->resrec.RecordType & kDNSRecordTypeActiveMask) &&
+ ((rr->Additional1 == mDNSNULL) || (rr->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
+ ((rr->Additional2 == mDNSNULL) || (rr->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
+ ((rr->DependentOn == mDNSNULL) || (rr->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)))
+ {
+ return mDNStrue;
+ }
+ else
+ {
+ return mDNSfalse;
+ }
+}
+
+mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *const rr, const mDNSInterfaceID InterfaceID)
+{
+ if (rr->resrec.InterfaceID == mDNSInterface_Any)
+ {
+ return mDNSPlatformValidRecordForInterface(rr, InterfaceID);
+ }
+ else
+ {
+ return ((rr->resrec.InterfaceID == InterfaceID) ? mDNStrue : mDNSfalse);
+ }
+}
-#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
- (ResourceRecordIsValidAnswer(RR) && \
- ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
+mDNSlocal mDNSBool ResourceRecordIsValidInterfaceAnswer(const AuthRecord *const rr, const mDNSInterfaceID interfaceID)
+{
+ return ((IsInterfaceValidForAuthRecord(rr, interfaceID) && ResourceRecordIsValidAnswer(rr)) ? mDNStrue : mDNSfalse);
+}
#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
+// Parameters for handling probing conflicts
+#define kMaxAllowedMCastProbingConflicts 1 // Maximum number of conflicts to allow from mcast messages.
+#define kProbingConflictPauseDuration mDNSPlatformOneSecond // Duration of probing pause after an allowed mcast conflict.
+
// See RFC 6762: "8.3 Announcing"
// "The Multicast DNS responder MUST send at least two unsolicited responses, one second apart."
// Send 4, which is really 8 since we send on both IPv4 and IPv6.
// If we do our normal refresh at 80% of the TTL, our local caching server will return 20 seconds, so we'll do another
// 80% refresh after 16 seconds, and then the server will return 4 seconds, and so on, in the fashion of Zeno's paradox.
// To avoid this, we extend the record's effective TTL to give it a little extra grace period.
-// We adjust the 100 second TTL to 127. This means that when we do our 80% query at 102 seconds,
+// We adjust the 100 second TTL to 127. This means that when we do our 80% query after 102 seconds,
// the cached copy at our local caching server will already have expired, so the server will be forced
// to fetch a fresh copy from the authoritative server, and then return a fresh record with the full TTL of 3600 seconds.
if (rr->ProbeCount)
{
+ rr->ProbingConflictCount = 0;
// If we have no probe suppression time set, or it is in the past, set it now
if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
{
const domainname *target;
if (rr->AutoTarget)
{
- // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
- // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
- // with the port number in our advertised SRV record automatically tracking the external mapped port.
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP;
+ rr->AutoTarget = Target_AutoHostAndNATMAP;
}
target = GetServiceTarget(m, rr);
}
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal mDNSBool AuthRecordIncludesOrIsAWDL(const AuthRecord *const ar)
+{
+ return ((AuthRecordIncludesAWDL(ar) || mDNSPlatformInterfaceIsAWDL(ar->resrec.InterfaceID)) ? mDNStrue : mDNSfalse);
+}
+#endif
+
// Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
// Eventually we should unify this with GetServiceTarget() in uDNS.c
mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
{
domainname *const target = GetRRDomainNameTarget(&rr->resrec);
- const domainname *newname = &m->MulticastHostname;
+ const domainname *newname;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (AuthRecordIncludesOrIsAWDL(rr))
+ {
+ newname = &m->RandomizedHostname;
+ }
+ else
+#endif
+ {
+ newname = &m->MulticastHostname;
+ }
if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage)))
LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
rr->state = regState_Pending;
}
- rr->ProbeCount = 0;
- rr->ProbeRestartCount = 0;
- rr->AnnounceCount = 0;
- rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
- rr->LastAPTime = m->timenow - rr->ThisAPInterval;
- rr->expire = 0; // Forget about all the leases, start fresh
- rr->uselease = mDNStrue;
- rr->updateid = zeroID;
- rr->SRVChanged = mDNSfalse;
- rr->updateError = mStatus_NoError;
+ rr->ProbingConflictCount = 0;
+ rr->LastConflictPktNum = 0;
+ rr->ProbeRestartCount = 0;
+ rr->ProbeCount = 0;
+ rr->AnnounceCount = 0;
+ rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+ rr->LastAPTime = m->timenow - rr->ThisAPInterval;
+ rr->expire = 0; // Forget about all the leases, start fresh
+ rr->uselease = mDNStrue;
+ rr->updateid = zeroID;
+ rr->SRVChanged = mDNSfalse;
+ rr->updateError = mStatus_NoError;
// RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
// The records might already be registered with the server and hence could have NAT state.
if (rr->NATinfo.clientContext)
return (mDNSNULL);
}
-
mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
{
if (RRLocalOnly(rr))
return;
}
- if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
+ if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
{
- // If about to get rid of the last advertised service
- if (m->AutoTargetServices == 1)
- DeadvertiseAllInterfaceRecords(m);
-
- m->AutoTargetServices--;
- LogInfo("DecrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
+ NetworkInterfaceInfo *intf;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ DeadvertiseFlags flags = 0; // DeadvertiseFlags for non-AWDL interfaces.
+ DeadvertiseFlags flagsAWDL = 0; // DeadvertiseFlags for AWDL interfaces.
+ if (AuthRecordIncludesOrIsAWDL(rr))
+ {
+ if (AuthRecordIncludesAWDL(rr))
+ {
+ m->AutoTargetAWDLIncludedCount--;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
+ m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
+ if (m->AutoTargetAWDLIncludedCount == 0)
+ {
+ flags |= kDeadvertiseFlag_RandHostname;
+ if (m->AutoTargetAWDLOnlyCount == 0) flagsAWDL |= kDeadvertiseFlag_RandHostname;
+ }
+ }
+ else
+ {
+ m->AutoTargetAWDLOnlyCount--;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
+ m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
+ if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
+ {
+ flagsAWDL |= kDeadvertiseFlag_RandHostname;
+ }
+ }
+ if (flags || flagsAWDL)
+ {
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (!intf->Advertise) continue;
+ if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID))
+ {
+ if (flagsAWDL) DeadvertiseInterface(m, intf, flagsAWDL);
+ }
+ else
+ {
+ if (flags) DeadvertiseInterface(m, intf, flags);
+ }
+ }
+ }
+ if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
+ {
+ GetRandomUUIDLocalHostname(&m->RandomizedHostname);
+ }
+ }
+ else
+#endif
+ {
+ m->AutoTargetServices--;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
+ m->AutoTargetServices, ARDisplayString(m, rr));
+ if (m->AutoTargetServices == 0)
+ {
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->Advertise) DeadvertiseInterface(m, intf, kDeadvertiseFlag_NormalHostname);
+ }
+ }
+ }
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (!AuthRecord_uDNS(rr))
{
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
m->NumAllInterfaceRecords--;
- LogInfo("DecrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DecrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
}
-#endif // BONJOUR_ON_DEMAND
+#endif
+}
+
+mDNSlocal void AdvertiseNecessaryInterfaceRecords(mDNS *const m)
+{
+ NetworkInterfaceInfo *intf;
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->Advertise) AdvertiseInterfaceIfNeeded(m, intf);
+ }
}
mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
{
- mDNSBool enablingBonjour = 0;
+ mDNSBool enablingBonjour = mDNSfalse;
if (RRLocalOnly(rr))
{
return;
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (!AuthRecord_uDNS(rr))
{
m->NumAllInterfaceRecords++;
- LogInfo("IncrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
{
// Enable Bonjour immediately by scheduling network changed processing where
// we will join the multicast group on each active interface.
m->BonjourEnabled = 1;
- enablingBonjour = 1;
+ enablingBonjour = mDNStrue;
m->NetworkChanged = m->timenow;
}
}
}
-#endif // BONJOUR_ON_DEMAND
+#endif
- if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
+ if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
{
- m->AutoTargetServices++;
- LogInfo("IncrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (AuthRecordIncludesAWDL(rr))
+ {
+ m->AutoTargetAWDLIncludedCount++;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
+ m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
+ }
+ else if (mDNSPlatformInterfaceIsAWDL(rr->resrec.InterfaceID))
+ {
+ m->AutoTargetAWDLOnlyCount++;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
+ m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
+ }
+ else
+#endif
+ {
+ m->AutoTargetServices++;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "IncrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
+ m->AutoTargetServices, ARDisplayString(m, rr));
+ }
// If this is the first advertised service and we did not just enable Bonjour above, then
// advertise all the interface records. If we did enable Bonjour above, the interface records will
// be advertised during the network changed processing scheduled above, so no need
// to do it here.
- if ((m->AutoTargetServices == 1) && (enablingBonjour == 0))
- AdvertiseAllInterfaceRecords(m);
+ if (!enablingBonjour) AdvertiseNecessaryInterfaceRecords(m);
}
}
if (!m->NewLocalRecords) m->NewLocalRecords = rr;
// When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
// records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
- // Note that for AutoTunnel this should never happen, but this check makes the code future-proof.
while (*p) p=&(*p)->next;
*p = rr;
if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
// 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-only answers then
- // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
+ // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv)" 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)
}
// Sometimes the records don't complete proper deregistration i.e., don't wait for a response
// from the server. In that case, if the records have been part of a group update, clear the
- // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized
+ // state here.
rr->updateid = zeroID;
// We defer cleaning up NAT state only after sending goodbyes. This is important because
return(mStatus_BadReferenceErr);
}
- // <rdar://problem/7457925> Local-only questions don't get remove events for unique records
- // We may want to consider changing this code so that we generate local-only question "rmv"
- // events (and maybe goodbye packets too) for unique records as well as for shared records
- // Note: If we change the logic for this "if" statement, need to ensure that the code in
- // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else"
- // clause will execute here and the record will be cut from the list.
if (rr->WakeUp.HMAC.l[0] ||
- (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)))
+ (((RecordType == kDNSRecordTypeShared) || (rr->ARType == AuthRecordLocalOnly)) &&
+ (rr->RequireGoodbye || rr->AnsweredLocalQ)))
{
verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeDeregistering;
if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
rr->next = mDNSNULL;
- // Should we generate local remove events here?
- // i.e. something like:
- // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
-
verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeUnregistered;
}
else
{
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
// See if this record was also registered with any D2D plugins.
D2D_stop_advertising_record(r2);
#endif
}
}
-mDNSlocal int AnonInfoSpace(AnonymousInfo *info)
-{
- ResourceRecord *rr = info->nsec3RR;
-
- // 2 bytes for compressed name + type (2) class (2) TTL (4) rdlength (2) rdata (n)
- return (2 + 10 + rr->rdlength);
-}
-
mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
{
AuthRecord *rr;
AuthRecord *ResponseRecords = mDNSNULL;
AuthRecord **nrp = &ResponseRecords;
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
- int AnoninfoSpace = 0;
// Make a list of all our records that need to be unicast to this destination
for (rr = m->ResourceRecords; rr; rr=rr->next)
while (ResponseRecords && ResponseRecords->NR_AnswerTo)
{
rr = ResponseRecords;
- if (rr->resrec.AnonInfo)
- {
- AnoninfoSpace += AnonInfoSpace(rr->resrec.AnonInfo);
- rr->resrec.AnonInfo->SendNow = mDNSInterfaceMark;
- }
if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
- // Retract the limit by AnoninfoSpace which we need to put the AnoInfo option.
- newptr = PutResourceRecordTTLWithLimit(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl,
- m->omsg.data + (AllowedRRSpace(&m->omsg) - AnoninfoSpace));
+ newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
if (!newptr && m->omsg.h.numAnswers)
rr->RequireGoodbye = mDNStrue;
}
- // We have reserved the space for AnonInfo option. PutResourceRecord uses the
- // standard limit (AllowedRRSpace) and we should have space now.
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (rr->resrec.AnonInfo && rr->resrec.AnonInfo->SendNow == mDNSInterfaceMark)
- {
- ResourceRecord *nsec3RR = rr->resrec.AnonInfo->nsec3RR;
-
- newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAuthorities, nsec3RR);
- if (newptr)
- {
- responseptr = newptr;
- debugf("SendDelayedUnicastResponse: Added NSEC3 Record %s on %p", RRDisplayString(m, nsec3RR), intf->InterfaceID);
- }
- else
- {
- // We allocated space and we should not fail. Don't break, we need to clear the SendNow flag.
- LogMsg("SendDelayedUnicastResponse: ERROR!! Cannot Add NSEC3 Record %s on %p", RRDisplayString(m, nsec3RR), intf->InterfaceID);
- }
- rr->resrec.AnonInfo->SendNow = mDNSNULL;
- }
- }
-
// Add additionals, if there's space
while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
{
}
if (m->omsg.h.numAnswers)
- mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSfalse);
}
}
rr->resrec.RecordType = kDNSRecordTypeShared;
rr->RequireGoodbye = mDNSfalse;
rr->WakeUp.HMAC = zeroEthAddr;
- if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
+ if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv); rr->AnsweredLocalQ = mDNSfalse; }
mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal); // Don't touch rr after this
}
}
}
-mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *ar, mDNSInterfaceID InterfaceID)
-{
- mDNSBool result;
-
- if (ar->resrec.InterfaceID == mDNSInterface_Any)
- {
- result = mDNSPlatformValidRecordForInterface(ar, InterfaceID);
- }
- else
- {
- result = (ar->resrec.InterfaceID == InterfaceID);
- }
-
- return(result);
-}
-
// 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;
int numDereg = 0;
int numAnnounce = 0;
int numAnswer = 0;
- int AnoninfoSpace = 0;
mDNSu8 *responseptr = m->omsg.data;
mDNSu8 *newptr;
InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
}
- if (rr->resrec.AnonInfo)
- {
- int tmp = AnonInfoSpace(rr->resrec.AnonInfo);
-
- AnoninfoSpace += tmp;
- // Adjust OwnerRecordSpace/TraceRecordSpace which is used by PutRR_OS_TTL below so that
- // we have space to put in the NSEC3 record in the authority section.
- OwnerRecordSpace += tmp;
- TraceRecordSpace += tmp;
- }
-
if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
if (newptr) // If succeeded in sending, advance to next interface
{
- if (rr->resrec.AnonInfo)
- {
- debugf("SendResponses: Marking %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
- TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
- rr->resrec.AnonInfo->SendNow = intf->InterfaceID;
- }
-
// 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);
}
}
- // Get the reserved space back
- OwnerRecordSpace -= AnoninfoSpace;
- TraceRecordSpace -= AnoninfoSpace;
- newptr = responseptr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (rr->resrec.AnonInfo && rr->resrec.AnonInfo->SendNow == intf->InterfaceID)
- {
- ResourceRecord *nsec3RR = rr->resrec.AnonInfo->nsec3RR;
-
- newptr = PutRR_OS_TTL(newptr, &m->omsg.h.numAuthorities, nsec3RR, nsec3RR->rroriginalttl);
- if (newptr)
- {
- responseptr = newptr;
- debugf("SendResponses: Added NSEC3 %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
- TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
- }
- else
- {
- LogMsg("SendResponses: Cannot add NSEC3 %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
- TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
- }
- rr->resrec.AnonInfo->SendNow = mDNSNULL;
- }
- }
// Second Pass. Add additional records, if there's space.
newptr = responseptr;
for (rr = m->ResourceRecords; rr; rr=rr->next)
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, mDNSfalse);
- if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSfalse);
+ if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSfalse);
if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
if (++pktcount >= 1000) { LogMsg("SendResponses exceeded loop limit %d: giving up", pktcount); break; }
// There might be more things to send on this interface, so go around one more time and try again.
{
if (rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P)
LogInfo("SendResponses: No active interface %d to send: %d %02X %s",
- (uint32_t)rr->SendRNow, (uint32_t)rr->resrec.InterfaceID, rr->resrec.RecordType, ARDisplayString(m, rr));
+ IIDPrintable(rr->SendRNow), IIDPrintable(rr->resrec.InterfaceID), rr->resrec.RecordType, ARDisplayString(m, rr));
rr->SendRNow = mDNSNULL;
}
// so allow at most 1/10 second lateness
// 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
// (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
-#define CacheCheckGracePeriod(RR) ( \
- ((RR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
- ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50) : \
- ((RR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
- ((RR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
+#define CacheCheckGracePeriod(CR) ( \
+ ((CR)->CRActiveQuestion == mDNSNULL ) ? (60 * mDNSPlatformOneSecond) : \
+ ((CR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(CR)/50) : \
+ ((CR)->resrec.rroriginalttl > 10 ) ? (mDNSPlatformOneSecond) : \
+ ((CR)->resrec.rroriginalttl > 0 ) ? (mDNSPlatformOneSecond/10) : 0)
-#define NextCacheCheckEvent(RR) ((RR)->NextRequiredQuery + CacheCheckGracePeriod(RR))
+#define NextCacheCheckEvent(CR) ((CR)->NextRequiredQuery + CacheCheckGracePeriod(CR))
mDNSexport void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event)
{
mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353 && intf->SupportsUnicastMDNSResponse;
mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
- mDNSu8 anoninfo_space = q->AnonInfo ? AnonInfoSpace(q->AnonInfo) : 0;
- mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast - anoninfo_space, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
+ mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
if (!newptr)
{
debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
}
else
{
- mDNSu32 forecast = *answerforecast + anoninfo_space;
+ mDNSu32 forecast = *answerforecast;
const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- CacheRecord *rr;
+ CacheRecord *cr;
CacheRecord **ka = *kalistptrptr; // Make a working copy of the pointer we're going to update
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
- if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
- !(rr->resrec.RecordType & kDNSRecordTypeUniqueMask) && // which is a shared (i.e. not unique) record type
- rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
- rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
- SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
- rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) // If we have a resource record in our cache,
+ if (cr->resrec.InterfaceID == q->SendQNow && // received on this interface
+ !(cr->resrec.RecordType & kDNSRecordTypeUniqueMask) && // which is a shared (i.e. not unique) record type
+ cr->NextInKAList == mDNSNULL && ka != &cr->NextInKAList && // which is not already in the known answer list
+ cr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
+ SameNameCacheRecordAnswersQuestion(cr, q) && // which answers our question
+ cr->TimeRcvd + TicksTTL(cr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
{
// We don't want to include unique records in the Known Answer section. The Known Answer section
// which we have a unique record already in our cache, then including that unique record as a
// Known Answer, so as to suppress the only answer we were expecting to get, makes little sense.
- *ka = rr; // Link this record into our known answer chain
- ka = &rr->NextInKAList;
+ *ka = cr; // Link this record into our known answer chain
+ ka = &cr->NextInKAList;
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
- forecast += 12 + rr->resrec.rdestimate;
+ forecast += 12 + cr->resrec.rdestimate;
// If we're trying to put more than one question in this packet, and it doesn't fit
// then undo that last question and try again next time
if (query->h.numQuestions > 1 && newptr + forecast >= limit)
*kalistptrptr = ka; // Update the known answer list pointer
if (ucast) q->ExpectUnicastResp = NonZeroTime(m->timenow);
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // For every resource record in our cache,
- if (rr->resrec.InterfaceID == q->SendQNow && // received on this interface
- rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not in the known answer list
- SameNameRecordAnswersQuestion(&rr->resrec, q)) // which answers our question
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) // For every resource record in our cache,
+ if (cr->resrec.InterfaceID == q->SendQNow && // received on this interface
+ cr->NextInKAList == mDNSNULL && ka != &cr->NextInKAList && // which is not in the known answer list
+ SameNameCacheRecordAnswersQuestion(cr, q)) // which answers our question
{
- rr->UnansweredQueries++; // indicate that we're expecting a response
- rr->LastUnansweredTime = m->timenow;
- SetNextCacheCheckTimeForRecord(m, rr);
+ cr->UnansweredQueries++; // indicate that we're expecting a response
+ cr->LastUnansweredTime = m->timenow;
+ SetNextCacheCheckTimeForRecord(m, cr);
}
return(mDNStrue);
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 (SameNameCacheRecordAnswersQuestion(cr, 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);
// We forecast: qname (n) type (2) class (2)
mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- const CacheRecord *rr;
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next) // If we have a resource record in our cache,
- if (rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
- SameNameRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
- rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
- rr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0) // and we'll ask at least once again before NextRequiredQuery
+ const CacheRecord *cr;
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next) // If we have a resource record in our cache,
+ if (cr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
+ SameNameCacheRecordAnswersQuestion(cr, q) && // which answers our question
+ cr->TimeRcvd + TicksTTL(cr)/2 - m->timenow >= 0 && // and it is less than half-way to expiry
+ cr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0) // and we'll ask at least once again before NextRequiredQuery
{
// We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
- forecast += 12 + rr->resrec.rdestimate;
+ forecast += 12 + cr->resrec.rdestimate;
if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate
}
return(mDNStrue);
ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(cr)/20, cr->resrec.InterfaceID);
// For uDNS queries (TargetQID non-zero) we adjust LastQTime,
// and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
- if (q->Target.type)
- {
- q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
- }
- else if (!mDNSOpaque16IsZero(q->TargetQID))
+ if (!mDNSOpaque16IsZero(q->TargetQID))
{
q->LastQTime = m->timenow - q->ThisQInterval;
cr->UnansweredQueries++;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
q = m->CurrentQuestion;
- if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
- {
- mDNSu8 *qptr = m->omsg.data;
- const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
-
- // 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(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->UseBackgroundTrafficClass);
- q->ThisQInterval *= QuestionIntervalStep;
- }
- if (q->ThisQInterval > MaxQuestionInterval)
- q->ThisQInterval = MaxQuestionInterval;
- q->LastQTime = m->timenow;
- q->LastQTxTime = m->timenow;
- q->RecentAnswerPkts = 0;
- q->SendQNow = mDNSNULL;
- q->ExpectUnicastResp = NonZeroTime(m->timenow);
- }
- else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+ if (mDNSOpaque16IsZero(q->TargetQID) && TimeToSendThisQuestion(q, m->timenow))
{
//LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
q->SendQNow = mDNSInterfaceMark; // Mark this question for sending on all interfaces
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
{
if (mDNSOpaque16IsZero(q->TargetQID)
- && (q->SendQNow || (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+ && (q->SendQNow || (ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
{
// If at least halfway to next query time, advance to next interval
// If less than halfway to next query time, then
else if ((Suppress = SuppressOnThisInterface(q->DupSuppress, intf)) ||
BuildQuestion(m, intf, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
{
- // We successfully added the question to the packet. Make sure that
- // we also send the NSEC3 record if required. BuildQuestion accounted for
- // the space.
- //
- // Note: We don't suppress anonymous questions and hence Suppress should always
- // be zero.
-
if (Suppress)
m->mDNSStats.DupQuerySuppressions++;
- if (!Suppress && q->AnonInfo)
- {
- debugf("SendQueries: marking for question %##s, Suppress %d", q->qname.c, Suppress);
- q->AnonInfo->SendNow = intf->InterfaceID;
- }
q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
if (q->WakeOnResolveCount)
{
}
// use background traffic class if any included question requires it
- if (q->UseBackgroundTrafficClass)
+ if (q->UseBackgroundTraffic)
{
useBackgroundTrafficClass = mDNStrue;
}
}
}
- for (q = m->Questions; q; q = q->next)
- {
- if (q->AnonInfo && q->AnonInfo->SendNow == intf->InterfaceID)
- {
- mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, q->AnonInfo->nsec3RR);
- if (newptr)
- {
- debugf("SendQueries: Added NSEC3 record %s on InterfaceID %p", RRDisplayString(m, q->AnonInfo->nsec3RR), intf->InterfaceID);
- queryptr = newptr;
- }
- else
- {
- LogMsg("SendQueries: ERROR!! Cannot add NSEC3 record %s on InterfaceID %p", RRDisplayString(m, q->AnonInfo->nsec3RR), intf->InterfaceID);
- }
- q->AnonInfo->SendNow = mDNSNULL;
- }
- }
-
if (queryptr > m->omsg.data)
{
// If we have data to send, add OWNER/TRACER/OWNER+TRACER option if necessary, then send packet
if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
- debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %p",
+ debugf("SendQueries: Sending %d Question%s %d Answer%s %d Update%s on %d (%s)",
m->omsg.h.numQuestions, m->omsg.h.numQuestions == 1 ? "" : "s",
m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
- m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", intf->InterfaceID);
- if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL, useBackgroundTrafficClass);
- if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL, useBackgroundTrafficClass);
+ m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", IIDPrintable(intf->InterfaceID), intf->ifname);
+ if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, useBackgroundTrafficClass);
+ if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, useBackgroundTrafficClass);
if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
if (++pktcount >= 1000)
{ LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
{
if (ar->ARType != AuthRecordLocalOnly && ar->ARType != AuthRecordP2P)
LogInfo("SendQueries: No active interface %d to send probe: %d %s",
- (uint32_t)ar->SendRNow, (uint32_t)ar->resrec.InterfaceID, ARDisplayString(m, ar));
+ IIDPrintable(ar->SendRNow), IIDPrintable(ar->resrec.InterfaceID), ARDisplayString(m, ar));
ar->SendRNow = mDNSNULL;
}
// so don't log the warning in that case.
if (q->InterfaceID != mDNSInterface_BLE)
LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)",
- (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+ IIDPrintable(q->SendQNow), x ? "new" : "old", IIDPrintable(q->InterfaceID), q->qname.c, DNSTypeName(q->qtype));
q->SendQNow = mDNSNULL;
}
q->CachedAnswerNeedsUpdate = mDNSfalse;
debugf("ResetQuestionState: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
}
+mDNSlocal void AdjustUnansweredQueries(mDNS *const m, CacheRecord *const rr)
+{
+ const mDNSs32 expireTime = RRExpireTime(rr);
+ const mDNSu32 interval = TicksTTL(rr) / 20; // Calculate 5% of the cache record's TTL.
+ mDNSu32 rem;
+
+ // If the record is expired or UnansweredQueries is already at the max, then return early.
+ if (((m->timenow - expireTime) >= 0) || (rr->UnansweredQueries >= MaxUnansweredQueries)) return;
+
+ if (interval == 0)
+ {
+ LogInfo("AdjustUnansweredQueries: WARNING: unusually small TTL (%d ticks) for %s", TicksTTL(rr), CRDisplayString(m, rr));
+ return;
+ }
+
+ // Calculate the number of whole 5% TTL intervals between now and expiration time.
+ rem = ((mDNSu32)(expireTime - m->timenow)) / interval;
+
+ // Calculate the expected number of remaining refresher queries.
+ // Refresher queries are sent at the start of the last MaxUnansweredQueries intervals.
+ if (rem > MaxUnansweredQueries) rem = MaxUnansweredQueries;
+
+ // If the current number of remaining refresher queries is greater than expected, then at least one refresher query time
+ // was missed. This can happen if the cache record didn't have an active question during any of the times at which
+ // refresher queries would have been sent if the cache record did have an active question. The cache record's
+ // UnansweredQueries count needs to be adjusted to avoid a burst of refresher queries being sent in an attempt to make up
+ // for lost time. UnansweredQueries is set to the number of queries that would have been sent had the cache record had an
+ // active question from the 80% point of its lifetime up to now, with one exception: if the number of expected remaining
+ // refresher queries is zero (because timenow is beyond the 95% point), then UnansweredQueries is set to
+ // MaxUnansweredQueries - 1 so that at least one refresher query is sent before the cache record expires.
+ // Note: The cast is safe because rem is never greater than MaxUnansweredQueries; the comparison has to be signed.
+ if ((MaxUnansweredQueries - rr->UnansweredQueries) > (mDNSs32)rem)
+ {
+ if (rem == 0) rem++;
+ rr->UnansweredQueries = (mDNSu8)(MaxUnansweredQueries - rem);
+ }
+}
+
// 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,
return;
}
- if (QuerySuppressed(q))
+ if (q->Suppressed && (AddRecord != QC_suppressed))
{
// If the query is suppressed, then we don't want to answer from the cache. But if this query is
// supposed to time out, we still want to callback the clients. We do this only for TimeoutQuestions
if (AddRecord == QC_add && Question_uDNS(q) && rr->resrec.RecordType != kDNSRecordTypePacketNegative &&
q->allowExpired != AllowExpired_None && rr->resrec.mortality == Mortality_Mortal ) rr->resrec.mortality = Mortality_Immortal; // Update a non-expired cache record to immortal if appropriate
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname)
{
const domainname * queryName;
responseLatencyMs = 0;
}
- MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, q->metrics.expiredAnswerState, responseLatencyMs, isForCellular);
+ MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, q->metrics.expiredAnswerState, q->metrics.dnsOverTCPState, responseLatencyMs, isForCellular);
q->metrics.answered = mDNStrue;
}
- if (q->metrics.querySendCount > 0)
- {
- MetricsUpdateDNSResolveStats(queryName, &rr->resrec, isForCellular);
- }
}
#endif
// Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q && rr->resrec.mortality != Mortality_Ghost)
{
- if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d",
rr->CRActiveQuestion, q, CRDisplayString(m,rr), q->CurrentAnswers);
- rr->CRActiveQuestion = q; // We know q is non-null
+ if (!rr->CRActiveQuestion)
+ {
+ m->rrcache_active++; // If not previously active, increment rrcache_active count
+ AdjustUnansweredQueries(m, rr); // Adjust UnansweredQueries in case the record missed out on refresher queries
+ }
+ rr->CRActiveQuestion = q; // We know q is non-null
SetNextCacheCheckTimeForRecord(m, rr);
}
if (rr->DelayDelivery) return; // We'll come back later when CacheRecordDeferredAdd() calls us
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
// If DNS64StateMachine() returns true, then the question was restarted as a different question, so return.
if (!mDNSOpaque16IsZero(q->TargetQID) && DNS64StateMachine(m, q, &rr->resrec, AddRecord)) return;
#endif
}
else
{
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
if (DNS64ShouldAnswerQuestion(q, &rr->resrec))
{
DNS64AnswerCurrentQuestion(m, &rr->resrec, AddRecord);
}
mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
}
+ // Note: Proceed with caution after this point because client callback function
+ // invoked above is allowed to do anything, such as starting/stopping queries
+ // (including this one itself, or the next or previous query in the linked list),
+ // registering/deregistering records, starting/stopping NAT traversals, etc.
+
// If this is an "Add" operation and this question needs validation, validate the response.
// In the case of negative responses, extra care should be taken. Negative cache records are
// used for many purposes. For example,
}
}
-mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
+mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *cr)
{
- rr->DelayDelivery = 0;
+ cr->DelayDelivery = 0;
if (m->CurrentQuestion)
LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)",
m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
DNSQuestion *q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (CacheRecordAnswersQuestion(cr, q))
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
// 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)
+mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *cr)
{
DNSQuestion *q;
// counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
{
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ if (CacheRecordAnswersQuestion(cr, q))
{
// If this question is one that's actively sending queries, and it's received ten answers within one
// second of sending the last query packet, then that indicates some radical network topology change,
SetNextQueryTime(m,q);
}
}
- verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c,
- DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ?
- &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ?
- rr->resrec.rDNSServer->port : zeroIPPort), q);
+ verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", cr, cr->resrec.name->c,
+ DNSTypeName(cr->resrec.rrtype), cr->resrec.rroriginalttl, cr->resrec.rDNSServer ?
+ &cr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(cr->resrec.rDNSServer ?
+ cr->resrec.rDNSServer->port : zeroIPPort), q);
q->CurrentAnswers++;
q->unansweredQueries = 0;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
if (q->CurrentAnswers > 4000)
{
static int msgcount = 0;
if (msgcount++ < 10)
LogMsg("CacheRecordAdd: %##s (%s) has %d answers; shedding records to resist DOS attack",
q->qname.c, DNSTypeName(q->qtype), q->CurrentAnswers);
- rr->resrec.rroriginalttl = 0;
- rr->UnansweredQueries = MaxUnansweredQueries;
+ cr->resrec.rroriginalttl = 0;
+ cr->UnansweredQueries = MaxUnansweredQueries;
}
}
}
- if (!rr->DelayDelivery)
+ if (!cr->DelayDelivery)
{
if (m->CurrentQuestion)
LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ if (CacheRecordAnswersQuestion(cr, q))
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
m->CurrentQuestion = mDNSNULL;
}
- SetNextCacheCheckTimeForRecord(m, rr);
+ SetNextCacheCheckTimeForRecord(m, cr);
}
// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
// 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)
+mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *cr)
{
LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
if (m->CurrentQuestion)
while (m->CurrentQuestion)
{
DNSQuestion *q = m->CurrentQuestion;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
+ if (CacheRecordAnswersQuestion(cr, q))
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_addnocache); // QC_addnocache means "don't expect remove events for this"
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
m->CurrentQuestion = q->next;
}
// Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
// If new questions are created as a result of invoking client callbacks, they will be added to
// 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
+// cr 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,
// 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)
+mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *cr)
{
if (m->CurrentQuestion)
LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)",
// response. A cache may be present that answers this question e.g., cache entry generated
// before the question became suppressed. We need to skip the suppressed questions here as
// the RMV event has already been generated.
- if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q) &&
- (q->allowExpired == AllowExpired_None || rr->resrec.mortality == Mortality_Mortal))
+ if (!q->Suppressed && CacheRecordAnswersQuestion(cr, q) &&
+ (q->allowExpired == AllowExpired_None || cr->resrec.mortality == Mortality_Mortal))
{
- verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
+ verbosedebugf("CacheRecordRmv %p %s", cr, CRDisplayString(m, cr));
q->FlappingInterface1 = mDNSNULL;
q->FlappingInterface2 = mDNSNULL;
else
{
q->CurrentAnswers--;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
}
// If we have dropped below the answer threshold for this mDNS question,
LogInfo("CacheRecordRmv: (%s) %##s dropped below threshold of %d answers",
DNSTypeName(q->qtype), q->qname.c, q->BrowseThreshold);
}
- if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
+ if (cr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
{
if ((q->CurrentAnswers == 0) && mDNSOpaque16IsZero(q->TargetQID))
{
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, rr->resrec.InterfaceID, 0);
+ ReconfirmAntecedents(m, &q->qname, q->qnamehash, cr->resrec.InterfaceID, 0);
}
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_rmv);
}
}
if (m->CurrentQuestion == q) // If m->CurrentQuestion was not auto-advanced, do it ourselves now
mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
{
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
unsigned int i;
for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
#endif
}
r->resrec.name = mDNSNULL;
- if (r->resrec.AnonInfo)
- {
- debugf("ReleaseCacheRecord: freeing AnonInfo for %##s (%s)", r->resrec.name->c, DNSTypeName(r->resrec.rrtype));
- FreeAnonInfo((void *)r->resrec.AnonInfo);
- }
- r->resrec.AnonInfo = mDNSNULL;
-
if (!r->resrec.InterfaceID)
{
m->rrcache_totalused_unicast -= r->resrec.rdlength;
// a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to
// MaxQuestionInterval. If we have inactive questions referring to negative cache entries,
// don't ressurect them as they will deliver duplicate "No such Record" ADD events
- if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q))
+ if (((mDNSOpaque16IsZero(q->TargetQID) && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)) ||
+ (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived)) && ActiveQuestion(q))
{
q->ThisQInterval = InitialQuestionInterval;
q->LastQTime = m->timenow - q->ThisQInterval;
m->CurrentRecord = mDNSNULL;
return mDNStrue;
}
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_add);
if (m->CurrentQuestion != q)
break; // If callback deleted q, then we're finished here
}
// Today, we suppress questions (not send them on the wire) for several reasons e.g.,
// AAAA query is suppressed because no IPv6 capability or PID is not allowed to make
-// DNS requests. We need to temporarily suspend the suppress status so that we can
-// deliver a negative response (AnswerCurrentQuestionWithResourceRecord does not answer
-// suppressed questions) and reset it back. In the future, if there are other
-// reasons for suppressing the query, this function should be updated.
+// DNS requests.
mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q)
{
- mDNSBool SuppressQuery;
- mDNSBool DisallowPID;
-
- // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response, just
- // deactivate the DNSQuestion.
- if (!q->ReturnIntermed)
+ // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response,
+ // just deactivate the DNSQuestion.
+ if (q->ReturnIntermed)
+ {
+ GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
+ }
+ else
{
q->ThisQInterval = 0;
- return;
}
-
- SuppressQuery = q->SuppressQuery;
- DisallowPID = q->DisallowPID;
-
- // make sure that QuerySuppressed() returns false
- q->SuppressQuery = mDNSfalse;
- q->DisallowPID = mDNSfalse;
-
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
-
- q->SuppressQuery = SuppressQuery;
- q->DisallowPID = DisallowPID;
}
mDNSlocal void AnswerNewQuestion(mDNS *const m)
{
mDNSBool ShouldQueryImmediately = mDNStrue;
DNSQuestion *const q = m->NewQuestions; // Grab the question we're going to answer
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
if (!mDNSOpaque16IsZero(q->TargetQID)) DNS64HandleNewQuestion(m, q);
#endif
CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- mDNSBool AnsweredFromCache = mDNSfalse;
verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
// If the client's question callback deletes the question, then m->CurrentQuestion will
// be advanced, and we'll exit out of the loop
m->lock_rrcache = 1;
- if (m->CurrentQuestion)
- LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
- m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ if (m->CurrentQuestion) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d->Q%d] AnswerNewQuestion ERROR m->CurrentQuestion already set: " PRI_DM_NAME " (" PUB_S ")",
+ m->CurrentQuestion->request_id, mDNSVal16(m->CurrentQuestion->TargetQID),
+ DM_NAME_PARAM(m->CurrentQuestion->qname.c), DNSTypeName(m->CurrentQuestion->qtype));
+ }
+
m->CurrentQuestion = q; // Indicate which question we're answering, so we'll know if it gets deleted
if (q->NoAnswer == NoAnswer_Fail)
{
- LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d->Q%d] AnswerNewQuestion: NoAnswer_Fail " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
+
MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer);
q->NoAnswer = NoAnswer_Normal; // Temporarily turn off answer suppression
AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
if (AnswerQuestionWithLORecord(m, q, mDNSfalse))
goto exit;
- // If we are not supposed to answer this question, generate a negative response.
- // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question
- //
// If it is a question trying to validate some response, it already checked the cache for a response. If it still
// reissues a question it means it could not find the RRSIGs. So, we need to bypass the cache check and send
// the question out.
- if (QuerySuppressed(q))
+ if (q->Suppressed)
{
AnswerSuppressedQuestion(m, q);
}
else if (!q->ValidatingResponse)
{
- CacheRecord *rr;
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ CacheRecord *cr;
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
{
// SecsSinceRcvd is whole number of elapsed seconds, rounded down
- mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
- if (rr->resrec.rroriginalttl <= SecsSinceRcvd && q->allowExpired != AllowExpired_AllowExpiredAnswers) continue; // Go to next one in loop
+ mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - cr->TimeRcvd)) / mDNSPlatformOneSecond;
+ mDNSBool IsExpired = (cr->resrec.rroriginalttl <= SecsSinceRcvd);
+ if (IsExpired && q->allowExpired != AllowExpired_AllowExpiredAnswers) continue; // Go to next one in loop
// If this record set is marked unique, then that means we can reasonably assume we have the whole set
// -- we don't need to rush out on the network and query immediately to see if there are more answers out there
- if ((rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
+ if ((cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
ShouldQueryImmediately = mDNSfalse;
q->CurrentAnswers++;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
- AnsweredFromCache = mDNStrue;
-#if AWD_METRICS
- if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = ExpiredAnswer_AnsweredWithExpired;
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = IsExpired ? ExpiredAnswer_AnsweredWithExpired : ExpiredAnswer_AnsweredWithCache;
#endif
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
- else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
+ else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(cr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
ShouldQueryImmediately = mDNSfalse;
}
// We don't use LogInfo for this "Question deleted" message because it happens so routinely that
// it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs.
if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; }
- // Neither a local record nor a cache entry could answer this question. If this question need to be retried
- // with search domains, generate a negative response which will now retry after appending search domains.
- // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed,
- // we will retry with search domains.
- if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains)
- {
- LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
- }
-
- if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; }
-
+ q->InitialCacheMiss = mDNStrue; // Initial cache check is done, so mark as a miss from now on
if (q->allowExpired == AllowExpired_AllowExpiredAnswers)
{
q->allowExpired = AllowExpired_MakeAnswersImmortal; // After looking through the cache for an answer, demote to make immortal
if (q->firstExpiredQname.c[0]) // If an original query name was saved on an expired answer, start it over in case it is updated
{
- LogMsg("AnswerNewQuestion: Restarting original question %p firstExpiredQname %##s for allowExpiredAnswers question", q, &q->firstExpiredQname.c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d->Q%d] AnswerNewQuestion: Restarting original question %p firstExpiredQname " PRI_DM_NAME " for allowExpiredAnswers question",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->firstExpiredQname.c));
mDNS_StopQuery_internal(m, q); // Stop old query
AssignDomainName(&q->qname, &q->firstExpiredQname); // Update qname
q->qnamehash = DomainNameHashValue(&q->qname); // and namehash
// Hence we don't execute the following block of code for those cases.
if (ShouldQueryImmediately && ActiveQuestion(q))
{
- debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ debugf("[R%d->Q%d] AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->request_id, mDNSVal16(q->TargetQID), q->qname.c, DNSTypeName(q->qtype));
q->ThisQInterval = InitialQuestionInterval;
q->LastQTime = m->timenow - q->ThisQInterval;
if (mDNSOpaque16IsZero(q->TargetQID)) // For mDNS, spread packets to avoid a burst of simultaneous queries
if (LocalOnlyRecordAnswersQuestion(rr, q))
{
retEv = mDNStrue;
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
{
- AuthRecord *rr = m->CurrentRecord;
- m->CurrentRecord = rr->next;
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ AuthRecord *ar = m->CurrentRecord;
+ m->CurrentRecord = ar->next;
+ if (AuthRecordAnswersQuestion(ar, q))
{
retEv = mDNStrue;
- AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerLocalQuestionWithLocalAuthRecord(m, ar, QC_add);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
if (!m->rrcache_free && m->MainCallback)
{
if (m->rrcache_totalused != m->rrcache_size)
- LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
- m->rrcache_totalused, m->rrcache_size);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "GetFreeCacheRR: count mismatch: m->rrcache_totalused %u != m->rrcache_size %u",
+ m->rrcache_totalused, m->rrcache_size);
+ }
// We don't want to be vulnerable to a malicious attacker flooding us with an infinite
// number of bogus records so that we keep growing our cache until the machine runs out of memory.
// 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 > 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);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "Possible denial-of-service attack in progress: m->rrcache_size %u; m->rrcache_active %u",
+ m->rrcache_size, m->rrcache_active);
+ }
else
{
mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
else ReleaseCacheGroup(m, cp);
}
}
- LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
- oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "GetCacheEntity recycled %d records to reduce cache from %d to %d",
+ oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
}
if (m->rrcache_free) // If there are records in the free list, take one
m->rrcache_free = e->next;
if (++m->rrcache_totalused >= m->rrcache_report)
{
- LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "RR Cache now using %u 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;
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);
+ r->resrec.rdata = (RData*) mDNSPlatformMemAllocateClear(sizeofRDataHeader + RDLength);
if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
}
cg->members = mDNSNULL;
cg->rrcache_tail = &cg->members;
if (namelen > sizeof(cg->namestorage))
- cg->name = mDNSPlatformMemAllocate(namelen);
+ cg->name = (domainname *) mDNSPlatformMemAllocate(namelen);
else
cg->name = (domainname*)cg->namestorage;
if (!cg->name)
{
debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr));
rr->resrec.RecordType = kDNSRecordTypeShared;
- AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse);
+ AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv);
if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now
{
rr->resrec.RecordType = kDNSRecordTypeDeregistering;
mDNS_SendKeepalives(m);
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (m->NextBonjourDisableTime && (m->timenow - m->NextBonjourDisableTime >= 0))
{
// Schedule immediate network change processing to leave the multicast group
LogInfo("mDNS_Execute: Scheduled network changed processing to leave multicast group.");
}
-#endif // BONJOUR_ON_DEMAND
+#endif
// Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0)
{
m->AnnounceOwner = 0;
-
- // This is a good time to reset the delay counter used to prevent spurious conflicts
- m->DelayConflictProcessing = 0;
}
if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
if (LocalRecordReady(rr))
{
debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
- AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_add);
}
else if (!rr->next)
{
{
m->NewLocalOnlyRecords = mDNSfalse;
for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
+ {
for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
{
for (i=0; i<100 && ag->NewLocalOnlyRecords; i++)
if (LocalRecordReady(rr))
{
debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
- AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+ AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_add);
}
else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr));
}
// We limit about 100 per AuthGroup that can be serviced at a time
if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit");
}
+ }
}
// 5. See what packets we need to send
// In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
{
- // For now this AutoTunnel stuff is specific to Mac OS X.
- // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
-#if APPLE_OSX_mDNSResponder
- // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
- // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
- // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
- // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
- // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic
- // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query.
-
- if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) &&
- !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
- {
- question->NoAnswer = NoAnswer_Suspended;
- AddNewClientTunnel(question);
- return;
- }
-#endif // APPLE_OSX_mDNSResponder
-
if (!question->DuplicateOf)
{
- debugf("ActivateUnicastQuery: %##s %s%s%s",
- question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+ debugf("ActivateUnicastQuery: %##s %s%s",
+ question->qname.c, DNSTypeName(question->qtype), ScheduleImmediately ? " ScheduleImmediately" : "");
question->CNAMEReferrals = 0;
if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
if (question->LongLived)
{
- question->state = LLQ_InitialRequest;
+ question->state = LLQ_Init;
question->id = zeroOpaque64;
question->servPort = zeroIPPort;
if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
// If the query is suppressed, the RMV events won't be delivered
if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; }
- // SuppressQuery status does not affect questions that are answered using local records
+ // Suppressed status does not affect questions that are answered using local records
if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; }
- LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q,
- q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig);
+ LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d", q,
+ q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains);
mDNS_StopQuery_internal(m, q);
- // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache
- // and then search domains should be appended. At the beginning, qnameOrig was NULL.
- if (q->qnameOrig)
- {
- LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig);
- AssignDomainName(&q->qname, q->qnameOrig);
- mDNSPlatformMemFree(q->qnameOrig);
- q->qnameOrig = mDNSNULL;
- q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
- }
- q->SearchListIndex = 0;
+ if (q->ResetHandler) q->ResetHandler(q);
q->next = restart;
restart = q;
}
newrdlength += 2;
rdsize = newrdlength > sizeof(RDataBody) ? newrdlength : sizeof(RDataBody);
- newrd = mDNSPlatformMemAllocate(sizeof(RData) - sizeof(RDataBody) + rdsize);
+ newrd = (RData *) mDNSPlatformMemAllocate(sizeof(RData) - sizeof(RDataBody) + rdsize);
if (!newrd) { LogMsg("UpdateKeepaliveRData: ptr NULL"); return mStatus_NoMemoryErr; }
newrd->MaxRDLength = (mDNSu16) rdsize;
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, mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSfalse);
if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv4 && intf->NetWakeResolve[sps].ThisQInterval == -1)
{
mDNSlocal void mDNSCoreStoreProxyRR(mDNS *const m, const mDNSInterfaceID InterfaceID, AuthRecord *const rr)
{
- AuthRecord *newRR = mDNSPlatformMemAllocate(sizeof(AuthRecord));
-
+ AuthRecord *newRR = (AuthRecord *) mDNSPlatformMemAllocateClear(sizeof(*newRR));
if (newRR == mDNSNULL)
{
LogSPS("%s : could not allocate memory for new resource record", __func__);
return;
}
- mDNSPlatformMemZero(newRR, sizeof(AuthRecord));
mDNS_SetupResourceRecord(newRR, mDNSNULL, InterfaceID, rr->resrec.rrtype,
rr->resrec.rroriginalttl, rr->resrec.RecordType,
rr->ARType, mDNSNULL, mDNSNULL);
{
AuthRecord *rr;
- LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+ PUB_S " (old state %d) at %d", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
if (sleep && !m->SleepState) // Going to sleep
{
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);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10);
}
else
#ifndef UNICAST_DISABLED
SuspendLLQs(m);
#endif
-#if APPLE_OSX_mDNSResponder
- RemoveAutoTunnel6Record(m);
-#endif
- LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
- m->SleepState == SleepState_Transferring ? "Transferring" :
- m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "mDNSCoreMachineSleep: m->SleepState %d (" PUB_S ") seq %d",
+ m->SleepState,
+ m->SleepState == SleepState_Transferring ? "Transferring" :
+ m->SleepState == SleepState_Sleeping ? "Sleeping" : "?", m->SleepSeqNum);
mDNS_Unlock(m);
}
else if (!sleep) // Waking up
mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, m->SPSFeatureFlags);
}
m->mDNSStats.Wakes++;
- m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
// ... and the same for NextSPSAttempt
for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
// and reactivtate service registrations
m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
- LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
// 2. Re-validate our cache records
currtime = mDNSPlatformUTC();
if (diff >= remain || diff > (2 * 24 * 3600))
{
- LogInfo("mDNSCoreMachineSleep: %s: Purging cache entry SleptTime %d, Remaining TTL %d",
- CRDisplayString(m, cr), diff, remain);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: " PRI_S ": Purging cache entry SleptTime %d, Remaining TTL %d",
+ CRDisplayString(m, cr), diff, remain);
mDNS_PurgeCacheResourceRecord(m, cr);
continue;
}
cr->TimeRcvd -= (diff * mDNSPlatformOneSecond);
if (m->timenow - (cr->TimeRcvd + ((mDNSs32)uTTL * mDNSPlatformOneSecond)) >= 0)
{
- LogInfo("mDNSCoreMachineSleep: %s: Purging after adjusting the remaining TTL %d by %d seconds",
- CRDisplayString(m, cr), remain, diff);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: " PRI_S ": Purging after adjusting the remaining TTL %d by %d seconds",
+ CRDisplayString(m, cr), remain, diff);
mDNS_PurgeCacheResourceRecord(m, cr);
}
else
{
- LogInfo("mDNSCoreMachineSleep: %s: Adjusted the remain ttl %u by %d seconds", CRDisplayString(m, cr), remain, diff);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "mDNSCoreMachineSleep: " PRI_S ": Adjusted the remain ttl %u by %d seconds",
+ CRDisplayString(m, cr), remain, diff);
}
}
}
// But if we do get a network configuration change, mDNSMacOSXNetworkChanged will call uDNS_SetupDNSConfig, which
// will call mDNS_SetPrimaryInterfaceInfo, which will call RecreateNATMappings to refresh them, potentially sooner
// than five seconds from now.
- LogInfo("mDNSCoreMachineSleep: recreating NAT mappings in 5 seconds");
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "mDNSCoreMachineSleep: recreating NAT mappings in 5 seconds");
RecreateNATMappings(m, mDNSPlatformOneSecond * 5);
mDNS_Unlock(m);
}
{
if (rr->state == regState_Refresh && rr->tcp)
{ LogSPS("mDNSCoreReadyForSleep: waiting for Record updateIntID 0x%x 0x%x (updateid %d) %s", rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
- #if APPLE_OSX_mDNSResponder
- if (!RecordReadyForSleep(rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
- #endif
}
mDNS_Unlock(m);
const mDNSu8 *const limit = response->data + sizeof(response->data);
const mDNSu8 *ptr = query->data;
AuthRecord *rr;
- mDNSu32 maxttl = mDNSMaximumTTLSeconds;
+ mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
int i;
// Initialize the response fields so we can answer the questions
if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
+#if defined(__clang_analyzer__)
+ // Get rid of analyzer warnings about ourptr and pktptr pointing to garbage after retruning from putRData().
+ // There are no clear indications from the analyzer of the cause of the supposed problem.
+ mDNSPlatformMemZero(ourdata, 1);
+ mDNSPlatformMemZero(pktdata, 1);
+#endif
ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
return(-1);
}
+mDNSlocal mDNSBool PacketRecordMatches(const AuthRecord *const rr, const CacheRecord *const pktrr, const AuthRecord *const master)
+{
+ if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
+ {
+ const AuthRecord *r2 = rr;
+ while (r2->DependentOn) r2 = r2->DependentOn;
+ if (r2 == master) return(mDNStrue);
+ }
+ return(mDNSfalse);
+}
+
// See if we have an authoritative record that's identical to this packet record,
// whose canonical DependentOn record is the specified master record.
// The DependentOn pointer is typically used for the TXT record of service registrations
const AuthRecord *r1;
for (r1 = m->ResourceRecords; r1; r1=r1->next)
{
- if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
- {
- const AuthRecord *r2 = r1;
- while (r2->DependentOn) r2 = r2->DependentOn;
- if (r2 == master) return(mDNStrue);
- }
+ if (PacketRecordMatches(r1, pktrr, master)) return(mDNStrue);
}
for (r1 = m->DuplicateRecords; r1; r1=r1->next)
{
- if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
- {
- const AuthRecord *r2 = r1;
- while (r2->DependentOn) r2 = r2->DependentOn;
- if (r2 == master) return(mDNStrue);
- }
+ if (PacketRecordMatches(r1, pktrr, master)) return(mDNStrue);
}
return(mDNSfalse);
}
{
ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
if (!ptr) break;
- if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+ if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && CacheRecordAnswersQuestion(&m->rec.r, q))
{
FoundUpdate = mDNStrue;
if (PacketRRConflict(m, our, &m->rec.r))
const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
{
- mDNSBool FromLocalSubnet = srcaddr && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+ const mDNSBool FromLocalSubnet = mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
AuthRecord *ResponseRecords = mDNSNULL;
AuthRecord **nrp = &ResponseRecords;
ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question...
if (!ptr) goto exit;
- pktq.AnonInfo = mDNSNULL;
- if (McastNSEC3Records)
- InitializeAnonInfoForQuestion(m, &McastNSEC3Records, &pktq);
// The only queries that *need* a multicast response are:
// * Queries sent via multicast
// * from port 5353
{
rr = m->CurrentRecord;
m->CurrentRecord = rr->next;
- if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
+ if (AnyTypeRecordAnswersQuestion(rr, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
{
m->mDNSStats.MatchingAnswersForQueries++;
if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype))
else if (ResourceRecordIsValidAnswer(rr))
{
NumAnswersForThisQuestion++;
- // As we have verified this question to be part of the same subset,
- // set the anonymous data which is needed below when walk the cache
- // records to see what answers we should be expecting. The cache records
- // may cache only the nsec3RR and not the anonymous data itself.
- if (pktq.AnonInfo && rr->resrec.AnonInfo)
- SetAnonData(&pktq, &rr->resrec, mDNStrue);
// 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.
// 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 (SameNameCacheRecordAnswersQuestion(cr, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+ {
if (!cr->NextInKAList && eap != &cr->NextInKAList)
{
*eap = cr;
eap = &cr->NextInKAList;
}
+ }
+ }
}
#endif // POOF_ENABLED
// 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.
- // For anonymous question, the duplicate suppressesion should happen if the
- // question belongs in the same group. As the group is expected to be
- // small, we don't do the optimization for now.
- if (!pktq.AnonInfo)
+ for (q = m->Questions; q; q=q->next)
{
- 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)
- if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
- if (q->qtype == pktq.qtype &&
- q->qclass == pktq.qclass &&
- q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
- { *dqp = q; dqp = &q->NextInDQList; }
+ if (ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
+ {
+ if (!q->InterfaceID || q->InterfaceID == InterfaceID)
+ {
+ if (q->NextInDQList == mDNSNULL && dqp != &q->NextInDQList)
+ {
+ if (q->qtype == pktq.qtype &&
+ q->qclass == pktq.qclass &&
+ q->qnamehash == pktq.qnamehash && SameDomainName(&q->qname, &pktq.qname))
+ { *dqp = q; dqp = &q->NextInDQList; }
+ }
+ }
+ }
}
}
- if (pktq.AnonInfo)
- {
- FreeAnonInfo(pktq.AnonInfo);
- }
}
// ***
while (*dqp)
{
DNSQuestion *q = *dqp;
- if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+ if (CacheRecordAnswersQuestion(&m->rec.r, q))
{ *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
else dqp = &q->NextInDQList;
}
m->omsg.h.numAnswers, m->omsg.h.numAnswers == 1 ? "" : "s",
m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s",
srcaddr, mDNSVal16(srcport), InterfaceID, srcaddr->type);
- mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSfalse);
}
}
{
DNSQuestion *q;
(void)id;
- (void)srcaddr;
for (q = m->Questions; q; q=q->next)
{
// 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);
- 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(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
+ LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) from %#a:%d %s",
+ q->qname.c, DNSTypeName(q->qtype), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
return(mDNSNULL);
}
}
rr->resrec.name = cg->name; // And set rr->resrec.name to point into our CacheGroup header
rr->resrec.mortality = Mortality_Mortal;
- // We need to add the anonymous info before we call CacheRecordAdd so that
- // if it finds a matching question with this record, it bumps up the counters like
- // CurrentAnswers etc. Otherwise, when a cache entry gets removed, CacheRecordRmv
- // will complain.
- if (m->rec.r.resrec.AnonInfo)
- {
- rr->resrec.AnonInfo = m->rec.r.resrec.AnonInfo;
- m->rec.r.resrec.AnonInfo = mDNSNULL;
- }
rr->DelayDelivery = delay;
// If this is an oversized record with external storage allocated, copy rdata to external storage
{
// Can't use the "cg->name" if we are not adding to the cache as the
// CacheGroup may be released anytime if it is empty
- domainname *name = mDNSPlatformMemAllocate(DomainNameLength(cg->name));
+ domainname *name = (domainname *) mDNSPlatformMemAllocate(DomainNameLength(cg->name));
if (name)
{
AssignDomainName(name, cg->name);
ptr = getQuestion(response, ptr, end, InterfaceID, &q);
if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, mDNSNULL)))
{
- CacheRecord *rr, *neg = mDNSNULL;
+ CacheRecord *cr, *neg = mDNSNULL;
CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ {
+ if (SameNameCacheRecordAnswersQuestion(cr, qptr))
{
// 1. If we got a fresh answer to this query, then don't need to generate a negative entry
- if (RRExpireTime(rr) - m->timenow > 0) break;
+ if (RRExpireTime(cr) - 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 (cr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = cr;
}
+ }
// 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
// do the appropriate thing. This negative response is also needed for appending new search domains.
if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
{
- if (!rr)
+ if (!cr)
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: Generate negative response for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+ const mDNSBool noData = ((response->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr) ? mDNStrue : mDNSfalse;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Generate negative response for " PRI_DM_NAME " (" PUB_S ")",
+ q.request_id, mDNSVal16(q.TargetQID), DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
m->CurrentQuestion = qptr;
// We are not creating a cache record in this case, we need to pass back
// the error we got so that the proxy code can return the right one to
// the application
if (qptr->ProxyQuestion)
qptr->responseFlags = response->h.flags;
- GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
+ GenerateNegativeResponseEx(m, mDNSInterface_Any, QC_forceresponse, noData);
m->CurrentQuestion = mDNSNULL;
}
else
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: Skipping check and not creating a negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Skipping check and not creating a negative cache entry for " PRI_DM_NAME " (" PUB_S ")",
+ q.request_id, mDNSVal16(q.TargetQID), DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
}
}
else
{
- if (!rr)
+ if (!cr)
{
// 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
// If we already had a negative cache entry just update it, else make one or more new negative cache entries.
if (neg)
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Renewing negative TTL from %d to %d " PRI_S,
+ q.request_id, mDNSVal16(q.TargetQID), neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
RefreshCacheRecord(m, neg, negttl);
// When we created the cache for the first time and answered the question, the question's
// interval was set to MaxQuestionInterval. If the cache is about to expire and we are resending
{
// We might just have an SOA record for zones that are not signed and hence don't log
// this as an error
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr %s during refresh", CRDisplayString(m, neg));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u->Q%d] mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr " PRI_S" during refresh",
+ q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, neg));
FreeNSECRecords(m, NSECRecords);
neg->CRDNSSECQuestion = 0;
}
negcr->CRDNSSECQuestion = 0;
if (!AddNSECSForCacheRecord(m, NSECRecords, negcr, rcode))
{
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr %s",
- CRDisplayString(m, negcr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr " PRI_S,
+ q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, negcr));
FreeNSECRecords(m, NSECRecords);
}
else
{
negcr->CRDNSSECQuestion = 1;
- LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord added neg NSEC for %s", CRDisplayString(m, negcr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord added neg NSEC for " PRI_S,
+ q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, negcr));
}
NSECRecords = mDNSNULL;
negcr->DelayDelivery = 0;
}
}
}
- if (NSECRecords) { LogInfo("mDNSCoreReceiveNoUnicastAnswers: NSECRecords not used"); FreeNSECRecords(m, NSECRecords); }
- if (SOARecord) { LogInfo("mDNSCoreReceiveNoUnicastAnswers: SOARecord not used"); ReleaseCacheRecord(m, SOARecord); }
+ if (NSECRecords)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveNoUnicastAnswers: NSECRecords not used");
+ FreeNSECRecords(m, NSECRecords);
+ }
+ if (SOARecord)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveNoUnicastAnswers: SOARecord not used");
+ ReleaseCacheRecord(m, SOARecord);
+ }
}
mDNSlocal void mDNSCorePrintStoredProxyRecords(mDNS *const m)
{
AuthRecord *rrPtr = mDNSNULL;
+ if (!m->SPSRRSet) return;
LogSPS("Stored Proxy records :");
for (rrPtr = m->SPSRRSet; rrPtr; rrPtr = rrPtr->next)
{
return mDNSfalse;
}
-mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
+mDNSexport CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
const mDNSu32 slot, CacheGroup *cg, DNSQuestion *unicastQuestion, CacheRecord ***cfp, CacheRecord **NSECCachePtr,
mDNSInterfaceID InterfaceID)
{
- CacheRecord *rr;
+ CacheRecord *cr;
CacheRecord **cflocal = *cfp;
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
mDNSBool match;
// Resource record received via unicast, the resGroupID should match ?
if (!InterfaceID)
{
- const mDNSu32 id1 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
+ const mDNSu32 id1 = (cr->resrec.rDNSServer ? cr->resrec.rDNSServer->resGroupID : 0);
const mDNSu32 id2 = (m->rec.r.resrec.rDNSServer ? m->rec.r.resrec.rDNSServer->resGroupID : 0);
match = (id1 == id2);
}
else
- match = (rr->resrec.InterfaceID == InterfaceID);
+ match = (cr->resrec.InterfaceID == InterfaceID);
// If we found this exact resource record, refresh its TTL
- if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
+ if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &cr->resrec))
{
if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
verbosedebugf("mDNSCoreReceiveCacheCheck: Found record size %5d interface %p already in cache: %s",
if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
{
// If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
- if (rr->NextInCFList == mDNSNULL && *cfp != &rr->NextInCFList && LLQType != uDNS_LLQ_Events)
+ if (cr->NextInCFList == mDNSNULL && *cfp != &cr->NextInCFList && LLQType != uDNS_LLQ_Events)
{
- *cflocal = rr;
- cflocal = &rr->NextInCFList;
+ *cflocal = cr;
+ cflocal = &cr->NextInCFList;
*cflocal = (CacheRecord*)1;
- *cfp = &rr->NextInCFList;
+ *cfp = &cr->NextInCFList;
}
// If this packet record is marked unique, and our previous cached copy was not, then fix it
- if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
+ if (!(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
{
DNSQuestion *q;
for (q = m->Questions; q; q=q->next)
{
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ if (CacheRecordAnswersQuestion(cr, q))
q->UniqueAnswers++;
}
- rr->resrec.RecordType = m->rec.r.resrec.RecordType;
+ cr->resrec.RecordType = m->rec.r.resrec.RecordType;
}
}
- if (!SameRDataBody(&m->rec.r.resrec, &rr->resrec.rdata->u, SameDomainNameCS))
+ if (!SameRDataBody(&m->rec.r.resrec, &cr->resrec.rdata->u, SameDomainNameCS))
{
// If the rdata of the packet record differs in name capitalization from the record in our cache
// then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
// a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
// <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
- rr->resrec.rroriginalttl = 0;
- rr->TimeRcvd = m->timenow;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTimeForRecord(m, rr);
- LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change old: %s", CRDisplayString(m, rr));
- LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change new: %s", CRDisplayString(m, &m->rec.r));
- LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change in %d slot %3d in %d %d",
- NextCacheCheckEvent(rr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
+ cr->resrec.rroriginalttl = 0;
+ cr->TimeRcvd = m->timenow;
+ cr->UnansweredQueries = MaxUnansweredQueries;
+ SetNextCacheCheckTimeForRecord(m, cr);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change old: " PRI_S, CRDisplayString(m, cr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change new: " PRI_S, CRDisplayString(m, &m->rec.r));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change in %d slot %3d in %d %d",
+ NextCacheCheckEvent(cr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
// DO NOT break out here -- we want to continue as if we never found it
}
- else if (!IdenticalAnonInfo(m->rec.r.resrec.AnonInfo, rr->resrec.AnonInfo))
- {
- // If the NSEC3 record changed, a few possibilities
- //
- // 1) the peer reinitialized e.g., after network change and still part of the
- // same set.
- // 2) the peer went to a different set but we did not see the goodbyes. If we just
- // update the nsec3 record, it would be incorrect. Flush the cache so that we
- // can deliver a RMV followed by ADD.
- // 3) if the peer is ourselves and we see the goodbye when moving to a different set
- // and so we flush the cache and create a new cache record with the new set information.
- // Now we move back to the original set. In this case, we can't just update the
- // NSEC3 record alone. We need to flush so that we can deliver an RMV followed by ADD
- // when we create the new cache entry.
- //
- // Note: For case (1), we could avoid flushing the cache but we can't tell the difference
- // from the other cases.
- rr->resrec.rroriginalttl = 0;
- rr->TimeRcvd = m->timenow;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTimeForRecord(m, rr);
- LogInfo("mDNSCoreReceiveCacheCheck: AnonInfo changed for %s", CRDisplayString(m, rr));
- // DO NOT break out here -- we want to continue as if we never found it. When we return
- // from this function, we will create a new cache entry with the new NSEC3 record
- }
else if (m->rec.r.resrec.rroriginalttl > 0)
{
DNSQuestion *q;
m->mDNSStats.CacheRefreshed++;
- if (rr->resrec.mortality == Mortality_Ghost && unicastQuestion && (unicastQuestion->allowExpired != AllowExpired_AllowExpiredAnswers) && !rr->DelayDelivery)
+ if (cr->resrec.mortality == Mortality_Ghost && unicastQuestion && (unicastQuestion->allowExpired != AllowExpired_AllowExpiredAnswers) && !cr->DelayDelivery)
{
- rr->DelayDelivery = NonZeroTime(m->timenow);
- debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(rr), CRDisplayString(m, rr));
+ cr->DelayDelivery = NonZeroTime(m->timenow);
+ debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(cr), CRDisplayString(m, cr));
}
- if (rr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, rr));
- RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
- rr->responseFlags = response->h.flags;
+ if (cr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, cr));
+ RefreshCacheRecord(m, cr, m->rec.r.resrec.rroriginalttl);
+ cr->responseFlags = response->h.flags;
// If we may have NSEC records returned with the answer (which we don't know yet as it
// has not been processed), we need to cache them along with the first cache
// that would answer the question. It is possible that we might cache additional things
// e.g., MX question might cache A records also, and we want to cache the NSEC on
// the record that answers the question.
- if (response->h.numAnswers && unicastQuestion && unicastQuestion->qtype == rr->resrec.rrtype
+ if (response->h.numAnswers && unicastQuestion && unicastQuestion->qtype == cr->resrec.rrtype
&& !(*NSECCachePtr))
{
- LogInfo("mDNSCoreReceiveCacheCheck: rescuing RR %s", CRDisplayString(m, rr));
- *NSECCachePtr = rr;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: rescuing RR " PRI_S, CRDisplayString(m, cr));
+ *NSECCachePtr = cr;
}
// We have to reset the question interval to MaxQuestionInterval so that we don't keep
// polling the network once we get a valid response back. For the first time when a new
// Currently, we do this for for both multicast and unicast questions as long as the record
// type is unique. For unicast, resource record is always unique and for multicast it is
// true for records like A etc. but not for PTR.
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
{
for (q = m->Questions; q; q=q->next)
{
if (!q->DuplicateOf && !q->LongLived &&
- ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ ActiveQuestion(q) && CacheRecordAnswersQuestion(cr, q))
{
ResetQuestionState(m, q);
debugf("mDNSCoreReceiveCacheCheck: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
// If record's current expiry time is more than a second from now, we set it to expire in one second.
// If the record is already going to expire in less than one second anyway, we leave it alone --
// we don't want to let the goodbye packet *extend* the record's lifetime in our cache.
- debugf("DE for %s", CRDisplayString(m, rr));
- if (RRExpireTime(rr) - m->timenow > mDNSPlatformOneSecond)
+ debugf("DE for %s", CRDisplayString(m, cr));
+ if (RRExpireTime(cr) - m->timenow > mDNSPlatformOneSecond)
{
- rr->resrec.rroriginalttl = 1;
- rr->TimeRcvd = m->timenow;
- rr->UnansweredQueries = MaxUnansweredQueries;
- SetNextCacheCheckTimeForRecord(m, rr);
+ cr->resrec.rroriginalttl = 1;
+ cr->TimeRcvd = m->timenow;
+ cr->UnansweredQueries = MaxUnansweredQueries;
+ SetNextCacheCheckTimeForRecord(m, cr);
}
break;
}
}
}
- return rr;
+ return cr;
}
mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
mDNSlocal void mDNSCoreResetRecord(mDNS *const m)
{
m->rec.r.resrec.RecordType = 0; // Clear RecordType to show we're not still using it
- if (m->rec.r.resrec.AnonInfo)
- {
- FreeAnonInfo(m->rec.r.resrec.AnonInfo);
- m->rec.r.resrec.AnonInfo = mDNSNULL;
- }
}
// Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
const mDNSInterfaceID InterfaceID)
{
int i;
- mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
+ const mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
DNSQuestion *llqMatch = mDNSNULL;
DNSQuestion *unicastQuestion = mDNSNULL;
response->h.numAuthorities, response->h.numAuthorities == 1 ? "y, " : "ies,",
response->h.numAdditionals, response->h.numAdditionals == 1 ? " " : "s", end - response->data, LLQType);
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (mDNSSameIPPort(srcport, UnicastDNSPort))
{
MetricsUpdateDNSResponseSize((mDNSu32)(end - (mDNSu8 *)response));
{
if (!failure)
{
- CacheRecord *rr;
+ CacheRecord *cr;
// Remember the unicast question that we found, which we use to make caching
// decisions later on in this function
CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
unicastQuestion = qptr;
if (qptr->qDNSServer && DNSSECQuestion(qptr))
{
- LogInfo("mDNSCoreReceiveResponse: Setting aware for %##s (%s) on %#a", qptr->qname.c,
- DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Setting aware for " PRI_DM_NAME " (" PUB_S ") on " PRI_IP_ADDR,
+ qptr->request_id, mDNSVal16(qptr->TargetQID), DM_NAME_PARAM(qptr->qname.c),
+ DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr);
+
qptr->qDNSServer->DNSSECAware = mDNStrue;
qptr->qDNSServer->req_DO = mDNStrue;
}
if (qptr->ValidatingResponse)
DNSSECQuestion = mDNStrue;
}
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ {
+ if (SameNameCacheRecordAnswersQuestion(cr, qptr))
{
debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
- rr->resrec.InterfaceID, CRDisplayString(m, rr));
+ cr->resrec.InterfaceID, CRDisplayString(m, cr));
// 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;
- rr->CRDNSSECQuestion = 0;
+ cr->TimeRcvd = m->timenow - TicksTTL(cr) - 1;
+ cr->UnansweredQueries = MaxUnansweredQueries;
+ cr->CRDNSSECQuestion = 0;
if (unicastQuestion && DNSSECQuestion(unicastQuestion))
{
- LogInfo("mDNSCoreReceiveResponse: CRDNSSECQuestion set for record %s, question %##s (%s)", CRDisplayString(m, rr),
- unicastQuestion->qname.c, DNSTypeName(unicastQuestion->qtype));
- rr->CRDNSSECQuestion = 1;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: CRDNSSECQuestion set for record " PRI_S ", question " PRI_DM_NAME " (" PUB_S ")",
+ unicastQuestion->request_id, mDNSVal16(unicastQuestion->TargetQID),
+ CRDisplayString(m, cr), DM_NAME_PARAM(unicastQuestion->qname.c),
+ DNSTypeName(unicastQuestion->qtype));
+ cr->CRDNSSECQuestion = 1;
}
}
+ }
}
else
{
// and hence retransmit without the EDNS0/DOK option.
if (DNSSECOptionalQuestion(qptr) && qptr->qDNSServer && !qptr->qDNSServer->DNSSECAware)
{
- LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag",
- qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query " PRI_DM_NAME " (" PUB_S "), clear DO flag",
+ qptr->request_id, mDNSVal16(qptr->TargetQID), qptr->qDNSServer, rcode,
+ DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
qptr->qDNSServer->req_DO = mDNSfalse;
}
// For Unicast DNS Queries, penalize the DNSServer
else
{
- LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)",
- qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded with code %d to query " PRI_DM_NAME " (" PUB_S ")",
+ qptr->request_id, mDNSVal16(qptr->TargetQID), qptr->qDNSServer, rcode,
+ DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
PenalizeDNSServer(m, qptr, response->h.flags);
}
}
else if (!InterfaceID && suspiciousForQ)
{
// If a response is suspicious for a question, then reissue the question via TCP
- LogInfo("mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d",
+ LogInfo("[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d",
+ suspiciousForQ->request_id, mDNSVal16(suspiciousForQ->TargetQID),
suspiciousForQ->qDNSServer, q.qname.c, DNSTypeName(q.qtype),
mDNSVal16(suspiciousForQ->TargetQID), mDNSVal16(response->h.id));
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+ m->NextSuspiciousTimeout = NonZeroTime(m->timenow + (SUSPICIOUS_REPLY_DEFENSE_SECS * mDNSPlatformOneSecond));
+#endif
uDNS_RestartQuestionAsTCP(m, suspiciousForQ, srcaddr, srcport);
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ suspiciousForQ->metrics.dnsOverTCPState = DNSOverTCP_Suspicious;
+#endif
return;
}
}
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");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%d] Ignoring %2d Answer" PUB_S " %2d Authorit" PUB_S " %2d Additional" PUB_S,
+ mDNSVal16(response->h.id),
+ 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;
{
// Accept all remaining records in this unicast response to an mDNS query.
recordAcceptedInResponse = mDNStrue;
- LogInfo("mDNSCoreReceiveResponse: Accepting response for query: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Accepting response for query: " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
}
}
else
// 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))
{
- LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+ LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s (interface %d)",
+ m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r), IIDPrintable(InterfaceID));
LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->resrec.rdatahash, ARDisplayString(m, rr));
// If this record is marked DependentOn another record for conflict detection purposes,
// Before we call deregister, check if this is a packet we registered with the sleep proxy.
if (!mDNSCoreRegisteredProxyRecord(m, rr))
{
- // This may be a conflict due to stale packets on the network. Delay probing by a second.
- // If there are conflicts after 3 such attempts, then it is a true conflict.
- if (m->DelayConflictProcessing)
- {
- m->DelayConflictProcessing--;
- LogMsg("Possible spurious conflict for %s. Attempt %d at suppressing probes for one second",
- ARDisplayString(m, rr), (MAX_CONFLICT_PROCESSING_DELAYS - m->DelayConflictProcessing));
- rr->ProbeCount = DefaultProbeCountForTypeUnique + 1;
- rr->AnnounceCount = InitialAnnounceCount;
- m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
- InitializeLastAPTime(m, rr);
- RecordProbeFailure(m, rr); // Repeated late conflicts also cause us to back off to the slower probing rate
- }
- else
+ if ((rr->ProbingConflictCount == 0) || (m->MPktNum != rr->LastConflictPktNum))
{
- LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr));
- m->mDNSStats.NameConflicts++;
-#if APPLE_OSX_mDNSResponder
- // See if this record was also registered with any D2D plugins.
- D2D_stop_advertising_record(rr);
+ const NetworkInterfaceInfo *const intf = FirstInterfaceForID(m, InterfaceID);
+ rr->ProbingConflictCount++;
+ rr->LastConflictPktNum = m->MPktNum;
+ if (ResponseMCast && (!intf || intf->SupportsUnicastMDNSResponse) &&
+ (rr->ProbingConflictCount <= kMaxAllowedMCastProbingConflicts))
+ {
+ LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; restarting probing after %d-tick pause due to possibly "
+ "spurious multicast conflict (%d/%d) via interface %d for %s",
+ rr->ProbeCount, kProbingConflictPauseDuration, rr->ProbingConflictCount,
+ kMaxAllowedMCastProbingConflicts, IIDPrintable(InterfaceID), ARDisplayString(m, rr));
+ rr->ProbeCount = DefaultProbeCountForTypeUnique;
+ rr->LastAPTime = m->timenow + kProbingConflictPauseDuration - rr->ThisAPInterval;
+ SetNextAnnounceProbeTime(m, rr);
+ }
+ else
+ {
+ LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s due to %scast conflict via interface %d",
+ rr->ProbeCount, ARDisplayString(m, rr), ResponseMCast ? "multi" : "uni", IIDPrintable(InterfaceID));
+ m->mDNSStats.NameConflicts++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ // See if this record was also registered with any D2D plugins.
+ D2D_stop_advertising_record(rr);
#endif
- mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+ 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
{
LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
m->mDNSStats.KnownUniqueNameConflicts++;
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
D2D_stop_advertising_record(rr);
#endif
mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
// 2. See if we want to add this packet resource record to our cache
// We only try to cache answers if we have a cache to put them in
// Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
- if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
+ if (!AcceptableResponse) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[Q%d] mDNSCoreReceiveResponse ignoring " PRI_S,
+ mDNSVal16(response->h.id), CRDisplayString(m, &m->rec.r));
+ }
if (m->rrcache_size && AcceptableResponse)
{
const mDNSu32 slot = HashSlotFromNameHash(m->rec.r.resrec.namehash);
CacheGroup *cg = CacheGroupForRecord(m, &m->rec.r.resrec);
CacheRecord *rr = mDNSNULL;
- if (McastNSEC3Records)
- InitializeAnonInfoForCR(m, &McastNSEC3Records, &m->rec.r);
-
// 2a. Check if this packet resource record is already in our cache.
//
// If this record should go in the nseclist, don't look in the cache for updating it.
rr->CRDNSSECQuestion = 0;
if (unicastQuestion && DNSSECQuestion(unicastQuestion))
{
- LogInfo("mDNSCoreReceiveResponse: CRDNSSECQuestion set for new record %s, question %##s (%s)", CRDisplayString(m, rr),
- unicastQuestion->qname.c, DNSTypeName(unicastQuestion->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: CRDNSSECQuestion set for new record " PRI_S ", question " PRI_DM_NAME " (" PUB_S ")",
+ unicastQuestion->request_id, mDNSVal16(unicastQuestion->TargetQID), CRDisplayString(m, rr),
+ DM_NAME_PARAM(unicastQuestion->qname.c), DNSTypeName(unicastQuestion->qtype));
rr->CRDNSSECQuestion = 1;
}
// NSEC/NSEC3 records and its signatures are cached with the negative cache entry
}
}
}
- else
- {
- if (rr && rr->resrec.AnonInfo && m->rec.r.resrec.AnonInfo)
- {
- CopyAnonInfoForCR(m, rr, &m->rec.r);
- }
- }
}
mDNSCoreResetRecord(m);
}
}
else
{
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (r2->resrec.mortality == Mortality_Ghost)
{
DNSQuestion * q;
for (q = m->Questions; q; q=q->next)
{
if (!q->LongLived && ActiveQuestion(q) &&
- ResourceRecordAnswersQuestion(&r2->resrec, q) &&
+ CacheRecordAnswersQuestion(r2, q) &&
q->metrics.expiredAnswerState == ExpiredAnswer_AnsweredWithExpired)
{
q->metrics.expiredAnswerState = ExpiredAnswer_ExpiredAnswerChanged;
{
if (!NSECCachePtr)
{
- LogInfo("mDNSCoreReceiveResponse: Updating NSECCachePtr to %s", CRDisplayString(m, r1));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] mDNSCoreReceiveResponse: Updating NSECCachePtr to " PRI_S,
+ unicastQuestion->request_id, mDNSVal16(unicastQuestion->TargetQID), CRDisplayString(m, r1));
NSECCachePtr = r1;
}
// Note: We need to do this before we call CacheRecordDeferredAdd as this
if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
if (mDNS_PacketLoggingEnabled)
- DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+ DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end, InterfaceID);
ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space);
if (ptr)
if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
{
mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
- AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
+ AuthRecord *ar = (AuthRecord *) mDNSPlatformMemAllocateClear(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
if (!ar)
{
m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused;
}
}
- if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+ if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, mDNSNULL, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSfalse);
mDNS_SendKeepalives(m);
}
// We use zero addresses and all-ones addresses at various places in the code to indicate special values like "no address"
// If we accept and try to process a packet with zero or all-ones source address, that could really mess things up
- if (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
+ if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
mDNS_Lock(m);
m->PktNum++;
{
ifid = mDNSInterface_Any;
if (mDNS_PacketLoggingEnabled)
- DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+ DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end, InterfaceID);
uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
// Note: mDNSCore also needs to get access to received unicast responses
}
#pragma mark - Searcher Functions
#endif
-// Targets are considered the same if both queries are untargeted, or
-// if both are targeted to the same address+port
-// (If Target address is zero, TargetPort is undefined)
-#define SameQTarget(A,B) (((A)->Target.type == mDNSAddrType_None && (B)->Target.type == mDNSAddrType_None) || \
- (mDNSSameAddress(& (A)->Target, & (B)->Target) && mDNSSameIPPort((A)->TargetPort, (B)->TargetPort)))
-
-// SameQuestionKind is true if *both* questions are either multicast or unicast
-// TargetQID is used for this determination.
-#define SameQuestionKind(A,B) ((mDNSOpaque16IsZero(A) && mDNSOpaque16IsZero(B)) || \
- ((!mDNSOpaque16IsZero(A)) && (!mDNSOpaque16IsZero(B))))
-
// Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
// circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
// and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
// (a) long-lived and
// (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
// for multicast questions, we don't want to treat LongLived as anything special
-#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
-#define IsAWDLIncluded(Q) (((Q)->flags & kDNSServiceFlagsIncludeAWDL) != 0)
+#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
+#define AWDLIsIncluded(Q) (((Q)->flags & kDNSServiceFlagsIncludeAWDL) != 0)
+#define SameQuestionKind(Q1, Q2) (mDNSOpaque16IsZero((Q1)->TargetQID) == mDNSOpaque16IsZero((Q2)->TargetQID))
mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
{
// This prevents circular references, where two questions are each marked as a duplicate of the other.
// Accordingly, we break out of the loop when we get to 'question', because there's no point searching
// further in the list.
- for (q = m->Questions; q && q != question; q=q->next) // Scan our list for another question
- if (q->InterfaceID == question->InterfaceID && // with the same InterfaceID,
- SameQTarget(q, question) && // and same unicast/multicast target settings
- q->qtype == question->qtype && // type,
- q->qclass == question->qclass && // class,
- 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->AnonInfo == question->AnonInfo) && // Anonymous query not a dup of normal query
- (q->SuppressQuery == question->SuppressQuery) && // Questions that are suppressed/not suppressed
- (q->ValidationRequired == question->ValidationRequired) && // Questions that require DNSSEC validation
- (q->ValidatingResponse == question->ValidatingResponse) && // Questions that are validating responses using DNSSEC
- (q->DisallowPID == question->DisallowPID) && // Disallowing a PID should not affect a PID that is allowed
- (q->BrowseThreshold == question->BrowseThreshold) && // browse thresholds must match
- q->qnamehash == question->qnamehash &&
- (IsAWDLIncluded(q) == IsAWDLIncluded(question)) && // Inclusion of AWDL interface must match
- SameQuestionKind(q->TargetQID, question->TargetQID) && // mDNS or uDNS must match
- SameDomainName(&q->qname, &question->qname)) // and name
- return(q);
+ for (q = m->Questions; q && (q != question); q = q->next)
+ {
+ if (!SameQuestionKind(q, question)) continue;
+ if (q->qnamehash != question->qnamehash) continue;
+ if (q->InterfaceID != question->InterfaceID) continue;
+ if (q->qtype != question->qtype) continue;
+ if (q->qclass != question->qclass) continue;
+ if (IsLLQ(q) != IsLLQ(question)) continue;
+ if (q->AuthInfo && !question->AuthInfo) continue;
+ if (q->ValidationRequired != question->ValidationRequired) continue;
+ if (q->ValidatingResponse != question->ValidatingResponse) continue;
+ if (!q->Suppressed != !question->Suppressed) continue;
+ if (q->BrowseThreshold != question->BrowseThreshold) continue;
+ if (AWDLIsIncluded(q) != AWDLIsIncluded(question)) continue;
+ if (!SameDomainName(&q->qname, &question->qname)) continue;
+ return(q);
+ }
return(mDNSNULL);
}
// question as a duplicate.
if (question->DuplicateOf)
{
- LogInfo("UpdateQuestionDuplicates: question %p %##s (%s) duplicate of %p %##s (%s)",
- question, question->qname.c, DNSTypeName(question->qtype),
- question->DuplicateOf, question->DuplicateOf->qname.c, DNSTypeName(question->DuplicateOf->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->DupQ%d->Q%d] UpdateQuestionDuplicates: question %p " PRI_DM_NAME " (" PUB_S ") duplicate of %p " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->DuplicateOf->TargetQID), mDNSVal16(question->TargetQID),
+ question, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype), question->DuplicateOf,
+ DM_NAME_PARAM(question->DuplicateOf->qname.c), DNSTypeName(question->DuplicateOf->qtype));
return;
}
if (!d) d = (const domainname *)"";
- LogInfo("mDNS_AddMcastResolver: Adding %##s, InterfaceID %p, timeout %u", d->c, interface, timeout);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "mDNS_AddMcastResolver: Adding " PUB_DM_NAME ", InterfaceID %p, timeout %u", DM_NAME_PARAM(d), interface, timeout);
mDNS_CheckLock(m);
else
{
// allocate, add to list
- *p = mDNSPlatformMemAllocate(sizeof(**p));
+ *p = (McastResolver *) mDNSPlatformMemAllocateClear(sizeof(**p));
if (!*p) LogMsg("mDNS_AddMcastResolver: ERROR!! - malloc");
else
{
//
// - DNSServer is scoped and InterfaceID is not NULL - the InterfaceID of the question and the DNSServer
// should match (Refer to (2) above).
- //
- // Note: mDNSInterface_Unicast is used only by .local unicast questions and are treated as unscoped.
- // If a question is scoped both to InterfaceID and ServiceID, the question will be scoped to InterfaceID.
- if (((d->scopeType == kScopeNone) && ((!InterfaceID && ServiceID == -1) || InterfaceID == mDNSInterface_Unicast)) ||
+ if (((d->scopeType == kScopeNone) && (!InterfaceID && ServiceID == -1)) ||
((d->scopeType == kScopeInterfaceID) && d->interface == InterfaceID) ||
((d->scopeType == kScopeServiceID) && d->serviceID == ServiceID))
{
DEQuery = DomainEnumQuery(&question->qname);
for (curr = m->DNSServers; curr; curr = curr->next)
{
- debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped);
+ debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scopeType);
// skip servers that will soon be deleted
- if (curr->flags & DNSServer_FlagDelete)
+ if (curr->flags & DNSServerFlag_Delete)
{
- debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped);
+ debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scopeType);
continue;
}
}
currcount = CountLabels(&curr->domain);
- if ((!curr->isCell || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
- (!curr->isExpensive || !(question->flags & kDNSServiceFlagsDenyExpensive)) &&
- DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
+ if ((!DEQuery || !curr->isCell) && DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
{
bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
timeout = 0;
}
debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d,"
- " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout,
+ " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scopeType, index, curr->timeout,
curr->interface);
timeout += curr->timeout;
if (DEQuery)
}
question->noServerResponse = 0;
- debugf("SetValidDNSServers: ValidDNSServer bits 0x%x%x%x%x for question %p %##s (%s)",
+ debugf("SetValidDNSServers: ValidDNSServer bits 0x%08x%08x%08x%08x for question %p %##s (%s)",
question->validDNSServers.l[3], question->validDNSServers.l[2], question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
// If there are no matching resolvers, then use the default timeout value.
// For ProxyQuestion, shorten the timeout so that dig does not timeout on us in case of no response.
for (curr = m->DNSServers; curr; curr = curr->next)
{
// skip servers that will soon be deleted
- if (curr->flags & DNSServer_FlagDelete)
+ if (curr->flags & DNSServerFlag_Delete)
{
- debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped);
+ debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scopeType);
continue;
}
char *ifname = mDNSNULL; // for logging purposes only
mDNSOpaque128 allValid;
- if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+ if (InterfaceID == mDNSInterface_LocalOnly)
InterfaceID = mDNSNULL;
if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
const domainname *name = &question->qname;
int currindex;
- if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+ if (InterfaceID == mDNSInterface_LocalOnly)
InterfaceID = mDNSNULL;
if (InterfaceID)
if (curmatch != mDNSNULL)
{
- LogInfo("GetServerForQuestion: %p DNS server (%p) %#a:%d (Penalty Time Left %d) (Scope %s:%p:%d) for %##s (%s)",
- question, curmatch, &curmatch->addr, mDNSVal16(curmatch->port),
- (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
- InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] GetServerForQuestion: %p DNS server (%p) " PRI_IP_ADDR ":%d (Penalty Time Left %d) (Scope " PUB_S ":%p:%d) for " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question, curmatch, &curmatch->addr,
+ mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0),
+ ifname ? ifname : "None", InterfaceID, question->ServiceID, DM_NAME_PARAM(name), DNSTypeName(question->qtype));
}
else
{
- LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p:%d) for %##s (%s)",
- question, ifname ? ifname : "None", InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] GetServerForQuestion: %p no DNS server (Scope " PUB_S ":%p:%d) for " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question, ifname ? ifname : "None", InterfaceID,
+ question->ServiceID, DM_NAME_PARAM(name), DNSTypeName(question->qtype));
}
return(curmatch);
}
-
-#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
- (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
-
// Called in normal client context (lock not held)
mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
{
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
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
mDNS_Unlock(m);
}
-mDNSlocal mDNSBool IsPrivateDomain(mDNS *const m, DNSQuestion *q)
-{
- DomainAuthInfo *AuthInfo;
- // Skip Private domains as we have special addresses to get the hosts in the Private domain
- AuthInfo = GetAuthInfoForName_internal(m, &q->qname);
- if (AuthInfo && !AuthInfo->deltime && AuthInfo->AutoTunnel)
- {
- debugf("IsPrivateDomain: %##s true", q->qname.c);
- return mDNStrue;
- }
- else
- {
- debugf("IsPrivateDomain: %##s false", q->qname.c);
- return mDNSfalse;
- }
-}
-
-#define TrueFalseStr(X) ((X) ? "true" : "false")
-
// This function takes the DNSServer as a separate argument because sometimes the
-// caller has not yet assigned the DNSServer, but wants to evaluate the SuppressQuery
+// caller has not yet assigned the DNSServer, but wants to evaluate the Suppressed
// status before switching to it.
-mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNSServer *d)
+mDNSlocal mDNSBool ShouldSuppressUnicastQuery(const DNSQuestion *const q, const DNSServer *const server)
{
- // Some callers don't check for the qtype
- if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
- {
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
-
- // Private domains are exempted irrespective of what the DNSServer says
- if (IsPrivateDomain(m, q))
- {
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, Private Domain", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
+ mDNSBool suppress = mDNSfalse;
+ const char *reason = NULL;
- if (!d)
+ if (q->BlockedByPolicy)
{
- LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, as the DNS server is NULL", q->qname.c, DNSTypeName(q->qtype));
- return mDNStrue;
+ suppress = mDNStrue;
+ reason = " (blocked by policy)";
}
-
- // Check if the DNS Configuration allows A/AAAA queries to be sent
- if ((q->qtype == kDNSType_A) && d->req_A)
+ else if (!server)
{
- // The server's configuration allows A record queries, so don't suppress this query unless
- // 1. the interface associated with the server is CLAT46; and
- // 2. the query has the kDNSServiceFlagsPathEvaluationDone flag, which indicates that it came from libnetcore.
- // See <rdar://problem/42672030> for more info.
- if (!(d->isCLAT46 && (q->flags & kDNSServiceFlagsPathEvaluationDone)))
+ if (!q->IsUnicastDotLocal)
{
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows A queries", q->qname.c,
- DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
- return mDNSfalse;
+ suppress = mDNStrue;
+ reason = " (no DNS server)";
}
}
- if ((q->qtype == kDNSType_AAAA) && d->req_AAAA)
+ else if (server->isCell && (q->flags & kDNSServiceFlagsDenyCellular))
{
- LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows AAAA queries", q->qname.c,
- DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
- return mDNSfalse;
+ suppress = mDNStrue;
+ reason = " (interface is cellular)";
}
-#if USE_DNS64
- if (DNS64IsQueryingARecord(q->dns64.state))
+ else if (server->isExpensive && (q->flags & kDNSServiceFlagsDenyExpensive))
{
- LogDebug("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
+ suppress = mDNStrue;
+ reason = " (interface is expensive)";
}
+ else if (server->isConstrained && (q->flags & kDNSServiceFlagsDenyConstrained))
+ {
+ suppress = mDNStrue;
+ reason = " (interface is constrained)";
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
+ else if (q->SuppressUnusable && !DNS64IsQueryingARecord(q->dns64.state))
+#else
+ else if (q->SuppressUnusable)
#endif
-
- LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A %s, req_AAAA %s, CLAT46 %s)",
- q->qname.c, DNSTypeName(q->qtype), TrueFalseStr(d->req_A), TrueFalseStr(d->req_AAAA), TrueFalseStr(d->isCLAT46));
-
- return mDNStrue;
-}
-
-mDNSlocal mDNSBool ShouldSuppressDotLocalQuery(mDNS *const m, DNSQuestion *q)
-{
- NetworkInterfaceInfo *intf;
- AuthRecord *rr;
- mDNSBool ret;
-
- // Check to see if there is at least one interface other than loopback and don't suppress
- // .local questions if you find one. If we have at least one interface, it means that
- // we can send unicast queries for the .local name and we don't want to suppress
- // multicast in that case as upper layers don't know how to handle if we return a
- // negative response for multicast followed by a positive response for unicast.
- //
- // Note: we used to check for multicast capable interfaces instead of just any interface
- // present. That did not work in the case where we have a valid interface for unicast
- // but not multicast capable e.g., cellular, as we ended up delivering a negative response
- // first and the upper layer did not wait for the positive response that came later.
- for (intf = m->HostInterfaces; intf; intf = intf->next)
{
- if (intf->InterfaceActive && !intf->Loopback)
+ if (q->qtype == kDNSType_A)
{
- LogInfo("ShouldSuppressDotLocalQuery: Found interface %s, not suppressing", intf->ifname);
- return mDNSfalse;
+ if (!server->usableA)
+ {
+ suppress = mDNStrue;
+ reason = " (A records are unusable)";
+ }
+ // If the server's configuration allows A record queries, suppress this query if
+ // 1. the interface associated with the server is CLAT46; and
+ // 2. the query has the kDNSServiceFlagsPathEvaluationDone flag, indicating that it's from libnetwork.
+ // See <rdar://problem/42672030> for more info.
+ else if (server->isCLAT46 && (q->flags & kDNSServiceFlagsPathEvaluationDone))
+ {
+ suppress = mDNStrue;
+ reason = " (CLAT46 A records are unusable)";
+ }
}
- }
-
- // 1. If we find a LocalOnly or P2P record answering this question, then don't suppress it.
- // Set m->CurrentQuestion as it is required by AnswerQuestionWithLORecord.
- m->CurrentQuestion = q;
- ret = AnswerQuestionWithLORecord(m, q, mDNStrue);
- m->CurrentQuestion = mDNSNULL;
-
- if (ret)
- {
- LogInfo("ShouldSuppressDotLocalQuery: Found LocalOnly record for %##s (%s), not suppressing", q->qname.c,
- DNSTypeName(q->qtype));
- return mDNSfalse;
- }
-
- // 2. If we find a local AuthRecord answering this question, then don't suppress it.
- for (rr = m->ResourceRecords; rr; rr = rr->next)
- {
- if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+ else if (q->qtype == kDNSType_AAAA)
{
- LogInfo("ShouldSuppressDotLocalQuery: Found resource record %s for %##s (%s) not suppressing", ARDisplayString(m, rr),
- q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
+ if (!server->usableAAAA)
+ {
+ suppress = mDNStrue;
+ reason = " (AAAA records are unusable)";
+ }
}
}
- return mDNStrue;
+ if (suppress)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] ShouldSuppressUnicastQuery: Query suppressed for " PRI_DM_NAME " " PUB_S PUB_S,
+ mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), reason ? reason : "");
+ }
+ return suppress;
}
-mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q)
+mDNSlocal mDNSBool ShouldSuppressQuery(DNSQuestion *q)
{
if (q->InterfaceID == mDNSInterface_LocalOnly)
{
- LogInfo("ShouldSuppressQuery: LocalOnly query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
return mDNSfalse;
}
-
- if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
+ if (!q->IsUnicastDotLocal && IsLocalDomain(&q->qname))
{
- LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
return mDNSfalse;
}
-
- // We still want the ability to be able to listen to the local services and hence
- // don't fail .local query if we have local records that can potentially answer
- // the question.
- if (q->InterfaceID != mDNSInterface_Unicast && IsLocalDomain(&q->qname))
- {
- if (!ShouldSuppressDotLocalQuery(m, q))
- {
- LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local question", q->qname.c, DNSTypeName(q->qtype));
- return mDNSfalse;
- }
- else
- {
- LogInfo("ShouldSuppressQuery: Query suppressed for %##s, qtype %s, Local question", q->qname.c, DNSTypeName(q->qtype));
- return mDNStrue;
- }
- }
-
- return (ShouldSuppressUnicastQuery(m, q, q->qDNSServer));
+ return (ShouldSuppressUnicastQuery(q, q->qDNSServer));
}
mDNSlocal void CacheRecordRmvEventsForCurrentQuestion(mDNS *const m, DNSQuestion *q)
{
- CacheRecord *rr;
+ CacheRecord *cr;
CacheGroup *cg;
cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
// Don't deliver RMV events for negative records
- if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+ if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
{
- LogInfo("CacheRecordRmvEventsForCurrentQuestion: CacheRecord %s Suppressing RMV events for question %p %##s (%s), CRActiveQuestion %p, CurrentAnswers %d",
- CRDisplayString(m, rr), q, q->qname.c, DNSTypeName(q->qtype), rr->CRActiveQuestion, q->CurrentAnswers);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] CacheRecordRmvEventsForCurrentQuestion: CacheRecord " PRI_S " Suppressing RMV events for question %p " PRI_DM_NAME " (" PUB_S "), CRActiveQuestion %p, CurrentAnswers %d",
+ q->request_id, mDNSVal16(q->TargetQID), CRDisplayString(m, cr), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), cr->CRActiveQuestion, q->CurrentAnswers);
continue;
}
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
{
LogInfo("CacheRecordRmvEventsForCurrentQuestion: Calling AnswerCurrentQuestionWithResourceRecord (RMV) for question %##s using resource record %s LocalAnswers %d",
- q->qname.c, CRDisplayString(m, rr), q->LOAddressAnswers);
+ q->qname.c, CRDisplayString(m, cr), q->LOAddressAnswers);
q->CurrentAnswers--;
- if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
- if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
-
- if (rr->CRActiveQuestion == q)
- {
- DNSQuestion *qptr;
- // If this was the active question for this cache entry, it was the one that was
- // responsible for keeping the cache entry fresh when the cache entry was reaching
- // its expiry. We need to handover the responsibility to someone else. Otherwise,
- // when the cache entry is about to expire, we won't find an active question
- // (pointed by CRActiveQuestion) to refresh the cache.
- for (qptr = m->Questions; qptr; qptr=qptr->next)
- if (qptr != q && ActiveQuestion(qptr) && ResourceRecordAnswersQuestion(&rr->resrec, qptr))
- break;
-
- if (qptr)
- LogInfo("CacheRecordRmvEventsForCurrentQuestion: Updating CRActiveQuestion to %p for cache record %s, "
- "Original question CurrentAnswers %d, new question CurrentAnswers %d, SuppressUnusable %d, SuppressQuery %d",
- qptr, CRDisplayString(m,rr), q->CurrentAnswers, qptr->CurrentAnswers, qptr->SuppressUnusable, qptr->SuppressQuery);
-
- rr->CRActiveQuestion = qptr; // Question used to be active; new value may or may not be null
- if (!qptr) m->rrcache_active--; // If no longer active, decrement rrcache_active count
- }
- AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+ if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+ if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+ AnswerCurrentQuestionWithResourceRecord(m, cr, QC_rmv);
if (m->CurrentQuestion != q) break; // If callback deleted q, then we're finished here
}
}
// NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero
// LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before
// LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers)
- if (q->SuppressQuery)
+ if (q->Suppressed)
{
- q->SuppressQuery = mDNSfalse;
+ q->Suppressed = mDNSfalse;
if (!CacheRecordRmvEventsForQuestion(m, q))
{
- LogInfo("SuppressStatusChanged: Question deleted while delivering RMV events from cache");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] SuppressStatusChanged: Question deleted while delivering RMV events from cache",
+ q->request_id, mDNSVal16(q->TargetQID));
return;
}
- q->SuppressQuery = mDNStrue;
+ q->Suppressed = mDNStrue;
}
// SuppressUnusable does not affect questions that are answered from the local records (/etc/hosts)
- // and SuppressQuery status does not mean anything for these questions. As we are going to stop the
+ // and Suppressed status does not mean anything for these questions. As we are going to stop the
// question below, we need to deliver the RMV events so that the ADDs that will be delivered during
// the restart will not be a duplicate ADD
if (!LocalRecordRmvEventsForQuestion(m, q))
{
- LogInfo("SuppressStatusChanged: Question deleted while delivering RMV events from Local AuthRecords");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] SuppressStatusChanged: Question deleted while delivering RMV events from Local AuthRecords",
+ q->request_id, mDNSVal16(q->TargetQID));
return;
}
//
// 2. Previously it was not suppressed and now it is suppressed. We need to restart the questions
// so that we redo the duplicate checks in mDNS_StartQuery_internal. A SuppressUnusable question
- // is a duplicate of non-SuppressUnusable question if it is not suppressed (SuppressQuery is false).
+ // is a duplicate of non-SuppressUnusable question if it is not suppressed (Suppressed is false).
// A SuppressUnusable question is not a duplicate of non-SuppressUnusable question if it is suppressed
- // (SuppressQuery is true). The reason for this is that when a question is suppressed, we want an
+ // (Suppressed is true). The reason for this is that when a question is suppressed, we want an
// immediate response and not want to be blocked behind a question that is querying DNS servers. When
// the question is not suppressed, we don't want two active questions sending packets on the wire.
// This affects both efficiency and also the current design where there is only one active question
//
// It is much cleaner and less error prone to build a list of questions and restart at the end.
- LogInfo("SuppressStatusChanged: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] SuppressStatusChanged: Stop question %p " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
mDNS_StopQuery_internal(m, q);
q->next = *restart;
*restart = q;
// we potentially restart questions here in this function that ends up as new questions,
// which may be suppressed at this instance. Before it is handled we get another network
// event that changes the status e.g., address becomes available. If we did not process
- // new questions, we would never change its SuppressQuery status.
+ // new questions, we would never change its Suppressed status.
//
// CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the
// application callback can potentially stop the current question (detected by CurrentQuestion) or
m->RestartQuestion = q->next;
if (q->SuppressUnusable)
{
- mDNSBool old = q->SuppressQuery;
- q->SuppressQuery = ShouldSuppressQuery(m, q);
- if (q->SuppressQuery != old)
+ const mDNSBool old = q->Suppressed;
+ q->Suppressed = ShouldSuppressQuery(q);
+ if (q->Suppressed != old)
{
// Previously it was not suppressed, Generate RMV events for the ADDs that we might have delivered before
// followed by a negative cache response. Temporarily turn off suppression so that
mDNSlocal void RestartUnicastQuestions(mDNS *const m)
{
DNSQuestion *q;
- DNSQuestion *restart = mDNSNULL;
+ DNSQuestion *restartList = mDNSNULL;
if (m->RestartQuestion)
LogMsg("RestartUnicastQuestions: ERROR!! m->RestartQuestion already set: %##s (%s)",
if (mDNSOpaque16IsZero(q->TargetQID))
LogMsg("RestartUnicastQuestions: ERROR!! Restart set for multicast question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->Restart = 0;
- SuppressStatusChanged(m, q, &restart);
+ q->Restart = mDNSfalse;
+ SuppressStatusChanged(m, q, &restartList);
}
}
- while (restart)
+ while ((q = restartList) != mDNSNULL)
{
- q = restart;
- restart = restart->next;
+ restartList = q->next;
q->next = mDNSNULL;
- LogInfo("RestartUnicastQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] RestartUnicastQuestions: Start question %p " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
mDNS_StartQuery_internal(m, q);
}
}
-
// ValidateParameters() is called by mDNS_StartQuery_internal() to check the client parameters of
// DNS Question that are already set by the client before calling mDNS_StartQuery()
mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
{
-
- if (question->Target.type && !ValidQuestionTarget(question))
- {
- LogMsg("ValidateParameters: Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery? for question %##s)",
- question->Target.type, mDNSVal16(question->TargetPort), question->qname.c);
- question->Target.type = mDNSAddrType_None;
- }
-
- // If no question->Target specified, clear TargetPort
- if (!question->Target.type)
- question->TargetPort = zeroIPPort;
-
if (!ValidateDomainName(&question->qname))
{
LogMsg("ValidateParameters: Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
}
// If this question is referencing a specific interface, verify it exists
- if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID) && question->InterfaceID != mDNSInterface_Unicast)
+ if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID))
{
NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
if (!intf)
LogInfo("ValidateParameters: Note: InterfaceID %d for question %##s (%s) not currently found in active interface list",
- (uint32_t)question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
+ IIDPrintable(question->InterfaceID), question->qname.c, DNSTypeName(question->qtype));
}
return(mStatus_NoError);
// First reset all DNS Configuration
question->qDNSServer = mDNSNULL;
question->validDNSServers = zeroOpaque128;
- question->triedAllServersOnce = 0;
- question->noServerResponse = 0;
+ question->triedAllServersOnce = mDNSfalse;
+ question->noServerResponse = mDNSfalse;
question->StopTime = (question->TimeoutQuestion) ? question->StopTime : 0;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics));
question->metrics.expiredAnswerState = (question->allowExpired != AllowExpired_None) ? ExpiredAnswer_Allowed : ExpiredAnswer_None;
#endif
if (question->TimeoutQuestion && !question->StopTime)
{
question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
- LogInfo("InitDNSConfig: Setting StopTime on the uDNS question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] InitDNSConfig: Setting StopTime on the uDNS question %p " PRI_DM_NAME " (" PUB_S ")",
+ mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype));
}
question->qDNSServer = GetServerForQuestion(m, question);
- LogDebug("InitDNSConfig: question %p %##s (%s) Timeout %d, DNS Server %#a:%d",
- question, question->qname.c, DNSTypeName(question->qtype), timeout,
- question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
- mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%u->Q%u] InitDNSConfig: question %p " PRI_DM_NAME " " PUB_S " Timeout %d, DNS Server " PRI_IP_ADDR ":%d",
+ question->request_id, mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(question->qname.c),
+ DNSTypeName(question->qtype), timeout, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
}
else if (question->TimeoutQuestion && !question->StopTime)
{
mDNSu32 timeout = LocalOnlyOrP2PInterface(question->InterfaceID) ?
DEFAULT_LO_OR_P2P_TIMEOUT : GetTimeoutForMcastQuestion(m, question);
question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
- LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] InitDNSConfig: Setting StopTime on the uDNS question %p " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype));
}
// Set StopTime here since it is a part of DNS Configuration
if (question->StopTime)
InitDNSConfig(m, question);
question->AuthInfo = GetAuthInfoForQuestion(m, question);
- question->SuppressQuery = 0;
- if (question->SuppressUnusable)
- question->SuppressQuery = ShouldSuppressQuery(m, question);
-
- // If ServiceID is 0 or the policy disallows making DNS requests,
- // set DisallowPID
- question->DisallowPID = (question->ServiceID == 0 || isBlocked);
- if (question->DisallowPID)
- LogInfo("InitCommonState: Query suppressed for %##s (%s), PID %d/ServiceID %d not allowed", question->qname.c,
- DNSTypeName(question->qtype), question->pid, question->ServiceID);
+ // The question's BlockedByPolicy value must be set before calling ShouldSuppressQuery().
+ question->BlockedByPolicy = isBlocked ? mDNStrue : mDNSfalse;
+ question->Suppressed = ShouldSuppressQuery(question);
question->NextInDQList = mDNSNULL;
question->SendQNow = mDNSNULL;
question->SendOnAll = mDNSfalse;
for (i=0; i<DupSuppressInfoSize; i++)
question->DupSuppress[i].InterfaceID = mDNSNULL;
- question->Restart = 0;
+ question->Restart = mDNSfalse;
debugf("InitCommonState: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
mDNSlocal void InitLLQState(DNSQuestion *const question)
{
- question->state = LLQ_InitialRequest;
+ question->state = LLQ_Init;
question->ReqLease = 0;
question->expire = 0;
question->ntries = 0;
question->id = zeroOpaque64;
}
-#ifdef DNS_PUSH_ENABLED
-mDNSlocal void InitDNSPNState(DNSQuestion *const question)
-{
- question->dnsPushState = DNSPUSH_INIT;
-}
-#endif // DNS_PUSH_ENABLED
-
// InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize
// DNSSEC & DNS Proxy fields of the DNS Question.
mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question)
// then we log a line as it could indicate an issue
if (question->DuplicateOf->qDNSServer == mDNSNULL)
{
- if (question->qDNSServer)
- LogInfo("FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(%#a:%d) but original question(%p) has no DNS Server! %##s (%s)",
- question, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
- mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort),
- question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype));
+ if (question->qDNSServer) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(" PRI_IP_ADDR ":%d) but original question(%p) has no DNS Server! " PRI_DM_NAME " (" PUB_S ")",
+ question->request_id, mDNSVal16(question->TargetQID), question,
+ question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort), question->DuplicateOf,
+ DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype));
+ }
+
}
question->qDNSServer = question->DuplicateOf->qDNSServer;
- LogInfo("FinalizeUnicastQuestion: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d",
- question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype),
- question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
- mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->DupQ%d->Q%d] FinalizeUnicastQuestion: Duplicate question %p (%p) " PRI_DM_NAME " (" PUB_S "), DNS Server " PRI_IP_ADDR ":%d",
+ question->request_id, mDNSVal16(question->DuplicateOf->TargetQID), mDNSVal16(question->TargetQID),
+ question, question->DuplicateOf, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype),
+ question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+ mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
}
ActivateUnicastQuery(m, question, mDNSfalse);
// the LLQ NAT state only for unicast. Otherwise we will unnecessarily
// start the NAT traversal that is not needed.
InitLLQNATState(m);
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
}
#ifdef USE_LIBIDN
// If the TLD includes high-ascii bytes, assume it will need to be converted to Punycode.
// (In the future the root name servers may answer UTF-8 queries directly, but for now they do not.)
+ // This applies to the top label (TLD) only
+ // -- for the second level and down we try UTF-8 first, and then fall back to Punycode only if UTF-8 fails.
if (IsHighASCIILabel(LastLabel(&question->qname)))
{
domainname newname;
}
#endif // USE_LIBIDN
- question->TargetQID =
#ifndef UNICAST_DISABLED
- (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) :
-#endif // UNICAST_DISABLED
- zeroID;
+ question->TargetQID = Question_uDNS(question) ? mDNS_NewMessageID(m) : zeroID;
+#else
+ question->TargetQID = zeroID;
+#endif
debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
// Note: It important that new questions are appended at the *end* of the list, not prepended at the start
InitCommonState(m, question);
InitWABState(question);
InitLLQState(question);
-#ifdef DNS_PUSH_ENABLED
- InitDNSPNState(question);
-#endif // DNS_PUSH_ENABLED
InitDNSSECProxyState(m, question);
// FindDuplicateQuestion should be called last after all the intialization
}
else
{
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
m->NumAllInterfaceQuestions++;
- LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
- m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_StartQuery_internal: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_DM_NAME " (" PUB_S ")",
+ m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
{
m->NextBonjourDisableTime = 0;
m->NetworkChanged = m->timenow;
}
}
-#endif // BONJOUR_ON_DEMAND
+#endif
if (question->WakeOnResolve)
{
LogInfo("mDNS_StartQuery_internal: Purging for %##s", question->qname.c);
mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
{
CacheGroup *cg = CacheGroupForName(m, question->qnamehash, &question->qname);
- CacheRecord *rr;
+ CacheRecord *cr;
DNSQuestion **qp = &m->Questions;
//LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
return(mStatus_BadReferenceErr);
}
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
if (!LocalOnlyOrP2PInterface(question->InterfaceID) && mDNSOpaque16IsZero(question->TargetQID))
{
if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
m->NumAllInterfaceQuestions--;
- LogInfo("mDNS_StopQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
- m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_StopQuery_internal: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_DM_NAME " (" PUB_S ")",
+ m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
}
-#endif // BONJOUR_ON_DEMAND
+#endif
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0))
{
const domainname * queryName;
queryName = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
isForCell = (question->qDNSServer && question->qDNSServer->isCell);
durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
- MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, durationMs, isForCell);
+ MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, question->metrics.dnsOverTCPState, durationMs, isForCell);
}
#endif
// Take care to cut question from list *before* calling UpdateQuestionDuplicates
// If there are any cache records referencing this as their active question, then see if there is any
// other question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
{
- if (rr->CRActiveQuestion == question)
+ if (cr->CRActiveQuestion == question)
{
DNSQuestion *q;
DNSQuestion *replacement = mDNSNULL;
// via CacheRecordRmv() when the cache record expires.
for (q = m->Questions; q && (q != m->NewQuestions); q = q->next)
{
- if (!q->DuplicateOf && !QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+ if (!q->DuplicateOf && !q->Suppressed && CacheRecordAnswersQuestion(cr, q))
{
if (q->ThisQInterval > 0)
{
}
if (replacement)
debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question "
- "CurrentAnswers %d, SuppressQuery %d", replacement, CRDisplayString(m,rr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->SuppressQuery);
- rr->CRActiveQuestion = replacement; // Question used to be active; new value may or may not be null
+ "CurrentAnswers %d, Suppressed %d", replacement, CRDisplayString(m,cr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->Suppressed);
+ cr->CRActiveQuestion = replacement; // Question used to be active; new value may or may not be null
if (!replacement) m->rrcache_active--; // If no longer active, decrement rrcache_active count
}
}
question->tcp = mDNSNULL;
}
}
-#ifdef DNS_PUSH_ENABLED
- else if (question->dnsPushState == DNSPUSH_ESTABLISHED)
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ else if (question->dnsPushServer != mDNSNULL)
{
- if (question->tcp)
- {
- UnSubscribeToDNSPushNotificationServer(m, q);
- question->tcp->question = mDNSNULL;
- question->tcp = mDNSNULL;
- }
+ UnSubscribeToDNSPushNotificationServer(m, question);
}
-#endif // DNS_PUSH_ENABLED
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
#endif
}
// wait until we send the refresh above which needs the nta
question->DAIFreeCallback(m, question->DNSSECAuthInfo);
question->DNSSECAuthInfo = mDNSNULL;
}
- if (question->AnonInfo)
- {
- FreeAnonInfo(question->AnonInfo);
- question->AnonInfo = mDNSNULL;
- }
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (question->metrics.originalQName)
{
mDNSPlatformMemFree(question->metrics.originalQName);
}
#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
DNS64ResetState(question);
#endif
status = mDNS_StopQuery_internal(m, question);
if (status == mStatus_NoError && !qq)
{
- const CacheRecord *rr;
+ const CacheRecord *cr;
CacheGroup *const cg = CacheGroupForName(m, question->qnamehash, &question->qname);
LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
- if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
+ for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+ {
+ if (cr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameCacheRecordAnswersQuestion(cr, question))
{
// Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
if (question->QuestionCallback)
- question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
+ question->QuestionCallback(m, question, &cr->resrec, mDNSfalse);
}
+ }
}
mDNS_Unlock(m);
return(status);
mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question,
const domainname *const srv, const domainname *const domain,
- const mDNSu8 *anondata, const mDNSInterfaceID InterfaceID, mDNSu32 flags,
+ const mDNSInterfaceID InterfaceID, mDNSu32 flags,
mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
mDNSQuestionCallback *Callback, void *Context)
{
question->InterfaceID = InterfaceID;
question->flags = flags;
- question->Target = zeroAddr;
question->qtype = kDNSType_PTR;
question->qclass = kDNSClass_IN;
question->LongLived = mDNStrue;
question->ForceMCast = ForceMCast;
question->ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
question->SuppressUnusable = mDNSfalse;
- question->SearchListIndex = 0;
- question->AppendSearchDomains = 0;
- question->RetryWithSearchDomains = mDNSfalse;
+ question->AppendSearchDomains = mDNSfalse;
question->TimeoutQuestion = 0;
question->WakeOnResolve = 0;
- question->UseBackgroundTrafficClass = useBackgroundTrafficClass;
+ question->UseBackgroundTraffic = useBackgroundTrafficClass;
question->ValidationRequired = 0;
question->ValidatingResponse = 0;
question->ProxyQuestion = 0;
- question->qnameOrig = mDNSNULL;
- question->AnonInfo = mDNSNULL;
question->QuestionCallback = Callback;
question->QuestionContext = Context;
if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain))
return(mStatus_BadParamErr);
- if (anondata)
- {
- question->AnonInfo = AllocateAnonInfo(&question->qname, anondata, mDNSPlatformStrLen(anondata), mDNSNULL);
- if (!question->AnonInfo)
- return(mStatus_BadParamErr);
- }
-
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 mDNSu8 *anondata, const mDNSInterfaceID InterfaceID, mDNSu32 flags,
+ const mDNSInterfaceID InterfaceID, mDNSu32 flags,
mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
mDNSQuestionCallback *Callback, void *Context)
{
mStatus status;
mDNS_Lock(m);
- status = mDNS_StartBrowse_internal(m, question, srv, domain, anondata, InterfaceID, flags, ForceMCast, useBackgroundTrafficClass, Callback, Context);
+ status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, flags, ForceMCast, useBackgroundTrafficClass, Callback, Context);
mDNS_Unlock(m);
return(status);
}
{
question->InterfaceID = InterfaceID;
question->flags = 0;
- question->Target = zeroAddr;
question->qtype = kDNSType_PTR;
question->qclass = kDNSClass_IN;
question->LongLived = mDNSfalse;
question->ForceMCast = mDNSfalse;
question->ReturnIntermed = mDNSfalse;
question->SuppressUnusable = mDNSfalse;
- question->SearchListIndex = 0;
- question->AppendSearchDomains = 0;
- question->RetryWithSearchDomains = mDNSfalse;
+ question->AppendSearchDomains = mDNSfalse;
question->TimeoutQuestion = 0;
question->WakeOnResolve = 0;
- question->UseBackgroundTrafficClass = mDNSfalse;
+ question->UseBackgroundTraffic = mDNSfalse;
question->ValidationRequired = 0;
question->ValidatingResponse = 0;
question->ProxyQuestion = 0;
- question->qnameOrig = mDNSNULL;
- question->AnonInfo = mDNSNULL;
question->pid = mDNSPlatformGetPID();
question->euid = 0;
question->QuestionCallback = Callback;
// Circular reference: AdvertiseInterface references mDNS_HostNameCallback, which calls mDNS_SetFQDN, which call AdvertiseInterface
mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *m, AuthRecord *rr, mStatus result);
+#endif
mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
{
// The parameter "set" here refers to the set of AuthRecords used to advertise this interface.
// (It's a set of records, not a set of interfaces.)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool useRandomizedHostname)
+#else
mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+#endif
{
- char buffer[MAX_REVERSE_MAPPING_NAME];
NetworkInterfaceInfo *primary;
- mDNSu8 recordType;
+ const domainname *hostname;
+ mDNSRecordCallback *hostnameCallback;
+ AuthRecord *addrAR;
+ AuthRecord *ptrAR;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ const mDNSBool interfaceIsAWDL = mDNSPlatformInterfaceIsAWDL(set->InterfaceID);
+#endif
+ mDNSu8 addrRecordType;
+ char buffer[MAX_REVERSE_MAPPING_NAME];
- if (m->AutoTargetServices == 0)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (interfaceIsAWDL || useRandomizedHostname)
{
- LogInfo("AdvertiseInterface: Returning due to AutoTargetServices zero for %s", set->ifname);
- return;
+ hostname = &m->RandomizedHostname;
+ hostnameCallback = mDNS_RandomizedHostNameCallback;
+ }
+ else
+#endif
+ {
+ hostname = &m->MulticastHostname;
+ hostnameCallback = mDNS_HostNameCallback;
}
- primary = FindFirstAdvertisedInterface(m);
- if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
- // We should never have primary be NULL, because even if there is
- // no other interface yet, we should always find ourself in the list.
-
- // If interface is marked as a direct link, we can assume the address record is unique
- // and does not need to go through the probe phase of the probe/announce packet sequence.
- recordType = (set->DirectLink ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!interfaceIsAWDL && useRandomizedHostname)
+ {
+ addrAR = &set->RR_AddrRand;
+ ptrAR = mDNSNULL;
+ }
+ else
+#endif
+ {
+ addrAR = &set->RR_A;
+ ptrAR = &set->RR_PTR;
+ }
+ if (addrAR->resrec.RecordType != kDNSRecordTypeUnregistered) return;
- if (set->DirectLink)
- LogInfo("AdvertiseInterface: Marking address record as kDNSRecordTypeKnownUnique for %s", set->ifname);
+ addrRecordType = set->DirectLink ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (hostname == &m->RandomizedHostname) addrRecordType = kDNSRecordTypeKnownUnique;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "AdvertiseInterface: Advertising " PUB_S " hostname on interface " PUB_S,
+ (hostname == &m->RandomizedHostname) ? "randomized" : "normal", set->ifname);
+#else
+ LogInfo("AdvertiseInterface: Advertising for ifname %s", set->ifname);
+#endif
// Send dynamic update for non-linklocal IPv4 Addresses
- mDNS_SetupResourceRecord(&set->RR_A, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, recordType, AuthRecordAny, mDNS_HostNameCallback, set);
- mDNS_SetupResourceRecord(&set->RR_PTR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
- mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+ mDNS_SetupResourceRecord(addrAR, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, addrRecordType, AuthRecordAny, hostnameCallback, set);
+ if (ptrAR) mDNS_SetupResourceRecord(ptrAR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
#if ANSWER_REMOTE_HOSTNAME_QUERIES
- set->RR_A.AllowRemoteQuery = mDNStrue;
- set->RR_PTR.AllowRemoteQuery = mDNStrue;
- set->RR_HINFO.AllowRemoteQuery = mDNStrue;
+ addrAR->AllowRemoteQuery = mDNStrue;
+ if (ptrAR) ptrAR->AllowRemoteQuery = mDNStrue;
#endif
// 1. Set up Address record to map from host name ("foo.local.") to IP address
// 2. Set up reverse-lookup PTR record to map from our address back to our host name
- AssignDomainName(&set->RR_A.namestorage, &m->MulticastHostname);
+ AssignDomainName(&addrAR->namestorage, hostname);
if (set->ip.type == mDNSAddrType_IPv4)
{
- set->RR_A.resrec.rrtype = kDNSType_A;
- set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
+ addrAR->resrec.rrtype = kDNSType_A;
+ addrAR->resrec.rdata->u.ipv4 = set->ip.ip.v4;
// Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.",
set->ip.ip.v4.b[3], set->ip.ip.v4.b[2], set->ip.ip.v4.b[1], set->ip.ip.v4.b[0]);
else if (set->ip.type == mDNSAddrType_IPv6)
{
int i;
- set->RR_A.resrec.rrtype = kDNSType_AAAA;
- set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
+ addrAR->resrec.rrtype = kDNSType_AAAA;
+ addrAR->resrec.rdata->u.ipv6 = set->ip.ip.v6;
for (i = 0; i < 16; i++)
{
static const char hexValues[] = "0123456789ABCDEF";
mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
}
- MakeDomainNameFromDNSNameString(&set->RR_PTR.namestorage, buffer);
- set->RR_PTR.AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
- set->RR_PTR.ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
+ if (ptrAR)
+ {
+ MakeDomainNameFromDNSNameString(&ptrAR->namestorage, buffer);
+ ptrAR->AutoTarget = Target_AutoHost; // Tell mDNS that the target of this PTR is to be kept in sync with our host name
+ ptrAR->ForceMCast = mDNStrue; // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
+ }
- set->RR_A.RRSet = &primary->RR_A; // May refer to self
+ primary = FindFirstAdvertisedInterface(m);
+ if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
+ // We should never have primary be NULL, because even if there is
+ // no other interface yet, we should always find ourself in the list.
- mDNS_Register_internal(m, &set->RR_A);
- mDNS_Register_internal(m, &set->RR_PTR);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!interfaceIsAWDL && useRandomizedHostname)
+ {
+ addrAR->RRSet = &primary->RR_AddrRand;
+ }
+ else
+#endif
+ {
+ addrAR->RRSet = &primary->RR_A;
+ }
+ mDNS_Register_internal(m, addrAR);
+ if (ptrAR) mDNS_Register_internal(m, ptrAR);
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
// must be after the mDNS_Register_internal() calls so that records have complete rdata fields, etc
D2D_start_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
+#endif
+}
- if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
+mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set)
+{
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (mDNSPlatformInterfaceIsAWDL(set->InterfaceID))
{
- mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
- AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
- set->RR_HINFO.DependentOn = &set->RR_A;
- mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
- p += 1 + (int)p[0];
- mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
- mDNS_Register_internal(m, &set->RR_HINFO);
+ if ((m->AutoTargetAWDLIncludedCount > 0) || (m->AutoTargetAWDLOnlyCount > 0))
+ {
+ AdvertiseInterface(m, set, mDNSfalse);
+ }
}
else
{
- debugf("Not creating HINFO record: platform support layer provided no information");
- set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
+ if (m->AutoTargetServices > 0) AdvertiseInterface(m, set, mDNSfalse);
+ if (m->AutoTargetAWDLIncludedCount > 0) AdvertiseInterface(m, set, mDNStrue);
}
+#else
+ if (m->AutoTargetServices > 0) AdvertiseInterface(m, set);
+#endif
}
-mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags)
{
- if (m->AutoTargetServices == 0)
- {
- LogInfo("DeadvertiseInterface: Returning due to AutoTargetServices zero for %s", set->ifname);
- return;
- }
-
-#if APPLE_OSX_mDNSResponder
- D2D_stop_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ const mDNSBool interfaceIsAWDL = mDNSPlatformInterfaceIsAWDL(set->InterfaceID);
+#endif
// Unregister these records.
// When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
// support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
// Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
// To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
- if (set->RR_A .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
- if (set->RR_PTR .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
- if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
-}
-
-mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m)
-{
- NetworkInterfaceInfo *intf;
- for (intf = m->HostInterfaces; intf; intf = intf->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if ((!interfaceIsAWDL && (flags & kDeadvertiseFlag_NormalHostname)) ||
+ ( interfaceIsAWDL && (flags & kDeadvertiseFlag_RandHostname)))
+#else
+ if (flags & kDeadvertiseFlag_NormalHostname)
+#endif
{
- if (intf->Advertise)
- {
- LogInfo("AdvertiseInterface: Advertising for ifname %s", intf->ifname);
- AdvertiseInterface(m, intf);
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "DeadvertiseInterface: Deadvertising " PUB_S " hostname on interface " PUB_S,
+ (flags & kDeadvertiseFlag_RandHostname) ? "randomized" : "normal", set->ifname);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ D2D_stop_advertising_interface(set);
+#endif
+ if (set->RR_A.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A, mDNS_Dereg_normal);
+ if (set->RR_PTR.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
}
-}
-
-mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m)
-{
- NetworkInterfaceInfo *intf;
- for (intf = m->HostInterfaces; intf; intf = intf->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ if (!interfaceIsAWDL && (flags & kDeadvertiseFlag_RandHostname))
{
- if (intf->Advertise)
- {
- LogInfo("DeadvertiseInterface: Deadvertising for ifname %s", intf->ifname);
- DeadvertiseInterface(m, intf);
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "DeadvertiseInterface: Deadvertising randomized hostname on interface " PUB_S, set->ifname);
+ AuthRecord *const ar = &set->RR_AddrRand;
+ if (ar->resrec.RecordType) mDNS_Deregister_internal(m, ar, mDNS_Dereg_normal);
}
+#endif
}
// Change target host name for record.
mDNSlocal void UpdateTargetHostName(mDNS *const m, AuthRecord *const rr)
{
-#if APPLE_OSX_mDNSResponder
- // If this record was also registered with any D2D plugins, stop advertising
- // the version with the old host name.
- D2D_stop_advertising_record(rr);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ // If this record was also registered with any D2D plugins, stop advertising
+ // the version with the old host name.
+ D2D_stop_advertising_record(rr);
#endif
SetTargetToHostName(m, rr);
-#if APPLE_OSX_mDNSResponder
- // Advertise the record with the updated host name with the D2D plugins if appropriate.
- D2D_start_advertising_record(rr);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ // Advertise the record with the updated host name with the D2D plugins if appropriate.
+ D2D_start_advertising_record(rr);
#endif
}
+mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m, DeadvertiseFlags flags)
+{
+ NetworkInterfaceInfo *intf;
+ for (intf = m->HostInterfaces; intf; intf = intf->next)
+ {
+ if (intf->Advertise) DeadvertiseInterface(m, intf, flags);
+ }
+}
+
mDNSexport void mDNS_SetFQDN(mDNS *const m)
{
domainname newmname;
else
{
AssignDomainName(&m->MulticastHostname, &newmname);
- DeadvertiseAllInterfaceRecords(m);
- AdvertiseAllInterfaceRecords(m);
+ DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_NormalHostname);
+ AdvertiseNecessaryInterfaceRecords(m);
}
// 3. Make sure that any AutoTarget SRV records (and the like) get updated
LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result, rr->resrec.name->c);
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *const m, AuthRecord *const addrRecord, const mStatus result)
+{
+ (void)addrRecord; // Unused parameter
+
+ if (result == mStatus_NameConflict)
+ {
+ AuthRecord *rr;
+ domainlabel newUUIDLabel;
+
+ GetRandomUUIDLabel(&newUUIDLabel);
+ if (SameDomainLabel(newUUIDLabel.c, m->RandomizedHostname.c))
+ {
+ IncrementLabelSuffix(&newUUIDLabel, mDNSfalse);
+ }
+
+ mDNS_Lock(m);
+
+ m->RandomizedHostname.c[0] = 0;
+ AppendDomainLabel(&m->RandomizedHostname, &newUUIDLabel);
+ AppendLiteralLabelString(&m->RandomizedHostname, "local");
+
+ DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_RandHostname);
+ AdvertiseNecessaryInterfaceRecords(m);
+ for (rr = m->ResourceRecords; rr; rr = rr->next)
+ {
+ if (rr->AutoTarget && AuthRecordIncludesOrIsAWDL(rr)) UpdateTargetHostName(m, rr);
+ }
+ for (rr = m->DuplicateRecords; rr; rr = rr->next)
+ {
+ if (rr->AutoTarget && AuthRecordIncludesOrIsAWDL(rr)) UpdateTargetHostName(m, rr);
+ }
+
+ mDNS_Unlock(m);
+ }
+}
+#endif
+
mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
{
NetworkInterfaceInfo *intf;
if (set->InterfaceActive)
{
LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip);
- mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, mDNSNULL, set->InterfaceID, 0, mDNSfalse, mDNSfalse, m->SPSBrowseCallback, set);
+ mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, 0, mDNSfalse, mDNSfalse, m->SPSBrowseCallback, set);
}
}
set->next = mDNSNULL;
*p = set;
- if (set->Advertise)
- AdvertiseInterface(m, set);
+ if (set->Advertise) AdvertiseInterfaceIfNeeded(m, set);
- LogInfo("mDNS_RegisterInterface: InterfaceID %d %s (%#a) %s",
- (uint32_t)set->InterfaceID, set->ifname, &set->ip,
- set->InterfaceActive ?
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_RegisterInterface: InterfaceID %u " PUB_S " (" PRI_IP_ADDR ") " PUB_S,
+ IIDPrintable(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");
LogMsg("mDNS_RegisterInterface: Using fast activation for DirectLink interface %s (%#a)", set->ifname, &set->ip);
break;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
case SlowActivation:
probedelay = mDNSPlatformOneSecond * 5;
numannounce = (mDNSu8)1;
LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a), doing slow activation", set->ifname, &set->ip);
m->mDNSStats.InterfaceUpFlap++;
break;
+#endif
case NormalActivation:
default:
// us to reconnect to the network. If we do this as part of the wake up code, it is possible
// that the network link comes UP after 60 seconds and we never set the OWNER option
m->AnnounceOwner = NonZeroTime(m->timenow + 60 * mDNSPlatformOneSecond);
- LogInfo("mDNS_RegisterInterface: Setting AnnounceOwner");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "mDNS_RegisterInterface: Setting AnnounceOwner");
m->mDNSStats.InterfaceUp++;
for (q = m->Questions; q; q=q->next) // Scan our list of questions
{
if (!q->InterfaceID || q->InterfaceID == set->InterfaceID) // If non-specific Q, or Q on this specific interface,
{ // then reactivate this question
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
// If flapping, delay between first and second queries is nine seconds instead of one second
mDNSBool dodelay = (activationSpeed == SlowActivation) && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
mDNSs32 initial = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
mDNSs32 qdelay = dodelay ? kDefaultQueryDelayTimeForFlappingInterface : 0;
if (dodelay) LogInfo("No cache records expired for %##s (%s); delaying questions by %d seconds", q->qname.c, DNSTypeName(q->qtype), qdelay);
+#else
+ mDNSs32 initial = InitialQuestionInterval;
+ mDNSs32 qdelay = 0;
+#endif
if (!q->ThisQInterval || q->ThisQInterval > initial)
{
}
q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
q->RecentAnswerPkts = 0;
- // Change the salt
- ReInitAnonInfo(&q->AnonInfo, &q->qname);
SetNextQueryTime(m,q);
}
}
{
if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
{
- // Change the salt
- ReInitAnonInfo(&rr->resrec.AnonInfo, rr->resrec.name);
mDNSCoreRestartRegistration(m, rr, numannounce);
}
}
// 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, InterfaceActivationSpeed activationSpeed)
{
+#if !MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
+ (void)activationSpeed; // Unused parameter
+#endif
NetworkInterfaceInfo **p = &m->HostInterfaces;
mDNSBool revalidate = mDNSfalse;
NetworkInterfaceInfo *primary;
if (intf)
{
LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %d %s (%#a) exists;"
- " making it active", (uint32_t)set->InterfaceID, set->ifname, &set->ip);
+ " making it active", IIDPrintable(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;
DNSQuestion *q;
LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %d %s (%#a) deregistered;"
- " marking questions etc. dormant", (uint32_t)set->InterfaceID, set->ifname, &set->ip);
+ " marking questions etc. dormant", IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
m->mDNSStats.InterfaceDown++;
-
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
if (set->McastTxRx && (activationSpeed == SlowActivation))
{
LogMsg("mDNS_DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
m->mDNSStats.InterfaceDownFlap++;
}
+#endif
// 1. Deactivate any questions specific to this interface, and tag appropriate questions
// so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
{
if (rr->resrec.InterfaceID == set->InterfaceID)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
// If this interface is deemed flapping,
// postpone deleting the cache records in case the interface comes back again
if (set->McastTxRx && (activationSpeed == SlowActivation))
rr->UnansweredQueries = MaxUnansweredQueries;
}
else
+#endif
{
rr->resrec.mortality = Mortality_Mortal;
mDNS_PurgeCacheResourceRecord(m, rr);
intf->RR_A.RRSet = A;
// If we were advertising on this interface, deregister those address and reverse-lookup records now
- if (set->Advertise) DeadvertiseInterface(m, set);
+ if (set->Advertise) DeadvertiseInterface(m, set, kDeadvertiseFlag_All);
// If we have any cache records received on this interface that went away, then re-verify them.
// In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
mDNS_Unlock(m);
}
-mDNSlocal void SetAnonInfoSRS(ServiceRecordSet *sr, int NumSubTypes)
-{
- int i, len;
-
- if (!sr->AnonData)
- return;
-
- len = mDNSPlatformStrLen(sr->AnonData);
- if (sr->RR_PTR.resrec.AnonInfo)
- {
- LogMsg("SetAnonInfoSRS: Freeing AnonInfo for PTR record %##s, should have been freed already", sr->RR_PTR.resrec.name->c);
- FreeAnonInfo(sr->RR_PTR.resrec.AnonInfo);
- }
- sr->RR_PTR.resrec.AnonInfo = AllocateAnonInfo(sr->RR_PTR.resrec.name, sr->AnonData, len, mDNSNULL);
- for (i=0; i<NumSubTypes; i++)
- {
- if (sr->SubTypes[i].resrec.AnonInfo)
- {
- LogMsg("SetAnonInfoSRS: Freeing AnonInfo for subtype record %##s, should have been freed already", sr->SubTypes[i].resrec.name->c);
- FreeAnonInfo(sr->SubTypes[i].resrec.AnonInfo);
- }
- sr->SubTypes[i].resrec.AnonInfo = AllocateAnonInfo(sr->SubTypes[i].resrec.name, sr->AnonData, len, mDNSNULL);
- }
-}
-
-mDNSlocal void ResetAnonInfoSRS(ServiceRecordSet *sr, int NumSubTypes)
-{
- int i;
-
- if (!sr->AnonData)
- return;
- if (sr->RR_PTR.resrec.AnonInfo)
- {
- FreeAnonInfo(sr->RR_PTR.resrec.AnonInfo);
- sr->RR_PTR.resrec.AnonInfo = mDNSNULL;
- }
- for (i=0; i<NumSubTypes; i++)
- {
- if (sr->SubTypes[i].resrec.AnonInfo)
- {
- FreeAnonInfo(sr->SubTypes[i].resrec.AnonInfo);
- sr->SubTypes[i].resrec.AnonInfo = mDNSNULL;
- }
- }
-}
-
mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
if (e->r.resrec.RecordType != kDNSRecordTypeUnregistered) return;
e = e->next;
}
- ResetAnonInfoSRS(sr, sr->NumSubTypes);
// If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
// then we can now report the NameConflict to the client
return artype;
}
-// Used to derive the original D2D specific flags specified by the client in the registration
-// when we don't have access to the original flag (kDNSServiceFlags*) values.
-mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
-{
- mDNSu32 flags = 0;
- if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
- flags |= kDNSServiceFlagsIncludeP2P;
- else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
- flags |= kDNSServiceFlagsIncludeAWDL;
- return flags;
-}
-
// Note:
// Name is first label of domain name (any dots in the name are actual dots, not label separators)
// Type is service type (e.g. "_ipp._tcp.")
{
mStatus err;
mDNSu32 i;
- mDNSu32 hostTTL;
AuthRecType artype;
mDNSu8 recordType = (flags & kDNSServiceFlagsKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
sr->RR_PTR.AuthFlags = AuthFlagsWakeOnly;
}
- if (SameDomainName(type, (const domainname *) "\x4" "_ubd" "\x4" "_tcp"))
- hostTTL = kHostNameSmallTTL;
- else
- hostTTL = kHostNameTTL;
-
- mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr);
+ mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, recordType, artype, ServiceCallback, sr);
mDNS_SetupResourceRecord(&sr->RR_TXT, txtrdata, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr);
// If port number is zero, that means the client is really trying to do a RegisterNoSuchService
sr->SubTypes[i].Additional2 = &sr->RR_TXT;
}
- SetAnonInfoSRS(sr, NumSubTypes);
-
// 3. Set up the SRV record rdata.
sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
sr->RR_SRV.resrec.rdata->u.srv.weight = 0;
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);
+ // If there's a pending TXT record update at this point, which can happen if a DNSServiceUpdateRecord() call was made
+ // after the TXT record's deregistration, execute it now, otherwise it will be lost during the service re-registration.
+ if (sr->RR_TXT.NewRData) CompleteRDataUpdate(m, &sr->RR_TXT);
err = mDNS_RegisterService(m, sr, newname, &type, &domain,
host, sr->RR_SRV.resrec.rdata->u.srv.port,
(sr->RR_TXT.resrec.rdata != &sr->RR_TXT.rdatastorage) ? sr->RR_TXT.resrec.rdata : mDNSNULL,
// SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
-
mDNS_Deregister_internal(m, &sr->RR_ADV, drt);
// We deregister all of the extra records, but we leave the sr->Extras list intact
static const char msg3[] = "Creating Local NDP Cache entry ";
static const char msg4[] = "Answering NDP Request from ";
static const char msg5[] = "Answering NDP Probe from ";
- const char *const msg = sha && mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
- (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
- sha && mDNSSameEthAddress(sha, &intf->MAC) ? msg3 :
- spa && mDNSIPv6AddressIsZero(*spa) ? msg4 : msg5;
+ const char *const msg = mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
+ (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
+ mDNSSameEthAddress(sha, &intf->MAC) ? msg3 :
+ mDNSIPv6AddressIsZero(*spa) ? msg4 : msg5;
LogSPS("%-7s %s %.6a %.16a for %.16a -- H-MAC %.6a I-MAC %.6a %s",
intf->ifname, msg, sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
if (msg == msg1)
const mDNSu8 *const trans = p + 14 + (pkt->v4.vlen & 0xF) * 4;
const mDNSu8 * transEnd = p + 14 + mDNSVal16(pkt->v4.totlen);
if (transEnd > end) transEnd = end;
- debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src, &pkt->v4.dst);
+ debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src.b, &pkt->v4.dst.b);
src.type = mDNSAddrType_IPv4; src.ip.v4 = pkt->v4.src;
dst.type = mDNSAddrType_IPv4; dst.ip.v4 = pkt->v4.dst;
if (transEnd >= trans + RequiredCapLen(pkt->v4.protocol))
else if (end >= p+54 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv6))
{
const mDNSu8 *const trans = p + 54;
- debugf("Got IPv6 %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src, &pkt->v6.dst);
+ debugf("Got IPv6 %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src.b, &pkt->v6.dst.b);
src.type = mDNSAddrType_IPv6; src.ip.v6 = pkt->v6.src;
dst.type = mDNSAddrType_IPv6; dst.ip.v6 = pkt->v6.dst;
if (end >= trans + RequiredCapLen(pkt->v6.pro))
if (!rrcachestorage) rrcachesize = 0;
+ m->next_request_id = 1;
m->p = p;
m->NetworkChanged = 0;
m->CanReceiveUnicastOn5353 = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
m->MainCallback = Callback;
m->MainContext = Context;
m->rec.r.resrec.RecordType = 0;
- m->rec.r.resrec.AnonInfo = mDNSNULL;
// For debugging: To catch and report locking failures
m->mDNS_busy = 0;
m->NextScheduledStopTime = timenow + FutureTime;
m->NextBLEServiceTime = 0; // zero indicates inactive
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
m->NextBonjourDisableTime = 0; // Timer active when non zero.
m->BonjourEnabled = 0; // Set when Bonjour on Demand is enabled and Bonjour is currently enabled.
-#endif // BONJOUR_ON_DEMAND
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+ m->NextSuspiciousTimeout = 0;
+#endif
- m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
m->RandomQueryDelay = 0;
m->RandomReconfirmDelay = 0;
m->PktNum = 0;
m->hostlabel.c[0] = 0;
m->nicelabel.c[0] = 0;
m->MulticastHostname.c[0] = 0;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ m->RandomizedHostname.c[0] = 0;
+#endif
m->HIHardware.c[0] = 0;
m->HISoftware.c[0] = 0;
m->ResourceRecords = mDNSNULL;
m->StaticHostname.c[0] = 0;
m->FQDN.c[0] = 0;
m->Hostnames = mDNSNULL;
- m->AutoTunnelNAT.clientContext = mDNSNULL;
m->WABBrowseQueriesCount = 0;
m->WABLBrowseQueriesCount = 0;
m->WABRegQueriesCount = 0;
m->AutoTargetServices = 0;
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
m->NumAllInterfaceRecords = 0;
m->NumAllInterfaceQuestions = 0;
#endif
m->DNSPushZones = mDNSNULL;
#endif
-#if APPLE_OSX_mDNSResponder
- m->TunnelClients = mDNSNULL;
-
-#if !NO_WCF
- CHECK_WCF_FUNCTION(WCFConnectionNew)
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ if (WCFConnectionNew)
{
m->WCF = WCFConnectionNew();
if (!m->WCF) { LogMsg("WCFConnectionNew failed"); return -1; }
}
-#endif
-
#endif
return(result);
mStatus result = mDNS_InitStorage(m, p, rrcachestorage, rrcachesize, AdvertiseLocalAddresses, Callback, Context);
if (result != mStatus_NoError)
return(result);
-
+
+#if MDNS_MALLOC_DEBUGGING
+ static mDNSListValidator lv;
+ mDNSPlatformAddListValidator(&lv, mDNS_ValidateLists, "mDNS_ValidateLists", m);
+#endif
result = mDNSPlatformInit(m);
#ifndef UNICAST_DISABLED
mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
}
-mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck)
+mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr)
{
mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative ||
cr->resrec.rrtype == kDNSType_A ||
cr->resrec.rrtype == kDNSType_SRV ||
cr->resrec.rrtype == kDNSType_CNAME;
- (void) lameduck;
- (void) ptr;
- debugf("PurgeOrReconfirmCacheRecord: %s cache record due to %s server %p %#a:%d (%##s): %s",
+ debugf("PurgeOrReconfirmCacheRecord: %s cache record due to server %#a:%d (%##s): %s",
purge ? "purging" : "reconfirming",
- lameduck ? "lame duck" : "new",
- ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
+ cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL,
+ cr->resrec.rDNSServer ? mDNSVal16(cr->resrec.rDNSServer->port) : -1,
+ cr->resrec.rDNSServer ? cr->resrec.rDNSServer->domain.c : mDNSNULL, CRDisplayString(m, cr));
if (purge)
{
LogInfo("PurgeorReconfirmCacheRecord: Purging Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType);
+ cr->resrec.mortality = Mortality_Mortal;
mDNS_PurgeCacheResourceRecord(m, cr);
}
else
}
for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
{
- if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(rp, q))
{
LogInfo("mDNS_PurgeBeforeResolve: Flushing %s", CRDisplayString(m, rp));
mDNS_PurgeCacheResourceRecord(m, rp);
for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
{
- if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(rp, q))
{
if (rp->resrec.RecordType != kDNSRecordTypePacketNegative || !rp->nsec)
{
}
}
-// Check for a positive unicast response to the question but with qtype
-mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype)
-{
- DNSQuestion question;
- CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
- CacheRecord *rp;
-
- // Create an identical question but with qtype
- mDNS_SetupQuestion(&question, q->InterfaceID, &q->qname, qtype, mDNSNULL, mDNSNULL);
- question.qDNSServer = q->qDNSServer;
-
- for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
- {
- if (!rp->resrec.InterfaceID && rp->resrec.RecordType != kDNSRecordTypePacketNegative &&
- SameNameRecordAnswersQuestion(&rp->resrec, &question))
- {
- LogInfo("mDNS_CheckForCacheRecord: Found %s", CRDisplayString(m, rp));
- return mDNStrue;
- }
- }
- return mDNSfalse;
-}
-
mDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new)
{
DNSQuestion *qptr;
for (ptr = m->DNSServers; ptr; ptr = ptr->next)
{
ptr->penaltyTime = 0;
- NumUnicastDNSServers--;
- ptr->flags |= DNSServer_FlagDelete;
-#if APPLE_OSX_mDNSResponder
- if (ptr->flags & DNSServer_FlagUnreachable)
+ ptr->flags |= DNSServerFlag_Delete;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+ if (ptr->flags & DNSServerFlag_Unreachable)
NumUnreachableDNSServers--;
#endif
}
for (ptr = m->DNSServers; ptr; ptr = ptr->next)
{
ptr->penaltyTime = 0;
- NumUnicastDNSServers++;
- ptr->flags &= ~DNSServer_FlagDelete;
-#if APPLE_OSX_mDNSResponder
- if (ptr->flags & DNSServer_FlagUnreachable)
+ ptr->flags &= ~DNSServerFlag_Delete;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+ if (ptr->flags & DNSServerFlag_Unreachable)
NumUnreachableDNSServers++;
#endif
}
}
}
+// Even though this is called “Setup” it is not called just once at startup.
+// It’s actually called multiple times, every time there’s a configuration change.
mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
{
mDNSu32 slot;
CacheGroup *cg;
CacheRecord *cr;
- mDNSBool Restart = mDNSfalse;
mDNSAddr v4, v6, r;
domainname fqdn;
DNSServer *ptr, **p = &m->DNSServers;
const DNSServer *oldServers = m->DNSServers;
DNSQuestion *q;
McastResolver *mr, **mres = &m->McastResolvers;
-
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ DNSPushNotificationServer **psp;
+#endif
+
debugf("uDNS_SetupDNSConfig: entry");
// Let the platform layer get the current DNS information and setup the WAB queries if needed.
// cache records and as the resGroupID is different, you can't use the cache record from the scoped DNSServer to answer the
// non-scoped question and vice versa.
//
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
DNS64RestartQuestions(m);
#endif
- for (q = m->Questions; q; q=q->next)
+
+ // First, restart questions whose suppression status will change. The suppression status of each question in a given
+ // question set, i.e., a non-duplicate question and all of its duplicates, if any, may or may not change. For example,
+ // a suppressed (or non-suppressed) question that is currently a duplicate of a suppressed (or non-suppressed) question
+ // may become a non-suppressed (or suppressed) question, while the question that it's a duplicate of may remain
+ // suppressed (or non-suppressed).
+ for (q = m->Questions; q; q = q->next)
{
- if (!mDNSOpaque16IsZero(q->TargetQID))
- {
- DNSServer *s, *t;
- DNSQuestion *qptr;
- if (q->DuplicateOf) continue;
- SetValidDNSServers(m, q);
- q->triedAllServersOnce = 0;
- s = GetServerForQuestion(m, q);
- t = q->qDNSServer;
- if (t != s)
- {
- mDNSBool old, new;
- // If DNS Server for this question has changed, reactivate it
- LogInfo("uDNS_SetupDNSConfig: Updating DNS Server from %#a:%d (%##s) to %#a:%d (%##s) for question %##s (%s) (scope:%p)",
- t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
- s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
- q->qname.c, DNSTypeName(q->qtype), q->InterfaceID);
-
- old = q->SuppressQuery;
- new = ShouldSuppressUnicastQuery(m, q, s);
- if (old != new)
- {
- // Changing the DNS server affected the SuppressQuery status. We need to
- // deliver RMVs for the previous ADDs (if any) before switching to the new
- // DNSServer. To keep it simple, we walk all the questions and mark them
- // to be restarted and then handle all of them at once.
- q->Restart = 1;
- q->SuppressQuery = new;
- for (qptr = q->next ; qptr; qptr = qptr->next)
- {
- if (qptr->DuplicateOf == q)
- qptr->Restart = 1;
- }
- Restart = mDNStrue;
- }
- else
- {
- DNSServerChangeForQuestion(m, q, s);
- q->unansweredQueries = 0;
+ DNSServer *s;
+ const DNSServer *t;
+ mDNSBool oldSuppressed;
- // If we had sent a query out to DNSServer "t" and we are changing to "s", we
- // need to ignore the responses coming back from "t" as the DNS configuration
- // has changed e.g., when a new interface is coming up and that becomes the primary
- // interface, we switch to the DNS servers configured for the primary interface. In
- // this case, we should not accept responses associated with the previous interface as
- // the "name" could resolve differently on this new primary interface. Hence, discard
- // in-flight responses.
- q->TargetQID = mDNS_NewMessageID(m);
+ if (mDNSOpaque16IsZero(q->TargetQID)) continue;
- if (!QuerySuppressed(q))
- {
- debugf("uDNS_SetupDNSConfig: Activating query %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
- ActivateUnicastQuery(m, q, mDNStrue);
- // ActivateUnicastQuery is called for duplicate questions also as it does something
- // special for AutoTunnel questions
- for (qptr = q->next ; qptr; qptr = qptr->next)
- {
- if (qptr->DuplicateOf == q) ActivateUnicastQuery(m, qptr, mDNStrue);
- }
- }
+ SetValidDNSServers(m, q);
+ q->triedAllServersOnce = mDNSfalse;
+ s = GetServerForQuestion(m, q);
+ t = q->qDNSServer;
+ if (s != t)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_SetupDNSConfig: Updating DNS server from " PRI_IP_ADDR ":%d (" PRI_DM_NAME ") to "
+ PRI_IP_ADDR ":%d (" PRI_DM_NAME ") for question " PRI_DM_NAME " (" PUB_S ") (scope:%p)",
+ q->request_id, mDNSVal16(q->TargetQID),
+ t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), DM_NAME_PARAM(t ? t->domain.c : (mDNSu8*)""),
+ s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), DM_NAME_PARAM(s ? s->domain.c : (mDNSu8*)""),
+ DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), q->InterfaceID);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ // If this question had a DNS Push server associated with it, substitute the new server for the
+ // old one. If there is no new server, then we'll clean up the push server later.
+ if (!q->DuplicateOf && (q->dnsPushServer != mDNSNULL))
+ {
+ if (q->dnsPushServer->qDNSServer == t)
+ {
+ q->dnsPushServer->qDNSServer = s; // which might be null
+ }
+ // If it is null, do the accounting and drop the push server.
+ if (q->dnsPushServer->qDNSServer == mDNSNULL)
+ {
+ DNSPushReconcileConnection(m, q);
}
}
- else
+#endif
+ }
+ oldSuppressed = q->Suppressed;
+ q->Suppressed = ShouldSuppressUnicastQuery(q, s);
+ if (!q->Suppressed != !oldSuppressed) q->Restart = mDNStrue;
+ }
+ RestartUnicastQuestions(m);
+
+ // Now, change the server for each question set, if necessary. Note that questions whose suppression status changed
+ // have already had their server changed by being restarted.
+ for (q = m->Questions; q; q = q->next)
+ {
+ DNSServer *s;
+ const DNSServer *t;
+
+ if (mDNSOpaque16IsZero(q->TargetQID) || q->DuplicateOf) continue;
+
+ SetValidDNSServers(m, q);
+ q->triedAllServersOnce = mDNSfalse;
+ s = GetServerForQuestion(m, q);
+ t = q->qDNSServer;
+ DNSServerChangeForQuestion(m, q, s);
+ if (s == t) continue;
+
+ q->Suppressed = ShouldSuppressUnicastQuery(q, s);
+ q->unansweredQueries = 0;
+ q->TargetQID = mDNS_NewMessageID(m);
+ if (!q->Suppressed) ActivateUnicastQuery(m, q, mDNStrue);
+ }
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ // The above code may have found some DNS Push servers that are no longer valid. Now that we
+ // are done running through the code, we need to drop our connections to those servers.
+ // When we get here, any such servers should have zero questions associated with them.
+ for (psp = &m->DNSPushServers; *psp != mDNSNULL; )
+ {
+ DNSPushNotificationServer *server = *psp;
+
+ // It's possible that a push server whose DNS server has been deleted could be still connected but
+ // not referenced by any questions. In this case, we just delete the push server rather than trying
+ // to figure out with which DNS server (if any) to associate it.
+ if (server->qDNSServer != mDNSNULL && server->qDNSServer->flags & DNSServerFlag_Delete)
+ {
+ server->qDNSServer = mDNSNULL;
+ }
+
+ if (server->qDNSServer == mDNSNULL)
+ {
+ // This would be a programming error, so should never happen.
+ if (server->numberOfQuestions != 0)
{
- debugf("uDNS_SetupDNSConfig: Not Updating DNS server question %p %##s (%s) DNS server %#a:%d %p %d",
- q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), q->DuplicateOf, q->SuppressUnusable);
- for (qptr = q->next ; qptr; qptr = qptr->next)
- if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
+ LogInfo("uDNS_SetupDNSConfig: deleting push server %##s that has questions.", &server->serverName);
}
+ DNSPushServerDrop(server);
+ *psp = server->next;
+ mDNSPlatformMemFree(server);
+ }
+ else
+ {
+ psp = &(*psp)->next;
}
}
- if (Restart)
- RestartUnicastQuestions(m);
+#endif
FORALL_CACHERECORDS(slot, cg, cr)
{
- if (cr->resrec.InterfaceID)
- continue;
+ if (cr->resrec.InterfaceID) continue;
// We already walked the questions and restarted/reactivated them if the dns server
// change affected the question. That should take care of updating the cache. But
// the questions if they were suppressed (see above). To keep it simple, we walk
// all the cache entries to make sure that there are no stale entries. We use the
// active question's InterfaceID/ServiceID for looking up the right DNS server.
- // Note that the unscoped value for ServiceID is -1.
//
// Note: If GetServerForName returns NULL, it could either mean that there are no
// DNS servers or no matching DNS servers for this question. In either case,
// the cache should get purged below when we process deleted DNS servers.
+ //
+ // If it is a DNSSEC question, purge the cache as the DNSSEC capabilities of the
+ // DNS server may have changed.
- ptr = GetServerForName(m, cr->resrec.name,
- (cr->CRActiveQuestion ? cr->CRActiveQuestion->InterfaceID : mDNSNULL),
- (cr->CRActiveQuestion ? cr->CRActiveQuestion->ServiceID : -1));
-
- // Purge or Reconfirm if this cache entry would use the new DNS server
- if (ptr && (ptr != cr->resrec.rDNSServer))
+ if (cr->CRActiveQuestion && !DNSSECQuestion(cr->CRActiveQuestion))
{
- // As the DNSServers for this cache record is not the same anymore, we don't
- // want any new questions to pick this old value. If there is no active question,
- // we can't possibly re-confirm, so purge in that case. If it is a DNSSEC question,
- // purge the cache as the DNSSEC capabilities of the DNS server may have changed.
-
- if (cr->CRActiveQuestion == mDNSNULL || DNSSECQuestion(cr->CRActiveQuestion))
+ // Purge or Reconfirm if this cache entry would use the new DNS server
+ ptr = GetServerForName(m, cr->resrec.name, cr->CRActiveQuestion->InterfaceID, cr->CRActiveQuestion->ServiceID);
+ if (ptr && (ptr != cr->resrec.rDNSServer))
{
- LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s, New DNS server %#a , Old DNS server %#a", CRDisplayString(m, cr),
- &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ? &cr->resrec.rDNSServer->addr : mDNSNULL));
- cr->resrec.mortality = Mortality_Mortal;
- mDNS_PurgeCacheResourceRecord(m, cr);
+ LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s, New DNS server %#a, Old DNS server %#a",
+ CRDisplayString(m, cr), &ptr->addr,
+ cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL);
+ PurgeOrReconfirmCacheRecord(m, cr);
+
+ // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
+ // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
+ if (!cr->resrec.rDNSServer && cr->CRActiveQuestion->qDNSServer)
+ {
+ LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->CRActiveQuestion->qDNSServer->addr, CRDisplayString(m, cr));
+ cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
+ }
}
- else
+
+ if (cr->resrec.rDNSServer && cr->resrec.rDNSServer->flags & DNSServerFlag_Delete)
{
- LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s, New DNS server %#a, Old DNS server %#a", CRDisplayString(m, cr),
- &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ? &cr->resrec.rDNSServer->addr : mDNSNULL));
- PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
+ DNSQuestion *qptr = cr->CRActiveQuestion;
+ if (qptr->qDNSServer == cr->resrec.rDNSServer)
+ {
+ LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
+ " to be freed", CRDisplayString(m, cr),
+ qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID,
+ &cr->resrec.rDNSServer->addr);
+ qptr->validDNSServers = zeroOpaque128;
+ qptr->qDNSServer = mDNSNULL;
+ cr->resrec.rDNSServer = mDNSNULL;
+ }
+ else
+ {
+ LogInfo("uDNS_SetupDNSConfig: Cache Record %s, Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
+ " resetting to question's DNSServer Address %#a", CRDisplayString(m, cr),
+ qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID,
+ &cr->resrec.rDNSServer->addr,
+ qptr->qDNSServer ? &qptr->qDNSServer->addr : mDNSNULL);
+ cr->resrec.rDNSServer = qptr->qDNSServer;
+ }
+ PurgeOrReconfirmCacheRecord(m, cr);
}
}
-
- // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
- // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
- if (!cr->resrec.rDNSServer && cr->CRActiveQuestion && cr->CRActiveQuestion->qDNSServer)
+ else if (!cr->resrec.rDNSServer || cr->resrec.rDNSServer->flags & DNSServerFlag_Delete)
{
- cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
- LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->resrec.rDNSServer->addr, CRDisplayString(m, cr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "uDNS_SetupDNSConfig: Purging Resourcerecord " PRI_S ", DNS server " PUB_S " " PRI_IP_ADDR " " PUB_S,
+ CRDisplayString(m, cr), !cr->resrec.rDNSServer ? "(to be deleted)" : "",
+ cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL,
+ cr->resrec.rDNSServer ? DNSScopeToString(cr->resrec.rDNSServer->scopeType) : "" );
+ cr->resrec.rDNSServer = mDNSNULL;
+ cr->resrec.mortality = Mortality_Mortal;
+ mDNS_PurgeCacheResourceRecord(m, cr);
}
}
+ // Delete all the DNS servers that are flagged for deletion
while (*p)
{
- if (((*p)->flags & DNSServer_FlagDelete) != 0)
+ if (((*p)->flags & DNSServerFlag_Delete) != 0)
{
- // Scan our cache, looking for uDNS records that we would have queried this server for.
- // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
- // different DNS servers can give different answers to the same question.
ptr = *p;
- FORALL_CACHERECORDS(slot, cg, cr)
- {
- if (cr->resrec.InterfaceID) continue;
- if (cr->resrec.rDNSServer == ptr)
- {
- // If we don't have an active question for this cache record, neither Purge can
- // generate RMV events nor Reconfirm can send queries out. Just set the DNSServer
- // pointer on the record NULL so that we don't point to freed memory (We might dereference
- // DNSServer pointers from resource record for logging purposes).
- //
- // If there is an active question, point to its DNSServer as long as it does not point to the
- // freed one. We already went through the questions above and made them point at either the
- // new server or NULL if there is no server.
-
- if (cr->CRActiveQuestion)
- {
- DNSQuestion *qptr = cr->CRActiveQuestion;
-
- if (qptr->qDNSServer == ptr)
- {
- LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
- " to be freed", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID, &ptr->addr);
- qptr->validDNSServers = zeroOpaque128;
- qptr->qDNSServer = mDNSNULL;
- cr->resrec.rDNSServer = mDNSNULL;
- }
- else
- {
- LogInfo("uDNS_SetupDNSConfig: Cache Record %s, Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
- " resetting to question's DNSServer Address %#a", CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype),
- qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer) ? &qptr->qDNSServer->addr : mDNSNULL);
- cr->resrec.rDNSServer = qptr->qDNSServer;
- }
- }
- else
- {
- LogInfo("uDNS_SetupDNSConfig: Cache Record %##s has no Active question, Record's DNSServer Address %#a, Server to be deleted %#a",
- cr->resrec.name, &cr->resrec.rDNSServer->addr, &ptr->addr);
- cr->resrec.rDNSServer = mDNSNULL;
- }
-
- cr->resrec.mortality = Mortality_Mortal;
- PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
- }
- }
*p = (*p)->next;
- LogInfo("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s) %d", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, NumUnicastDNSServers);
+ LogInfo("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
mDNSPlatformMemFree(ptr);
}
else
{
- (*p)->flags &= ~DNSServer_FlagNew;
p = &(*p)->next;
}
}
+ LogInfo("uDNS_SetupDNSConfig: CountOfUnicastDNSServers %d", CountOfUnicastDNSServers(m));
// If we now have no DNS servers at all and we used to have some, then immediately purge all unicast cache records (including for LLQs).
// This is important for giving prompt remove events when the user disconnects the Ethernet cable or turns off wireless.
if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
}
- debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", NumUnicastDNSServers);
+ debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", CountOfUnicastDNSServers(m));
return mStatus_NoError;
}
mDNSCoreBeSleepProxyServer_internal(m, 0, 0, 0, 0, 0);
-#if APPLE_OSX_mDNSResponder
-#if !NO_WCF
- CHECK_WCF_FUNCTION(WCFConnectionDealloc)
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ if (WCFConnectionDealloc)
{
- if (m->WCF) WCFConnectionDealloc((WCFConnection *)m->WCF);
+ if (m->WCF) WCFConnectionDealloc(m->WCF);
}
#endif
-#endif
#ifndef UNICAST_DISABLED
{
}
#endif
- DeadvertiseAllInterfaceRecords(m);
+ DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_All);
// Shut down all our active NAT Traversals
while (m->NATTraversals)
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
#ifndef __mDNSDebug_h
#define __mDNSDebug_h
+#include "mDNSFeatures.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+#include <os/log.h>
+#endif
+
// Set MDNS_DEBUGMSGS to 0 to optimize debugf() calls out of the compiled code
// Set MDNS_DEBUGMSGS to 1 to generate normal debugging messages
// Set MDNS_DEBUGMSGS to 2 to generate verbose debugging messages
// warning: double format, pointer arg (arg 2) (for %.4a, %.16a, %#a -- IP address formats)
#define MDNS_CHECK_PRINTF_STYLE_FUNCTIONS 0
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+typedef os_log_t mDNSLogCategory_t;
+
+typedef os_log_type_t mDNSLogLevel_t;
+#define MDNS_LOG_FAULT OS_LOG_TYPE_FAULT
+#define MDNS_LOG_ERROR OS_LOG_TYPE_ERROR
+#define MDNS_LOG_WARNING OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_DEFAULT OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_INFO OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_DEBUG OS_LOG_TYPE_DEBUG
+#else
+typedef const char * mDNSLogCategory_t;
typedef enum
{
- MDNS_LOG_MSG,
- MDNS_LOG_OPERATION,
- MDNS_LOG_SPS,
- MDNS_LOG_INFO,
- MDNS_LOG_DEBUG,
+ MDNS_LOG_FAULT = 1,
+ MDNS_LOG_ERROR = 2,
+ MDNS_LOG_WARNING = 3,
+ MDNS_LOG_DEFAULT = 4,
+ MDNS_LOG_INFO = 5,
+ MDNS_LOG_DEBUG = 6
} mDNSLogLevel_t;
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ extern os_log_t mDNSLogCategory_Default;
+ extern os_log_t mDNSLogCategory_mDNS;
+ extern os_log_t mDNSLogCategory_uDNS;
+ extern os_log_t mDNSLogCategory_SPS;
+ extern os_log_t mDNSLogCategory_XPC;
+
+ #define MDNS_LOG_CATEGORY_DEFINITION(NAME) mDNSLogCategory_ ## NAME
+#else
+ #define MDNS_LOG_CATEGORY_DEFINITION(NAME) # NAME
+#endif
+
+#define MDNS_LOG_CATEGORY_DEFAULT MDNS_LOG_CATEGORY_DEFINITION(Default)
+#define MDNS_LOG_CATEGORY_MDNS MDNS_LOG_CATEGORY_DEFINITION(mDNS)
+#define MDNS_LOG_CATEGORY_UDNS MDNS_LOG_CATEGORY_DEFINITION(uDNS)
+#define MDNS_LOG_CATEGORY_SPS MDNS_LOG_CATEGORY_DEFINITION(SPS)
+#define MDNS_LOG_CATEGORY_XPC MDNS_LOG_CATEGORY_DEFINITION(XPC)
-// Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
+// Set this symbol to 1 to answer remote queries for our Address, and reverse mapping PTR
#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 1
+// #define MDNS_MALLOC_DEBUGGING 1
+
+#if (MDNS_MALLOC_DEBUGGING > 0) && defined(WIN32)
+#error "Malloc debugging does not yet work on Windows"
+#endif
//#define ForceAlerts 1
//#define LogTimeStamps 1
#if (MDNS_HAS_VA_ARG_MACROS)
#if (MDNS_C99_VA_ARGS)
- #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)
- #define LogDebug(... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG, __VA_ARGS__);} while (0)
+ #define MDNS_LOG_DEFINITION(LEVEL, ...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, LEVEL, __VA_ARGS__); } while (0)
+
+ #define debug_noop(...) do {} while(0)
+ #define LogMsg(...) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, __VA_ARGS__)
+ #define LogOperation(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, __VA_ARGS__)
+ #define LogSPS(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, __VA_ARGS__)
+ #define LogInfo(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, __VA_ARGS__)
+ #define LogDebug(...) MDNS_LOG_DEFINITION(MDNS_LOG_DEBUG, __VA_ARGS__)
#elif (MDNS_GNU_VA_ARGS)
- #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)
- #define LogDebug( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG, ARGS);} while (0)
+ #define MDNS_LOG_DEFINITION(LEVEL, ARGS...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, LEVEL, ARGS); } while (0)
+
+ #define debug_noop(ARGS...) do {} while (0)
+ #define LogMsg(ARGS... ) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, ARGS)
+ #define LogOperation(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, ARGS)
+ #define LogSPS(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, ARGS)
+ #define LogInfo(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO, ARGS)
+ #define LogDebug(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_DEBUG, ARGS)
#else
- #error Unknown variadic macros
+ #error "Unknown variadic macros"
#endif
#else
// If your platform does not support variadic macros, you need to define the following variadic functions.
extern void LogDebug_(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);
extern int mDNS_DebugMode; // If non-zero, LogMsg() writes to stderr instead of syslog
extern const char ProgramName[];
-extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
+extern void LogMsgWithLevel(mDNSLogCategory_t category, mDNSLogLevel_t level, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
// LogMsgNoIdent needs to be fixed so that it logs without the ident prefix like it used to
// (or completely overhauled to use the new "log to a separate file" facility)
#define LogMsgNoIdent LogMsg
#define LogFatalError LogMsg
#endif
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
-extern void *mallocL(char *msg, unsigned int size);
-extern void freeL(char *msg, void *x);
-extern void uds_validatelists(void);
-extern void udns_validatelists(void *const v);
+#if MDNS_MALLOC_DEBUGGING >= 1
+extern void *mallocL(const char *msg, mDNSu32 size);
+extern void *callocL(const char *msg, mDNSu32 size);
+extern void freeL(const char *msg, void *x);
+#if APPLE_OSX_mDNSResponder
extern void LogMemCorruption(const char *format, ...);
#else
-#define mallocL(X,Y) malloc(Y)
-#define callocL(X,Y) calloc(1, Y)
-#define freeL(X,Y) free(Y)
+#define LogMemCorruption LogMsg
+#endif
+#else
+#define mallocL(MSG, SIZE) malloc(SIZE)
+#define callocL(MSG, SIZE) calloc(1, SIZE)
+#define freeL(MSG, PTR) free(PTR)
#endif
#ifdef __cplusplus
}
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+/** @brief Write a log message to system's log storage(memory or disk).
+ *
+ * On Apple platform, os_log() will be called to log a message.
+ *
+ * @param CATEGORY A custom log object previously created by the os_log_create function, and such an object is
+ * used to specify "subsystem" and "category". For mDNSResponder, the subsystem should always
+ * be set to "com.apple.mDNSResponder"; and the category is used for categorization and
+ * filtering of related log messages within the subsystem’s settings. We have 4 categories that
+ * are pre-defined: MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_CATEGORY_UDNS,
+ * MDNS_LOG_CATEGORY_SPS. If these categories are not enough, use os_log_create to create more.
+ *
+ * @param LEVEL The log level that determines the importance of the message. The levels are, in order of
+ * decreasing importance:
+ * MDNS_LOG_FAULT Fault-level messages are intended for capturing system-level errors
+ * that are critical to the system. They are always saved in the data store.
+ * MDNS_LOG_ERROR Error-level messages are intended for reporting process-level errors
+ * that are unexpected and incorrect during the normal operation. They
+ * are always saved in the data store.
+ * MDNS_LOG_WARNING Warning-level messages are intended for capturing unexpected and
+ * possible incorrect behavior that might be used later to root cause
+ * an error or fault. They are are initially stored in memory buffers
+ * and then moved to a data store.
+ * MDNS_LOG_DEFAULT Default-level messages are intended for reporting things that might
+ * result a failure. They are are initially stored in memory buffers
+ * and then moved to a data store.
+ * MDNS_LOG_INFO Info-level messages are intended for capturing information that may
+ * be helpful, but isn’t essential, for troubleshooting errors. They
+ * are initially stored in memory buffers, but will only be moved into
+ * data store when faults and, optionally, errors occur.
+ * MDNS_LOG_DEBUG Debug-level messages are intended for information that may be useful
+ * during development or while troubleshooting a specific problem, Debug
+ * logging should not be used in shipping software. They are only
+ * captured in memory when debug logging is enabled through a
+ * configuration change.
+ *
+ * @param FORMAT A constant string or format string that produces a human-readable log message. The format
+ * string follows the IEEE printf specification, besides the following customized format specifiers:
+ * %{mdnsresponder:domain_name}.*P the pointer to a DNS lable sequence
+ * %{mdnsresponder:ip_addr}.20P the pointer to a mDNSAddr variable
+ * %{network:in_addr}.4P the pointer to a mDNSv4Addr variable
+ * %{network:in6_addr}.16P the pointer to a mDNSv6Addr variable
+ * %{mdnsresponder:mac_addr}.6P the pointer to a 6-byte-length MAC address
+ *
+ * @param ... The parameter list that will be formated by the format string. Note that if the customized
+ * format specifiers are used and the data length is not specified in the format string, the
+ * size should be listed before the pointer to the data, for example:
+ * "%{mdnsresponder:domain_name}.*P", (name ? (int)DomainNameLength((const domainname *)name) : 0), <the pointer to a DNS label sequence>
+ *
+ */
+ #define LogRedact(CATEGORY, LEVEL, FORMAT, ...) os_log_with_type(CATEGORY, LEVEL, FORMAT, ## __VA_ARGS__)
+#else
+ #if (MDNS_HAS_VA_ARG_MACROS)
+ #if (MDNS_C99_VA_ARGS)
+ #define LogRedact(CATEGORY, LEVEL, ...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(CATEGORY, LEVEL, __VA_ARGS__); } while (0)
+ #elif (MDNS_GNU_VA_ARGS)
+ #define LogRedact(CATEGORY, LEVEL, ARGS...) \
+ do { if (mDNS_LoggingEnabled) LogMsgWithLevel(CATEGORY, LEVEL, ARGS); } while (0)
+ #else
+ #error "Unknown variadic macros"
+ #endif
+ #else
+ #define LogRedact (mDNS_LoggingEnabled == 0) ? ((void)0) : LogRedact_
+ extern void LogRedact_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+ #endif
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+
+// The followings are the customized log specifier defined in os_log. For compatibility, we have to define it when it is
+// not on the Apple platform, for example, the Posix platform. The keyword "public" or "private" is used to control whether
+// the content would be redacted when the redaction is turned on: "public" means the content will always be printed;
+// "private" means the content will be printed as <private> if the redaction is turned on, only when the redaction is
+// turned off, the content will be printed as what it should be.
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_S "%{public}s"
+ #define PRI_S "%{private}s"
+#else
+ #define PUB_S "%s"
+ #define PRI_S PUB_S
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_DM_NAME "%{public, mdnsresponder:domain_name}.*P"
+ #define PRI_DM_NAME "%{private, mdnsresponder:domain_name}.*P"
+ // When DM_NAME_PARAM is used, the file where the function is defined must include DNSEmbeddedAPI.h
+ #define DM_NAME_PARAM(name) ((name) ? ((int)DomainNameLength((const domainname *)(name))) : 0), (name)
+#else
+ #define PUB_DM_NAME "%##s"
+ #define PRI_DM_NAME PUB_DM_NAME
+ #define DM_NAME_PARAM(name) (name)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_IP_ADDR "%{public, mdnsresponder:ip_addr}.20P"
+ #define PRI_IP_ADDR "%{private, mdnsresponder:ip_addr}.20P"
+
+ #define PUB_IPv4_ADDR "%{public, network:in_addr}.4P"
+ #define PRI_IPv4_ADDR "%{private, network:in_addr}.4P"
+
+ #define PUB_IPv6_ADDR "%{public, network:in6_addr}.16P"
+ #define PRI_IPv6_ADDR "%{private, network:in6_addr}.16P"
+#else
+ #define PUB_IP_ADDR "%#a"
+ #define PRI_IP_ADDR PUB_IP_ADDR
+
+ #define PUB_IPv4_ADDR "%.4a"
+ #define PRI_IPv4_ADDR PUB_IPv4_ADDR
+
+ #define PUB_IPv6_ADDR "%.16a"
+ #define PRI_IPv6_ADDR PUB_IPv6_ADDR
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ #define PUB_MAC_ADDR "%{public, mdnsresponder:mac_addr}.6P"
+ #define PRI_MAC_ADDR "%{private, mdnsresponder:mac_addr}.6P"
+#else
+ #define PUB_MAC_ADDR "%.6a"
+ #define PRI_MAC_ADDR PUB_MAC_ADDR
#endif
+
+extern void LogToFD(int fd, const char *format, ...);
+
+#endif // __mDNSDebug_h
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
#include <stdarg.h> // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
#endif
-#include "mDNSDebug.h"
#if APPLE_OSX_mDNSResponder
#include <uuid/uuid.h>
-#include <TargetConditionals.h>
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "mDNSFeatures.h"
// ***************************************************************************
// Feature removal compile options & limited resource targets
// memory footprint for use in embedded systems with limited resources.
// UNICAST_DISABLED - disables unicast DNS functionality, including Wide Area Bonjour
-// ANONYMOUS_DISABLED - disables anonymous functionality
// DNSSEC_DISABLED - disables DNSSEC functionality
// SPC_DISABLED - disables Bonjour Sleep Proxy client
// IDLESLEEPCONTROL_DISABLED - disables sleep control for Bonjour Sleep Proxy clients
// In order to disable the above features pass the option to your compiler, e.g. -D UNICAST_DISABLED
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
+#endif
+
// Additionally, the LIMITED_RESOURCES_TARGET compile option will reduce the maximum DNS message sizes.
#ifdef LIMITED_RESOURCES_TARGET
#define MaximumRDSize 264
#endif
-#if !defined(MDNSRESPONDER_BTMM_SUPPORT)
-#define MDNSRESPONDER_BTMM_SUPPORT 0
+#ifdef __cplusplus
+extern "C" {
#endif
// ***************************************************************************
#endif
#endif
+#ifndef fallthrough
+ #if __clang__
+ #if __has_c_attribute(fallthrough)
+ #define fallthrough() [[fallthrough]]
+ #else
+ #define fallthrough()
+ #endif
+ #elif __GNUC__
+ #define fallthrough() __attribute__((fallthrough))
+ #else
+ #define fallthrough()
+ #endif // __GNUC__
+#endif // fallthrough
+
// ***************************************************************************
#if 0
#pragma mark - DNS Resource Record class and type constants
typedef unsigned int mDNSu32;
#endif
+#include "mDNSDebug.h"
+
// To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
// This way, mDNSInterfaceIDs can be assigned, and compared with each other, but not with other types
// Declaring the type to be the typical generic "void *" would lack this type checking
-typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+typedef const struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+
+// Use when printing interface IDs; the interface ID is actually a pointer, but we're only using
+// the pointer as a unique identifier, and in special cases it's actually a small number. So there's
+// little point in printing all 64 bits--the upper 32 bits in particular will not add information.
+#define IIDPrintable(x) ((uint32_t)(uintptr_t)(x))
// These types are for opaque two- and four-byte identifiers.
// The "NotAnInteger" fields of the unions allow the value to be conveniently passed around in a
mStatus_NoRouter = -65566,
mStatus_PollingMode = -65567,
mStatus_Timeout = -65568,
- mStatus_HostUnreachErr = -65569,
- // -65570 to -65786 currently unused; available for allocation
+ mStatus_DefunctConnection = -65569,
+ // -65570 to -65785 currently unused; available for allocation
+
+ // udp connection status
+ mStatus_HostUnreachErr = -65786,
// tcp connection status
mStatus_ConnPending = -65787,
#define kStandardTTL (3600UL * 100 / 80)
#define kHostNameTTL 120UL
-// Some applications want to register their SRV records with a lower ttl so that in case the server
-// using a dynamic port number restarts, the clients will not have stale information for more than
-// 10 seconds
-
-#define kHostNameSmallTTL 10UL
-
-
// Multicast DNS uses announcements (gratuitous responses) to update peer caches.
// This means it is feasible to use relatively larger TTL values than we might otherwise
// use, because we have a cache coherency protocol to keep the peer caches up to date.
// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
// The actual definition of these structures appear in the appropriate platform support code
+typedef struct TCPListener_struct TCPListener;
typedef struct TCPSocket_struct TCPSocket;
typedef struct UDPSocket_struct UDPSocket;
// hashLength, nxt, bitmap
} rdataNSEC3;
-// In the multicast usage of NSEC3, we know the actual size of RData
-// 4 bytes : HashAlg, Flags,Iterations
-// 5 bytes : Salt Length 1 byte, Salt 4 bytes
-// 21 bytes : HashLength 1 byte, Hash 20 bytes
-// 34 bytes : Window number, Bitmap length, Type bit map to include the first 256 types
-#define MCAST_NSEC3_RDLENGTH (4 + 5 + 21 + 34)
-#define SHA1_HASH_LENGTH 20
-
-// Base32 encoding takes 5 bytes of the input and encodes as 8 bytes of output.
-// For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32
-// bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5
-// is the max hash length possible.
-#define NSEC3_MAX_HASH_LEN 155
-// In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label
-// size.
-#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL
-
// We define it here instead of dnssec.h so that these values can be used
// in files without bringing in all of dnssec.h unnecessarily.
typedef enum
#pragma mark - DNSServer & McastResolver structures and constants
#endif
-enum
-{
- DNSServer_FlagDelete = 0x1,
- DNSServer_FlagNew = 0x2,
-#if APPLE_OSX_mDNSResponder
- DNSServer_FlagUnreachable = 0x4,
-#endif
-};
-
enum
{
McastResolver_FlagDelete = 1,
// have a matching serviceID
} ScopeType;
+typedef mDNSu32 DNSServerFlags;
+#define DNSServerFlag_Delete (1U << 0)
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#define DNSServerFlag_Unreachable (1U << 1)
+#endif
+
// Note: DNSSECAware is set if we are able to get a valid response to
// a DNSSEC question. In some cases it is possible that the proxy
// strips the EDNS0 option and we just get a plain response with no
{
struct DNSServer *next;
mDNSInterfaceID interface; // DNS requests should be sent on this interface
- mDNSs32 serviceID;
- mDNSAddr addr;
- mDNSIPPort port;
- mDNSu32 flags; // Set when we're planning to delete this from the list
- domainname domain; // name->server matching for "split dns"
+ mDNSs32 serviceID; // ServiceID from DNS configuration.
+ mDNSAddr addr; // DNS server's IP address.
+ DNSServerFlags flags; // Set when we're planning to delete this from the list.
mDNSs32 penaltyTime; // amount of time this server is penalized
ScopeType scopeType; // See the ScopeType enum above
mDNSu32 timeout; // timeout value for questions
mDNSu32 resGroupID; // ID of the resolver group that contains this DNSServer
- mDNSu8 retransDO; // Total Retransmissions for queries sent with DO option
- mDNSBool isCell; // Resolver from Cellular Interface?
- mDNSBool req_A; // If set, send v4 query (DNSConfig allows A queries)
- mDNSBool req_AAAA; // If set, send v6 query (DNSConfig allows AAAA queries)
+ mDNSIPPort port; // DNS server's port number.
+ mDNSBool usableA; // True if A query results are usable over the interface, i.e., interface has IPv4.
+ mDNSBool usableAAAA; // True if AAAA query results are usable over the interface, i.e., interface has IPv6.
+ mDNSBool isCell; // True if the interface to this server is cellular.
+ mDNSBool isExpensive; // True if the interface to this server is expensive.
+ mDNSBool isConstrained; // True if the interface to this server is constrained.
+ mDNSBool isCLAT46; // True if the interface to this server supports CLAT46.
mDNSBool req_DO; // If set, okay to send DNSSEC queries (EDNS DO bit is supported)
mDNSBool DNSSECAware; // Set if we are able to receive a response to a request sent with DO option.
- mDNSBool isExpensive; // True if the interface to this server is expensive.
- mDNSBool isCLAT46; // True if the interface to this server is CLAT46.
+ mDNSu8 retransDO; // Total Retransmissions for queries sent with DO option
+ domainname domain; // name->server matching for "split dns"
} DNSServer;
-typedef struct
-{
- mDNSu8 *AnonData;
- int AnonDataLen;
- mDNSu32 salt;
- ResourceRecord *nsec3RR;
- mDNSInterfaceID SendNow; // The interface ID that this record should be sent on
-} AnonymousInfo;
+#define kNegativeRecordType_Unspecified 0 // Initializer of ResourceRecord didn't specify why the record is negative.
+#define kNegativeRecordType_NoData 1 // The record's name exists, but there are no records of this type.
struct ResourceRecord_struct
{
mDNSu8 RecordType; // See kDNSRecordTypes enum.
+ mDNSu8 negativeRecordType; // If RecordType is kDNSRecordTypePacketNegative, specifies type of negative record.
MortalityState mortality; // Mortality of this resource record (See MortalityState enum)
mDNSu16 rrtype; // See DNS_TypeValues enum.
mDNSu16 rrclass; // See DNS_ClassValues enum.
const domainname *name;
RData *rdata; // Pointer to storage for this rdata
DNSServer *rDNSServer; // Unicast DNS server authoritative for this entry; null for multicast
- AnonymousInfo *AnonInfo; // Anonymous Information
};
AuthRecordAnyIncludeAWDL, // registered for *Any, including AWDL interface
AuthRecordAnyIncludeAWDLandP2P, // registered for *Any, including AWDL and P2P interfaces
AuthRecordLocalOnly,
- AuthRecordP2P // discovered over D2D/P2P framework
+ AuthRecordP2P, // discovered over D2D/P2P framework
} AuthRecType;
+#define AuthRecordIncludesAWDL(AR) \
+ (((AR)->ARType == AuthRecordAnyIncludeAWDL) || ((AR)->ARType == AuthRecordAnyIncludeAWDLandP2P))
+
typedef enum
{
AuthFlagsWakeOnly = 0x1 // WakeOnly service
mDNSs32 KATimeExpire; // In platform time units: time to send keepalive packet for the proxy record
// Field Group 3: Transient state for Authoritative Records
+ mDNSs32 ProbingConflictCount; // Number of conflicting records observed during probing.
+ mDNSs32 LastConflictPktNum; // Number of the last received packet that caused a probing conflict.
mDNSu8 Acknowledged; // Set if we've given the success callback to the client
mDNSu8 ProbeRestartCount; // Number of times we have restarted probing
mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
// Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID.
// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
#define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
-#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \
+#define Question_uDNS(Q) ((Q)->IsUnicastDotLocal || (Q)->ProxyQuestion || \
((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && (Q)->InterfaceID != mDNSInterface_BLE && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
// AuthRecordLocalOnly records are registered using mDNSInterface_LocalOnly and
// All other auth records, not including those defined as RRLocalOnly().
#define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P || (rr)->ARType == AuthRecordAnyIncludeAWDL || (rr)->ARType == AuthRecordAnyIncludeAWDLandP2P)
-// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
-// is not available locally for A or AAAA question respectively. Also, if the
-// query is disallowed for the "pid" that we are sending on behalf of, suppress it.
-#define QuerySuppressed(Q) (((Q)->SuppressUnusable && (Q)->SuppressQuery) || ((Q)->DisallowPID))
-
-#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
-
// Normally we always lookup the cache and /etc/hosts before sending the query on the wire. For single label
// queries (A and AAAA) that are unqualified (indicated by AppendSearchDomains), we want to append search
// domains before we try them as such
ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration
mDNSu32 NumSubTypes;
AuthRecord *SubTypes;
- const mDNSu8 *AnonData;
mDNSu32 flags; // saved for subsequent calls to mDNS_RegisterService() if records
// need to be re-registered.
AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
typedef enum
{
- LLQ_InitialRequest = 1,
- LLQ_SecondaryRequest = 2,
- LLQ_Established = 3,
- LLQ_Poll = 4
+ // This is the initial state.
+ LLQ_Init = 1,
+
+ // All of these states indicate that we are doing DNS Push, and haven't given up yet.
+ LLQ_DNSPush_ServerDiscovery = 100,
+ LLQ_DNSPush_Connecting = 101,
+ LLQ_DNSPush_Established = 102,
+
+ // All of these states indicate that we are doing LLQ and haven't given up yet.
+ LLQ_InitialRequest = 200,
+ LLQ_SecondaryRequest = 201,
+ LLQ_Established = 202,
+
+ // If we get here, it means DNS Push isn't available, so we're polling.
+ LLQ_Poll = 300
} LLQ_State;
// LLQ constants
enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
-// DNS Push Notification
-typedef enum
-{
- DNSPUSH_NOERROR = 0,
- DNSPUSH_FORMERR = 1,
- DNSPUSH_SERVFAIL = 2,
- DNSPUSH_NOTIMP = 4,
- DNSPUSH_REFUSED = 5
-} DNSPUSH_ErrorCode;
-
typedef enum {
- DNSPUSH_INIT = 1,
- DNSPUSH_NOSERVER = 2,
- DNSPUSH_SERVERFOUND = 3,
- DNSPUSH_ESTABLISHED = 4
-} DNSPush_State;
-
+ DNSPushServerDisconnected,
+ DNSPushServerConnectFailed,
+ DNSPushServerConnectionInProgress,
+ DNSPushServerConnected,
+ DNSPushServerSessionEstablished,
+ DNSPushServerNoDNSPush
+} DNSPushServer_ConnectState;
+
enum {
AllowExpired_None = 0, // Don't allow expired answers or mark answers immortal (behave normally)
AllowExpired_MakeAnswersImmortal = 1, // Any answers to this question get marked as immortal
#define HMAC_OPAD 0x5c
#define MD5_LEN 16
-#define AutoTunnelUnregistered(X) ( \
- (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered && \
- (X)->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered )
-
// Internal data structure to maintain authentication information
typedef struct DomainAuthInfo
{
struct DomainAuthInfo *next;
mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted
- mDNSBool AutoTunnel; // Whether this is AutoTunnel
- AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services
- AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
- AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
- AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
- AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from awacsd
- mDNSBool AutoTunnelServiceStarted; // Whether a service has been registered in this domain
- mDNSv6Addr AutoTunnelInnerAddress;
domainname domain;
domainname keyname;
domainname hostname;
// addition to not entering in the cache, it also forces the negative response through.
typedef enum { QC_rmv = 0, QC_add, QC_addnocache, QC_forceresponse, QC_dnssec , QC_nodnssec, QC_suppressed } QC_result;
typedef void mDNSQuestionCallback (mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+typedef void (*mDNSQuestionResetHandler)(DNSQuestion *question);
typedef void AsyncDispatchFunc(mDNS *const m, void *context);
typedef void DNSSECAuthInfoFreeCallback(mDNS *const m, void *context);
extern void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func);
// RFC 4122 defines it to be 16 bytes
#define UUID_SIZE 16
-#define AWD_METRICS (USE_AWD && TARGET_OS_IOS)
-
-#if AWD_METRICS
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
enum
{
ExpiredAnswer_None = 0, // No expired answers used
ExpiredAnswer_Allowed = 1, // An expired answer is allowed by this request
- ExpiredAnswer_AnsweredWithExpired = 2, // Question was answered with an expired answer
- ExpiredAnswer_ExpiredAnswerChanged = 3, // Expired answer changed on refresh
+ ExpiredAnswer_AnsweredWithCache = 2, // Question was answered with a cached answer
+ ExpiredAnswer_AnsweredWithExpired = 3, // Question was answered with an expired answer
+ ExpiredAnswer_ExpiredAnswerChanged = 4, // Expired answer changed on refresh
ExpiredAnswer_EnumCount
};
typedef mDNSu8 ExpiredAnswerMetric;
+enum
+{
+ DNSOverTCP_None = 0, // DNS Over TCP not used
+ DNSOverTCP_Truncated = 1, // DNS Over TCP used because UDP reply was truncated
+ DNSOverTCP_Suspicious = 2, // DNS Over TCP used because we received a suspicious reply
+ DNSOverTCP_SuspiciousDefense = 3, // DNS Over TCP used because we were within the timeframe of a previous suspicious response
+
+ DNSOverTCP_EnumCount
+};
+typedef mDNSu8 DNSOverTCPMetric;
+
typedef struct
{
domainname * originalQName; // Name of original A/AAAA record if this question is for a CNAME record.
mDNSs32 firstQueryTime; // The time when the first query was sent to a DNS server.
mDNSBool answered; // Has this question been answered?
ExpiredAnswerMetric expiredAnswerState; // Expired answer state (see ExpiredAnswerMetric above)
-
+ DNSOverTCPMetric dnsOverTCPState; // DNS Over TCP state (see DNSOverTCPMetric above)
+
} uDNSMetrics;
#endif
-// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
-#define USE_DNS64 (HAVE_DNS64 && TARGET_OS_IOS)
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
+extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device
+#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
#include "DNS64State.h"
#endif
-#if TARGET_OS_EMBEDDED
-extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
-extern mDNSu32 max_num_regservices; // tracks the max number of simultaneous services registered by the device
-#endif
+typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
+typedef struct mDNS_DNSPushNotificationZone DNSPushNotificationZone;
struct DNSQuestion_struct
{
DomainAuthInfo *AuthInfo; // Non-NULL if query is currently being done using Private DNS
DNSQuestion *DuplicateOf;
DNSQuestion *NextInDQList;
- AnonymousInfo *AnonInfo; // Anonymous Information
DupSuppressInfo DupSuppress[DupSuppressInfoSize];
mDNSInterfaceID SendQNow; // The interface this query is being sent on right now
mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces
mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done
- mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire
+ mDNSBool Suppressed; // This query should be suppressed, i.e., not sent on the wire.
mDNSu8 LOAddressAnswers; // Number of answers from the local only auth records that are
// answering A, AAAA, CNAME, or PTR (/etc/hosts)
mDNSu8 WakeOnResolveCount; // Number of wakes that should be sent on resolve
+ mDNSBool InitialCacheMiss; // True after the question cannot be answered from the cache
mDNSs32 StopTime; // Time this question should be stopped by giving them a negative answer
// DNSSEC fields
DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise)
mDNSOpaque128 validDNSServers; // Valid DNSServers for this question
mDNSu16 noServerResponse; // At least one server did not respond.
- mDNSu16 triedAllServersOnce; // Tried all DNS servers once
+ mDNSBool triedAllServersOnce; // True if all DNS servers have been tried once.
mDNSu8 unansweredQueries; // The number of unanswered queries to this server
AllowExpiredState allowExpired; // Allow expired answers state (see enum AllowExpired_None, etc. above)
mDNSIPPort tcpSrcPort; // Local Port TCP packet received on;need this as tcp struct is disposed
// by tcpCallback before calling into mDNSCoreReceive
mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed
- mDNSu8 Restart; // This question should be restarted soon
+ mDNSBool Restart; // This question should be restarted soon.
// LLQ-specific fields. These fields are only meaningful when LongLived flag is set
LLQ_State state;
// the number of packets sent for this TCP/TLS connection
// DNS Push Notification fields. These fields are only meaningful when LongLived flag is set
- DNSPush_State dnsPushState; // The state of the DNS push notification negotiation
- mDNSAddr dnsPushServerAddr; // Address of the system acting as the DNS Push Server
- mDNSIPPort dnsPushServerPort; // Port on which the DNS Push Server is being advertised.
+ DNSPushNotificationServer *dnsPushServer;
mDNSOpaque64 id;
// DNS Proxy fields
mDNSOpaque16 responseFlags; // Temporary place holder for the error we get back from the DNS server
// till we populate in the cache
- mDNSBool DisallowPID; // Is the query allowed for the "PID" that we are sending on behalf of ?
+ mDNSBool BlockedByPolicy; // True if the question is blocked by policy rule evaluation.
mDNSs32 ServiceID; // Service identifier to match against the DNS server
// Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface
mDNSu32 flags; // flags from original DNSService*() API request.
- 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
+ mDNSOpaque16 TargetQID; // DNS or mDNS message ID.
domainname qname;
domainname firstExpiredQname; // first expired qname in request chain
mDNSu16 qtype;
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
- mDNSu8 RetryWithSearchDomains; // Retry with search domains if there is no entry in the cache or AuthRecords
- mDNSu8 TimeoutQuestion; // Timeout this question if there is no reply in configured time
- mDNSu8 WakeOnResolve; // Send wakeup on resolve
- mDNSu8 UseBackgroundTrafficClass; // Set by client to use background traffic class for request
- mDNSs8 SearchListIndex; // Index into SearchList; Used by the client layer but not touched by core
- mDNSs8 AppendSearchDomains; // Search domains can be appended for this query
- mDNSs8 AppendLocalSearchDomains; // Search domains ending in .local can be appended for this query
+ mDNSBool TimeoutQuestion; // Timeout this question if there is no reply in configured time
+ mDNSBool IsUnicastDotLocal; // True if this is a dot-local query that should be answered via unicast DNS.
+ mDNSBool WakeOnResolve; // Send wakeup on resolve
+ mDNSBool UseBackgroundTraffic; // Set by client to use background traffic class for request
+ mDNSBool AppendSearchDomains; // Search domains can be appended for this query
mDNSu8 ValidationRequired; // Requires DNSSEC validation.
mDNSu8 ProxyQuestion; // Proxy Question
mDNSu8 ProxyDNSSECOK; // Proxy Question with EDNS0 DNSSEC OK bit set
mDNSs32 pid; // Process ID of the client that is requesting the question
mDNSu8 uuid[UUID_SIZE]; // Unique ID of the client that is requesting the question (valid only if pid is zero)
mDNSu32 euid; // Effective User Id of the client that is requesting the question
- domainname *qnameOrig; // Copy of the original question name if it is not fully qualified
+ mDNSu32 request_id; // The ID of request that generates the current question
mDNSQuestionCallback *QuestionCallback;
+ mDNSQuestionResetHandler ResetHandler;
void *QuestionContext;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
uDNSMetrics metrics; // Data used for collecting unicast DNS query metrics.
#endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
DNS64 dns64; // DNS64 state for performing IPv6 address synthesis on networks with NAT64.
#endif
};
// 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;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ AuthRecord RR_AddrRand; // For non-AWDL interfaces, this is the A or AAAA record of the randomized hostname.
+#endif
// 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
mDNSu32 WakeOnResolves; // Number of times we did a wake on resolve
} mDNSStatistics;
-extern void LogMDNSStatistics(mDNS *const m);
-
-typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
-typedef struct mDNS_DNSPushNotificationZone DNSPushNotificationZone;
-
-struct mDNS_DNSPushNotificationServer
-{
- mDNSAddr serverAddr; // Server Address
- tcpInfo_t *connection; // TCP Connection pointer
- mDNSu32 numberOfQuestions; // Number of questions for this server
- DNSPushNotificationServer *next;
-} ;
-
-struct mDNS_DNSPushNotificationZone
-{
- domainname zoneName;
- DNSPushNotificationServer *servers; // DNS Push Notification Servers for this zone
- mDNSu32 numberOfQuestions; // Number of questions for this zone
- DNSPushNotificationZone *next;
-} ;
-
+extern void LogMDNSStatisticsToFD(int fd, mDNS *const m);
// Time constant (~= 260 hours ~= 10 days and 21 hours) used to set
// various time values to a point well into the future.
mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets
mDNSs32 NextScheduledSPS; // Next time to purge expiring Sleep Proxy records
mDNSs32 NextScheduledKA; // Next time to send Keepalive packets (SPS)
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
mDNSs32 NextBonjourDisableTime; // Next time to leave multicast group if Bonjour on Demand is enabled
mDNSu8 BonjourEnabled; // Non zero if Bonjour is currently enabled by the Bonjour on Demand logic
-#endif // BONJOUR_ON_DEMAND
- mDNSs32 DelayConflictProcessing; // To prevent spurious confilcts due to stale packets on the wire/air.
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+ mDNSs32 NextSuspiciousTimeout; // Time until suspicious reply defense will timeout
+#endif
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
domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local."
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ domainname RandomizedHostname; // Randomized hostname to use for services involving AWDL interfaces. This is to
+ // avoid using a hostname derived from the device's name, which may contain the
+ // owner's real name, (e.g., "Steve's iPhone" -> "Steves-iPhone.local"), which is a
+ // privacy concern.
+ mDNSu32 AutoTargetAWDLIncludedCount;// Number of registered AWDL-included auto-target records.
+ mDNSu32 AutoTargetAWDLOnlyCount; // Number of registered AWDL-only auto-target records.
+#endif
UTF8str255 HIHardware;
UTF8str255 HISoftware;
AuthRecord DeviceInfo;
domainname StaticHostname; // Current answer to reverse-map query
domainname FQDN;
HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
- NATTraversalInfo AutoTunnelNAT; // Shared between all AutoTunnel DomainAuthInfo structs
- mDNSv6Addr AutoTunnelRelayAddr;
mDNSu32 WABBrowseQueriesCount; // Number of WAB Browse domain enumeration queries (b, db) callers
mDNSu32 WABLBrowseQueriesCount; // Number of legacy WAB Browse domain enumeration queries (lb) callers
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;
- void *WCF;
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ WCFConnection *WCF;
#endif
// DNS Proxy fields
mDNSu32 dp_ipintf[MaxIp]; // input interface index list from the DNS Proxy Client
int uds_listener_skt; // Listening socket for incoming UDS clients. This should not be here -- it's private to uds_daemon.c and nothing to do with mDNSCore -- SC
mDNSu32 AutoTargetServices; // # of services that have AutoTarget set
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
// Counters used in Bonjour on Demand logic.
mDNSu32 NumAllInterfaceRecords; // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.)
mDNSu32 NumAllInterfaceQuestions; // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately.
-#endif // BONJOUR_ON_DEMAND
+#endif
DNSSECStatistics DNSSECStats;
mDNSStatistics mDNSStats;
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
+
+ mDNSu32 next_request_id;
};
#define FORALL_CACHERECORDS(SLOT,CG,CR) \
extern const mDNSInterfaceID mDNSInterface_Any; // Zero
extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value
-extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value
extern const mDNSInterfaceID mDNSInterfaceMark; // Special value
extern const mDNSInterfaceID mDNSInterface_P2P; // Special value
extern const mDNSInterfaceID uDNSInterfaceMark; // Special value
extern const mDNSOpaque128 zeroOpaque128;
extern mDNSBool StrictUnicastOrdering;
-extern int NumUnicastDNSServers;
-#if APPLE_OSX_mDNSResponder
-extern mDNSu8 NumUnreachableDNSServers;
-#endif
#define localdomain (*(const domainname *)"\x5" "local")
#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
// If we're not doing inline functions, then this header needs to have the extern declarations
#if !defined(mDNSinline)
+extern int CountOfUnicastDNSServers(mDNS *const m);
extern mDNSs32 NonZeroTime(mDNSs32 t);
extern mDNSu16 mDNSVal16(mDNSOpaque16 x);
extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
#ifdef mDNSinline
+mDNSinline int CountOfUnicastDNSServers(mDNS *const m)
+{
+ int count = 0;
+ DNSServer *ptr = m->DNSServers;
+ while(ptr) { if(!(ptr->flags & DNSServerFlag_Delete)) count++; ptr = ptr->next; }
+ return (count);
+}
+
mDNSinline mDNSs32 NonZeroTime(mDNSs32 t) { if (t) return(t);else return(1);}
mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x) { return((mDNSu16)((mDNSu16)x.b[0] << 8 | (mDNSu16)x.b[1])); }
}
#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+#define SUSPICIOUS_REPLY_DEFENSE_SECS 10
+#endif
// ***************************************************************************
#if 0
extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context);
-extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
extern mStatus mDNS_RegisterService (mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, RData *txtrdata, const mDNSu8 txtinfo[], mDNSu16 txtlen,
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 mDNSu8 *anondata,
+ const domainname *const srv, const domainname *const domain,
const mDNSInterfaceID InterfaceID, mDNSu32 flags,
mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
mDNSQuestionCallback *Callback, void *Context);
// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
#define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \
if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0)
+#define AssignConstStringDomainName(DST, SRC) do { \
+ mDNSu16 len__ = DomainNameLengthLimit((domainname *)(SRC), (mDNSu8 *)(SRC) + sizeof (SRC)); \
+ if (len__ <= MAX_DOMAIN_NAME) \
+ mDNSPlatformMemCopy((DST)->c, (SRC), len__); else (DST)->c[0] = 0; } while(0)
// Comparison functions
#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
// not the number of characters that *would* have been printed were buflen unlimited.
extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) IS_A_PRINTF_STYLE_FUNCTION(3,0);
extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
+extern void mDNS_snprintf_add(char **dst, const char *lim, 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 *const rr, const RDataBody *const rd1, char *const buffer);
extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
extern mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr); // returns true for RFC1918 private addresses
#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4))
+extern const char *DNSScopeToString(mDNSu32 scope);
// For PCP
extern void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out);
// and the value is prepended to the IPSec identifier (used for key lookup)
extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
- const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel);
+ const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port);
extern void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
+ const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46,
mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags);
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
(M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \
} while (0)
-#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \
- do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0)
-
// verify a DNS message. The message must be complete, with all values in network byte order. end points to the
// end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is
// the matching key to use for verifying the message. This function expects that the additionals member
//
// mDNSPlatformUTC returns the time, in seconds, since Jan 1st 1970 UTC and is required for generating TSIG records
+#ifdef MDNS_MALLOC_DEBUGGING
+typedef void mDNSListValidationFunction(void *);
+typedef struct listValidator mDNSListValidator;
+struct listValidator {
+ struct listValidator *next;
+ const char *validationFunctionName;
+ mDNSListValidationFunction *validator;
+ void *context;
+};
+#endif // MDNS_MALLOC_DEBUGGING
+
extern mStatus mDNSPlatformInit (mDNS *const m);
extern void mDNSPlatformClose (mDNS *const m);
extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
extern void mDNSPlatformLock (const mDNS *const m);
extern void mDNSPlatformUnlock (const mDNS *const m);
-extern void mDNSPlatformStrCopy ( void *dst, const void *src);
extern mDNSu32 mDNSPlatformStrLCopy ( void *dst, const void *src, mDNSu32 len);
extern mDNSu32 mDNSPlatformStrLen ( const void *src);
extern void mDNSPlatformMemCopy ( void *dst, const void *src, mDNSu32 len);
extern int mDNSPlatformMemCmp (const void *dst, const void *src, mDNSu32 len);
extern void mDNSPlatformMemZero ( void *dst, mDNSu32 len);
extern void mDNSPlatformQsort (void *base, int nel, int width, int (*compar)(const void *, const void *));
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-#define mDNSPlatformMemAllocate(X) mallocL(# X, X)
+#if MDNS_MALLOC_DEBUGGING
+#define mDNSPlatformMemAllocate(X) mallocL(# X, X)
+#define mDNSPlatformMemAllocateClear(X) callocL(# X, X)
+#define mDNSPlatformMemFree(X) freeL(# X, X)
+extern void mDNSPlatformValidateLists (void);
+extern void mDNSPlatformAddListValidator(mDNSListValidator *validator,
+ mDNSListValidationFunction *vf, const char *vfName, void *context);
#else
-extern void * mDNSPlatformMemAllocate (mDNSu32 len);
+extern void * mDNSPlatformMemAllocate(mDNSu32 len);
extern void * mDNSPlatformMemAllocateClear(mDNSu32 len);
-#endif
-extern void mDNSPlatformMemFree (void *mem);
+extern void mDNSPlatformMemFree(void *mem);
+#endif // MDNS_MALLOC_DEBUGGING
// 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
} TCPSocketFlags;
typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
-extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+typedef void (*TCPAcceptedCallback)(TCPSocket *sock, mDNSAddr *addr, mDNSIPPort *port,
+ const char *remoteName, void *context);
+extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrtype, mDNSIPPort *port, domainname *hostname, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+extern TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+ TCPAcceptedCallback callback, void *context); // Listen on a port
+extern mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context);
extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
extern int mDNSPlatformTCPGetFD(TCPSocket *sock);
-extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
+extern mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock);
+extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context);
extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock);
extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
// in browse/registration calls must implement these routines to get the "default" browse/registration list.
extern mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
- DNameListElem **BrowseDomains, mDNSBool ackConfig);
+ DNameListElem **BrowseDomains, mDNSBool ackConfig);
extern mStatus mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
extern void mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
extern mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID);
-extern mDNSBool mDNSPlatformInterfaceIsAWDL(const NetworkInterfaceInfo *intf);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+extern mDNSBool mDNSPlatformInterfaceIsAWDL(mDNSInterfaceID interfaceID);
+#endif
extern mDNSBool mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
extern mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf);
extern void mDNSPlatformFormatTime(unsigned long t, mDNSu8 *buf, int bufsize);
+// Platform event API
+
#ifdef _LEGACY_NAT_TRAVERSAL_
// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
extern void LNT_SendDiscoveryMsg(mDNS *m);
extern void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+extern CacheRecord *mDNSCheckCacheFlushRecords(mDNS *m, CacheRecord *CacheFlushRecords, mDNSBool id_is_zero, int numAnswers,
+ DNSQuestion *unicastQuestion, CacheRecord *NSECCachePtr, CacheRecord *NSECRecords,
+ mDNSu8 rcode);
extern void mDNSCoreRestartQueries(mDNS *const m);
extern void mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q);
extern void mDNSCoreRestartRegistration(mDNS *const m, AuthRecord *rr, int announceCount);
extern AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr);
extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
-extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
-// For now this AutoTunnel stuff is specific to Mac OS X.
-// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
#if APPLE_OSX_mDNSResponder
-extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
-extern void AddNewClientTunnel(DNSQuestion *const q);
-extern void StartServerTunnel(DomainAuthInfo *const info);
-extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
-extern void RemoveAutoTunnel6Record(mDNS *const m);
-extern mDNSBool RecordReadyForSleep(AuthRecord *rr);
// For now this LocalSleepProxy stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
extern mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly);
-extern void mDNSPlatformUpdateDNSStatus(DNSQuestion *q);
-extern void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q);
-extern void mDNSPlatformLogToFile(int log_level, const char *buffer);
extern mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf);
-extern mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAddr *addr);
-extern mStatus SymptomReporterDNSServerUnreachable(DNSServer *s);
#endif
typedef void ProxyCallback (void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
extern mDNSs32 mDNSPlatformGetPID(void);
extern mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr);
extern mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+extern void GetRandomUUIDLabel(domainlabel *label);
+extern void GetRandomUUIDLocalHostname(domainname *hostname);
+#endif
// ***************************************************************************
#if 0
mDNSu32 A,B,C,D;
mDNSu32 Nl,Nh;
mDNSu32 data[MD5_BLOCK_LONG];
- int num;
+ mDNSu32 num;
} MD5_CTX;
extern int MD5_Init(MD5_CTX *c);
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_RDataBody [(sizeof(RDataBody) == 264) ? 1 : -1];
char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 72) ? 1 : -1];
- char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
+ char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1168) ? 1 : -1];
char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 232) ? 1 : -1];
char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 232) ? 1 : -1];
- char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1168) ? 1 : -1];
+ char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 1128) ? 1 : -1];
char sizecheck_ZoneData [(sizeof(ZoneData) <= 2000) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 200) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
- char sizecheck_DNSServer [(sizeof(DNSServer) <= 330) ? 1 : -1];
- char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 8400) ? 1 : -1];
- char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5540) ? 1 : -1];
- char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7888) ? 1 : -1];
+ char sizecheck_DNSServer [(sizeof(DNSServer) <= 328) ? 1 : -1];
+ char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 8240) ? 1 : -1];
+ char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 4728) ? 1 : -1];
+ char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 944) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1512) ? 1 : -1];
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ // structure size is assumed by LogRedact routine.
+ char sizecheck_mDNSAddr [(sizeof(mDNSAddr) == 20) ? 1 : -1];
+ char sizecheck_mDNSv4Addr [(sizeof(mDNSv4Addr) == 4) ? 1 : -1];
+ char sizecheck_mDNSv6Addr [(sizeof(mDNSv6Addr) == 16) ? 1 : -1];
+#endif
};
// Routine to initialize device-info TXT record contents
mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr);
-#if APPLE_OSX_mDNSResponder
-extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface);
-extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface);
-extern void D2D_start_advertising_record(AuthRecord *ar);
-extern void D2D_stop_advertising_record(AuthRecord *ar);
-#else
-#define D2D_start_advertising_interface(X)
-#define D2D_stop_advertising_interface(X)
-#define D2D_start_advertising_record(X)
-#define D2D_stop_advertising_record(X)
-#endif
-
// ***************************************************************************
#ifdef __cplusplus
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2019 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.
return mDNSNULL;
}
for (cr = cg->members; cr; cr = cr->next)
- if (SameNameRecordAnswersQuestion(&cr->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
return cr;
return mDNSNULL;
}
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2018 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.
#include "nsec3.h"
#include "nsec.h"
+// Base32 encoding takes 5 bytes of the input and encodes as 8 bytes of output.
+// For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32
+// bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5
+// is the max hash length possible.
+#define NSEC3_MAX_HASH_LEN 155
+// In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label
+// size.
+#define NSEC3_MAX_B32_LEN MAX_DOMAIN_LABEL
+
// Define DNSSEC_DISABLED to remove all the DNSSEC functionality
// and use the stub functions implemented later in this file.
return mDNSfalse;
}
+mDNSlocal const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen)
+{
+ AlgContext *ctx;
+ unsigned int i;
+ unsigned int iterations;
+ domainname lname;
+ mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
+ const mDNSu8 *digest;
+ int digestlen;
+ mDNSBool first = mDNStrue;
+
+ if (DNSNameToLowerCase((domainname *)name, &lname) != mStatus_NoError)
+ {
+ LogMsg("NSEC3HashName: ERROR!! DNSNameToLowerCase failed");
+ return mDNSNULL;
+ }
+
+ digest = lname.c;
+ digestlen = DomainNameLength(&lname);
+
+ // Note that it is "i <=". The first iteration is for digesting the name and salt.
+ // The iteration count does not include that.
+ iterations = swap16(nsec3->iterations);
+ for (i = 0; i <= iterations; i++)
+ {
+ ctx = AlgCreate(DIGEST_ALG, nsec3->alg);
+ if (!ctx)
+ {
+ LogMsg("NSEC3HashName: ERROR!! Cannot allocate context");
+ return mDNSNULL;
+ }
+
+ AlgAdd(ctx, digest, digestlen);
+ if (nsec3->saltLength)
+ AlgAdd(ctx, p, nsec3->saltLength);
+ if (first)
+ {
+ first = mDNSfalse;
+ digest = hash;
+ digestlen = AlgLength(ctx);
+ }
+ AlgFinal(ctx, (void *)digest, digestlen);
+ AlgDestroy(ctx);
+ }
+ *dlen = digestlen;
+ return digest;
+}
+
// This function can be called with NSEC3ClosestEncloser, NSEC3Covers and NSEC3CEProof
//
// Passing in NSEC3ClosestEncloser means "find an exact match for the origName".
int b32len;
name = SkipLeadingLabels(origName, i);
- if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
+ if (!NSEC3HashName(name, nsec3, hashName, &hlen))
{
LogMsg("NSEC3Find: NSEC3HashName failed for %##s", name->c);
continue;
nsec3 = (rdataNSEC3 *)rdb->data;
- if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
+ if (!NSEC3HashName(name, nsec3, hashName, &hlen))
{
LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for %##s", name->c);
return mDNSNULL;
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2017 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
* Any dynamic run-time requirements should be handled by the platform layer below or client layer above
*/
-#if APPLE_OSX_mDNSResponder
-#include <TargetConditionals.h>
-#endif
#include "uDNS.h"
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
#include "Metrics.h"
#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#include "SymptomReporter.h"
+#endif
+
#if (defined(_MSC_VER))
// Disable "assignment within conditional expression".
// Other compilers understand the convention that if you place the assignment expression within an extra pair
// The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
mDNSBool StrictUnicastOrdering = mDNSfalse;
+extern mDNS mDNSStorage;
+
// We keep track of the number of unicast DNS servers and log a message when we exceed 64.
// Currently the unicast queries maintain a 128 bit map to track the valid DNS servers for that
// question. Bit position is the index into the DNS server list. This is done so to try all
// the servers exactly once before giving up. If we could allocate memory in the core, then
// arbitrary limitation of 128 DNSServers can be removed.
-int NumUnicastDNSServers = 0;
#define MAX_UNICAST_DNS_SERVERS 128
-#if APPLE_OSX_mDNSResponder
-mDNSu8 NumUnreachableDNSServers = 0;
-#endif
#define SetNextuDNSEvent(m, rr) { \
if ((m)->NextuDNSEvent - ((rr)->LastAPTime + (rr)->ThisAPInterval) >= 0) \
#pragma mark - Name Server List Management
#endif
-#define TrueFalseStr(X) ((X) ? "true" : "false")
-
-mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isCLAT46,
- mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *domain, const mDNSInterfaceID interface,
+ const mDNSs32 serviceID, const mDNSAddr *addr, const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout,
+ mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46, mDNSu32 resGroupID,
+ mDNSBool usableA, mDNSBool usableAAAA, mDNSBool reqDO)
{
DNSServer **p;
DNSServer *server;
-
- if ((NumUnicastDNSServers + 1) > MAX_UNICAST_DNS_SERVERS)
+ int dnsCount = CountOfUnicastDNSServers(m);
+ if (dnsCount >= MAX_UNICAST_DNS_SERVERS)
{
- LogMsg("mDNS_AddDNSServer: DNS server limit of %d reached, not adding this server", MAX_UNICAST_DNS_SERVERS);
+ LogMsg("mDNS_AddDNSServer: DNS server count of %d reached, not adding this server", dnsCount);
return mDNSNULL;
}
- if (!d)
- d = (const domainname *)"";
+ if (!domain) domain = (const domainname *)"";
- LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scopeType %d, resGroupID %d req_A %s, req_AAAA %s, cell %s, expensive %s, CLAT46 %s, req_DO %s",
- NumUnicastDNSServers, addr, d->c, interface, serviceID, (int)scopeType, resGroupID,
- TrueFalseStr(reqA), TrueFalseStr(reqAAAA), TrueFalseStr(isCell), TrueFalseStr(isExpensive), TrueFalseStr(isCLAT46), TrueFalseStr(reqDO));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "mDNS_AddDNSServer(%d): Adding " PRI_IP_ADDR " for " PRI_DM_NAME " interface " PUB_S " (%p), serviceID %u, "
+ "scopeType %d, resGroupID %u" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S,
+ dnsCount + 1, addr, DM_NAME_PARAM(domain), InterfaceNameForID(&mDNSStorage, interface), interface, serviceID,
+ (int)scopeType, resGroupID,
+ usableA ? ", usableA" : "",
+ usableAAAA ? ", usableAAAA" : "",
+ isCell ? ", cell" : "",
+ isExpensive ? ", expensive" : "",
+ isConstrained ? ", constrained" : "",
+ isCLAT46 ? ", CLAT46" : "",
+ reqDO ? ", reqDO" : "");
mDNS_CheckLock(m);
+ // Scan our existing list to see if we already have a matching record for this DNS resolver
for (p = &m->DNSServers; (server = *p) != mDNSNULL; p = &server->next)
{
- if ((server->scopeType == scopeType) &&
- (server->interface == interface) &&
- (server->serviceID == serviceID) &&
- mDNSSameAddress(&server->addr, addr) &&
- mDNSSameIPPort(server->port, port) &&
- (server->timeout == timeout) &&
- (!!server->isCell == !!isCell) &&
- (!!server->isExpensive == !!isExpensive) &&
- (!!server->isCLAT46 == !!isCLAT46) &&
- (!!server->req_A == !!reqA) &&
- (!!server->req_AAAA == !!reqAAAA) &&
- (!!server->req_DO == !!reqDO) &&
- SameDomainName(&server->domain, d))
- {
- if (!(server->flags & DNSServer_FlagDelete))
- debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
- *p = server->next;
- server->next = mDNSNULL;
- break;
- }
+ if (server->interface != interface) continue;
+ if (server->serviceID != serviceID) continue;
+ if (!mDNSSameAddress(&server->addr, addr)) continue;
+ if (!mDNSSameIPPort(server->port, port)) continue;
+ if (!SameDomainName(&server->domain, domain)) continue;
+ if (server->scopeType != scopeType) continue;
+ if (server->timeout != timeout) continue;
+ if (!server->usableA != !usableA) continue;
+ if (!server->usableAAAA != !usableAAAA) continue;
+ if (!server->isCell != !isCell) continue;
+ if (!server->req_DO != !reqDO) continue;
+ if (!(server->flags & DNSServerFlag_Delete))
+ {
+ debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once",
+ addr, mDNSVal16(port), domain->c, interface);
+ }
+ // If we found a matching record, cut it from the list
+ // (and if we’re *not* resurrecting a record that was marked for deletion, it’s a duplicate,
+ // and the debugf message signifies that we’re collapsing duplicate entries into one)
+ *p = server->next;
+ server->next = mDNSNULL;
+ break;
}
+
+ // If we broke out because we found an existing matching record, advance our pointer to the end of the list
while (*p)
{
p = &(*p)->next;
}
- // NumUnicastDNSServers is the count of active DNS servers i.e., ones that are not marked
- // with DNSServer_FlagDelete. We should increment it:
- //
- // 1) When we add a new DNS server
- // 2) When we resurrect a old DNS server that is marked with DNSServer_FlagDelete
- //
- // Don't increment when we resurrect a DNS server that is not marked with DNSServer_FlagDelete.
- // We have already accounted for it when it was added for the first time. This case happens when
- // we add DNS servers with the same address multiple times (mis-configuration).
-
- if (!server || (server->flags & DNSServer_FlagDelete))
- NumUnicastDNSServers++;
-
if (server)
{
- if (server->flags & DNSServer_FlagDelete)
+ if (server->flags & DNSServerFlag_Delete)
{
-#if APPLE_OSX_mDNSResponder
- server->flags &= ~DNSServer_FlagUnreachable;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+ server->flags &= ~DNSServerFlag_Unreachable;
#endif
- server->flags &= ~DNSServer_FlagDelete;
+ server->flags &= ~DNSServerFlag_Delete;
}
- *p = server; // move to end of list, to ensure ordering from platform layer
+ server->isExpensive = isExpensive;
+ server->isConstrained = isConstrained;
+ server->isCLAT46 = isCLAT46;
+ *p = server; // Append resurrected record at end of list
}
else
{
- // allocate, add to list
- server = (DNSServer *)mDNSPlatformMemAllocateClear(sizeof(*server));
+ server = (DNSServer *) mDNSPlatformMemAllocateClear(sizeof(*server));
if (!server)
{
LogMsg("Error: mDNS_AddDNSServer - malloc");
}
else
{
- server->scopeType = scopeType;
- server->interface = interface;
- server->serviceID = serviceID;
- server->addr = *addr;
- server->port = port;
- server->flags = DNSServer_FlagNew;
- server->timeout = timeout;
- server->isCell = isCell;
- server->isExpensive = isExpensive;
- server->isCLAT46 = isCLAT46;
- server->req_A = reqA;
- server->req_AAAA = reqAAAA;
- server->req_DO = reqDO;
+ server->interface = interface;
+ server->serviceID = serviceID;
+ server->addr = *addr;
+ server->port = port;
+ server->scopeType = scopeType;
+ server->timeout = timeout;
+ server->usableA = usableA;
+ server->usableAAAA = usableAAAA;
+ server->isCell = isCell;
+ server->isExpensive = isExpensive;
+ server->isConstrained = isConstrained;
+ server->isCLAT46 = isCLAT46;
+ server->req_DO = reqDO;
// We start off assuming that the DNS server is not DNSSEC aware and
// when we receive the first response to a DNSSEC question, we set
// it to true.
server->DNSSECAware = mDNSfalse;
server->retransDO = 0;
- AssignDomainName(&server->domain, d);
- *p = server;
+ AssignDomainName(&server->domain, domain);
+ *p = server; // Append new record at end of list
}
}
- if (server) {
+ if (server)
+ {
server->penaltyTime = 0;
// We always update the ID (not just when we allocate a new instance) because we want
// all the resGroupIDs for a particular domain to match.
mDNS_CheckLock(m);
- LogInfo("PenalizeDNSServer: Penalizing DNS server %#a question for question %p %##s (%s) SuppressUnusable %d",
- (q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL), q, q->qname.c, DNSTypeName(q->qtype), q->SuppressUnusable);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Penalizing DNS server " PRI_IP_ADDR " question for question %p " PRI_DM_NAME " (" PUB_S ") SuppressUnusable %d",
+ (q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), q->SuppressUnusable);
// If we get error from any DNS server, remember the error. If all of the servers,
// return the error, then return the first error.
if (!StrictUnicastOrdering)
{
- LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Strict Unicast Ordering is FALSE");
// We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME
// XXX Include other logic here to see if this server should really be penalized
//
if (q->qtype == kDNSType_PTR)
{
- LogInfo("PenalizeDNSServer: Not Penalizing PTR question");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Not Penalizing PTR question");
}
else if ((rcode == kDNSFlag1_RC_FormErr) || (rcode == kDNSFlag1_RC_ServFail) || (rcode == kDNSFlag1_RC_NotImpl) || (rcode == kDNSFlag1_RC_Refused))
{
- LogInfo("PenalizeDNSServer: Not Penalizing DNS Server since it at least responded with rcode %d", rcode);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Not Penalizing DNS Server since it at least responded with rcode %d", rcode);
}
else
{
- LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Penalizing question type %d", q->qtype);
q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
}
}
else
{
- LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "PenalizeDNSServer: Strict Unicast Ordering is TRUE");
}
end:
{
if (new)
{
- LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server %#a:%d", &new->addr,
- mDNSVal16(new->port));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server " PRI_IP_ADDR ":%d",
+ &new->addr, mDNSVal16(new->port));
q->ThisQInterval = 0; // Inactivate this question so that we dont bombard the network
}
else
// is slow in responding and we have sent three queries. When we repeatedly call, it is
// okay to receive the same NULL DNS server. Next time we try to send the query, we will
// realize and re-initialize the DNS servers.
- LogInfo("PenalizeDNSServer: GetServerForQuestion returned the same server NULL");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: GetServerForQuestion returned the same server NULL");
}
}
else
if (new)
{
- LogInfo("PenalizeDNSServer: 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);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Server for " PRI_DM_NAME " (" PUB_S ") changed to " PRI_IP_ADDR ":%d (" PRI_DM_NAME ")",
+ DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), DM_NAME_PARAM(q->qDNSServer->domain.c));
// We want to try the next server immediately. As the question may already have backed off, reset
// the interval. We do this only the first time when we try all the DNS servers. Once we reached the end of
// list and retrying all the servers again e.g., at least one server failed to respond in the previous try, we
// the next query will not happen until cache expiry. If it is a long lived question,
// AnswerCurrentQuestionWithResourceRecord will not set it to MaxQuestionInterval. In that case,
// we want the normal backoff to work.
- LogInfo("PenalizeDNSServer: Server for %p, %##s (%s) changed to NULL, Interval %d", q, q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "PenalizeDNSServer: Server for %p, " PRI_DM_NAME " (" PUB_S ") changed to NULL, Interval %d",
+ q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), q->ThisQInterval);
}
q->unansweredQueries = 0;
// First purge any dead keys from the list
while (*p)
{
- if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
+ if ((*p)->deltime && m->timenow - (*p)->deltime >= 0)
{
DNSQuestion *q;
DomainAuthInfo *info = *p;
// MUST be called with the lock held
mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
- const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
+ const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
{
DNSQuestion *q;
DomainAuthInfo **p = &m->AuthInfoList;
if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
- LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, autoTunnel ? " AutoTunnel" : "");
+ LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s", domain->c, keyname->c);
- info->AutoTunnel = autoTunnel;
AssignDomainName(&info->domain, domain);
AssignDomainName(&info->keyname, keyname);
if (hostname)
while (*p && (*p) != info) p=&(*p)->next;
if (*p) {LogInfo("mDNS_SetSecretForDomain: Domain %##s Already in list", (*p)->domain.c); return(mStatus_AlreadyRegistered);}
- // Caution: Only zero AutoTunnelHostRecord.namestorage AFTER we've determined that this is a NEW DomainAuthInfo
- // being added to the list. Otherwise we risk smashing our AutoTunnel host records that are already active and in use.
- info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeUnregistered;
- info->AutoTunnelServiceStarted = mDNSfalse;
- info->AutoTunnelInnerAddress = zerov6Addr;
info->next = mDNSNULL;
*p = info;
// we risk causing spurious "SendQueries didn't send all its queries" log messages
q->LastQTime = m->timenow - q->ThisQInterval + 1;
SetNextQueryTime(m, q);
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
if (q->tcp) { LogMsg("sendChallengeResponse: ERROR!!: question %##s (%s) tcp non-NULL", q->qname.c, DNSTypeName(q->qtype)); return; }
- if (PrivateQuery(q)) { LogMsg("sendChallengeResponse: ERROR!!: Private Query %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-
if (q->ntries++ == kLLQ_MAX_TRIES)
{
LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
if (responsePtr)
{
- mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSfalse);
if (err) { LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); }
}
else StartLLQPolling(m,q);
}
else if (q->state == 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
- // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
- // if the server sends back SERVFULL or STATIC.
- if (PrivateQuery(q))
- {
- LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
- q->id = llq->id;
- }
-
if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q->qname.c, DNSTypeName(q->qtype), llq->err); StartLLQPolling(m,q); return; }
if (!mDNSSameOpaque64(&q->id, &llq->id))
{ LogMsg("recvSetupResponse - ID changed. discarding"); return; } // this can happen rarely (on packet loss + reordering)
q->state = LLQ_Established;
q->ntries = 0;
SetLLQTimer(m, q, llq);
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
}
//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, q, &opt->u.llq);
- if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+ if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, mDNSNULL, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSfalse);
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));
*matchQuestion = q;
}
// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
-struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
// tcpCallback is called to handle events (e.g. connection opening and data reception) on TCP connections for
// Private DNS operations -- private queries, private LLQs, private record updates and private service updates
AuthInfo = q->AuthInfo; // Need to add TSIG to this message
}
- err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo, mDNSfalse);
+ err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, sock, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, AuthInfo, mDNSfalse);
if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
if (mDNSSameIPPort(tcpInfo->Port, UnicastDNSPort))
{
MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&tcpInfo->request));
if (tcpInfo->replylen < sizeof(DNSMessageHeader))
{ LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
- tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
+ tcpInfo->reply = (DNSMessage *) mDNSPlatformMemAllocate(tcpInfo->replylen);
if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
}
tcpInfo_t *info;
mDNSBool useBackgroundTrafficClass;
- useBackgroundTrafficClass = question ? question->UseBackgroundTrafficClass : mDNSfalse;
+ useBackgroundTrafficClass = question ? question->UseBackgroundTraffic : mDNSfalse;
if ((flags & kTCPSocketFlags_UseTLS) && (!hostname || !hostname->c[0]))
{ LogMsg("MakeTCPConn: TLS connection being setup with NULL hostname"); return mDNSNULL; }
- info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
+ info = (tcpInfo_t *) mDNSPlatformMemAllocateClear(sizeof(*info));
if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
- mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
info->m = m;
- info->sock = mDNSPlatformTCPSocket(flags, &srcport, useBackgroundTrafficClass);
+ info->sock = mDNSPlatformTCPSocket(flags, Addr->type, &srcport, hostname, useBackgroundTrafficClass);
info->requestLen = 0;
info->question = question;
info->rr = rr;
if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
mDNSPlatformSetSocktOpt(info->sock, mDNSTransport_TCP, Addr->type, question);
- err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
+ err = mDNSPlatformTCPConnect(info->sock, Addr, Port, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
// Probably suboptimal here.
// Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
// Lock must be held
mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
{
+ // States prior to LLQ_InitialRequest should not react to NAT Mapping changes.
+ // startLLQHandshake is never called with q->state < LLQ_InitialRequest except
+ // from LLQNATCallback. When we are actually trying to do LLQ, then q->state will
+ // be equal to or greater than LLQ_InitialRequest when LLQNATCallback calls
+ // startLLQHandshake.
+ if (q->state < LLQ_InitialRequest)
+ {
+ return;
+ }
+
if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
{
LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
return;
}
- if (PrivateQuery(q))
+ 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));
+
+ if (q->ntries++ >= kLLQ_MAX_TRIES)
{
- 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 = mDNSNULL; }
- if (!q->nta)
- {
- // Normally we lookup the zone data and then call this function. And we never free the zone data
- // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
- // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
- // When we poll, we free the zone information as we send the query to the server (See
- // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
- // are still behind Double NAT, we would have returned early in this function. But we could
- // have switched to a network with no NATs and we should get the zone data again.
- LogInfo("startLLQHandshake: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
- return;
- }
- else if (!q->nta->Host.c[0])
- {
- // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
- LogMsg("startLLQHandshake: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
- }
- q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
- if (!q->tcp)
- q->ThisQInterval = mDNSPlatformOneSecond * 5; // If TCP failed (transient networking glitch) try again in five seconds
- else
- {
- q->state = LLQ_SecondaryRequest; // Right now, for private DNS, we skip the four-way LLQ handshake
- q->ReqLease = kLLQ_DefLease;
- q->ThisQInterval = 0;
- }
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
+ LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
+ StartLLQPolling(m, q);
}
else
{
- 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));
-
- if (q->ntries++ >= kLLQ_MAX_TRIES)
- {
- LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
- StartLLQPolling(m, q);
- }
- else
- {
- mDNSu8 *end;
- LLQOptData llqData;
+ mDNSu8 *end;
+ LLQOptData llqData;
- // set llq rdata
- llqData.vers = kLLQ_Vers;
- llqData.llqOp = kLLQOp_Setup;
- llqData.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
- llqData.id = zeroOpaque64;
- llqData.llqlease = kLLQ_DefLease;
+ // set llq rdata
+ llqData.vers = kLLQ_Vers;
+ llqData.llqOp = kLLQOp_Setup;
+ llqData.err = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
+ llqData.id = zeroOpaque64;
+ llqData.llqlease = kLLQ_DefLease;
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
- end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
- if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
+ InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+ 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, mDNSfalse);
+ mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort , mDNSNULL, mDNSfalse);
- // update question state
- q->state = LLQ_InitialRequest;
- q->ReqLease = kLLQ_DefLease;
- q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
- }
+ // update question state
+ q->state = LLQ_InitialRequest;
+ q->ReqLease = kLLQ_DefLease;
+ q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
}
}
return(&rr->resrec.rdata->u.srv.target);
else
{
-#if APPLE_OSX_mDNSResponder
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- if (AuthInfo && AuthInfo->AutoTunnel)
- {
- StartServerTunnel(AuthInfo);
- if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
- debugf("GetServiceTarget: Returning %##s", AuthInfo->AutoTunnelHostRecord.namestorage.c);
- return(&AuthInfo->AutoTunnelHostRecord.namestorage);
- }
- else
-#endif // APPLE_OSX_mDNSResponder
{
const int srvcount = CountLabels(rr->resrec.name);
HostnameInfo *besthi = mDNSNULL, *hi;
}
}
-mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
-mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
+mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE = (const domainname*)"\x0B_dns-update" "\x04_udp";
+mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE = (const domainname*)"\x08_dns-llq" "\x04_udp";
-mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
-mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
-mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
-mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0C_dns-push-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_UPDATE_SERVICE_TYPE = (const domainname*)"\x0F_dns-update-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_QUERY_SERVICE_TYPE = (const domainname*)"\x0E_dns-query-tls" "\x04_tcp";
+mDNSlocal const domainname *PRIVATE_LLQ_SERVICE_TYPE = (const domainname*)"\x0C_dns-llq-tls" "\x04_tcp";
+mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0D_dns-push-tls" "\x04_tcp";
#define ZoneDataSRV(X) ( \
(X)->ZoneService == ZoneServiceUpdate ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
{
AssignDomainName(&zd->ZoneName, answer->name);
zd->ZoneClass = answer->rrclass;
- AssignDomainName(&zd->question.qname, &zd->ZoneName);
GetZoneData_StartQuery(m, zd, kDNSType_SRV);
}
else if (zd->CurrentSOA->c[0])
{
- DomainAuthInfo *AuthInfo = GetAuthInfoForName(m, zd->CurrentSOA);
- if (AuthInfo && AuthInfo->AutoTunnel)
- {
- // To keep the load on the server down, we don't chop down on
- // SOA lookups for AutoTunnels
- LogInfo("GetZoneData_QuestionCallback: not chopping labels for %##s", zd->CurrentSOA->c);
- zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
- }
- else
- {
- zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
- AssignDomainName(&zd->question.qname, zd->CurrentSOA);
- GetZoneData_StartQuery(m, zd, kDNSType_SOA);
- }
+ zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
+ AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+ GetZoneData_StartQuery(m, zd, kDNSType_SOA);
}
else
{
{
AssignDomainName(&zd->Host, &answer->rdata->u.srv.target);
zd->Port = answer->rdata->u.srv.port;
- AssignDomainName(&zd->question.qname, &zd->Host);
- GetZoneData_StartQuery(m, zd, kDNSType_A);
+ // The MakeTCPConn path, which is used by everything but DNS Push, won't work at all for
+ // IPv6. This should be fixed for all cases we care about, but for now we make an exception
+ // for Push notifications: we do not look up the a record here, but rather rely on the DSO
+ // infrastructure to do a GetAddrInfo call on the name and try each IP address in sequence
+ // until one connects. We can't do this for the other use cases because this is in the DSO
+ // code, not in MakeTCPConn. Ultimately the fix for this is to use Network Framework to do
+ // the connection establishment for all of these use cases.
+ //
+ // One implication of this is that if two different zones have DNS push server SRV records
+ // pointing to the same server using a different domain name, we will not see these as being
+ // the same server, and will not share the connection. This isn't something we can easily
+ // fix, and so the advice if someone runs into this and considers it a problem should be to
+ // use the same name.
+ //
+ // Another issue with this code is that at present, we do not wait for more than one SRV
+ // record--we cancel the query as soon as the first one comes in. This isn't ideal: it
+ // would be better to wait until we've gotten all our answers and then pick the one with
+ // the highest priority. Of course, this is unlikely to cause an operational problem in
+ // practice, and as with the previous point, the fix is easy: figure out which server you
+ // want people to use and don't list any other servers. Fully switching to Network
+ // Framework for this would (I think!) address this problem, or at least make it someone
+ // else's problem.
+ if (zd->ZoneService != ZoneServiceDNSPush)
+ {
+ AssignDomainName(&zd->question.qname, &zd->Host);
+ GetZoneData_StartQuery(m, zd, kDNSType_A);
+ }
+ else
+ {
+ zd->ZoneDataCallback(m, mStatus_NoError, zd);
+ }
}
else
{
zd->question.ThisQInterval = -1;
zd->question.InterfaceID = mDNSInterface_Any;
zd->question.flags = 0;
- zd->question.Target = zeroAddr;
//zd->question.qname.c[0] = 0; // Already set
zd->question.qtype = qtype;
zd->question.qclass = kDNSClass_IN;
zd->question.ForceMCast = mDNSfalse;
zd->question.ReturnIntermed = mDNStrue;
zd->question.SuppressUnusable = mDNSfalse;
- zd->question.SearchListIndex = 0;
zd->question.AppendSearchDomains = 0;
- zd->question.RetryWithSearchDomains = mDNSfalse;
zd->question.TimeoutQuestion = 0;
zd->question.WakeOnResolve = 0;
- zd->question.UseBackgroundTrafficClass = mDNSfalse;
+ zd->question.UseBackgroundTraffic = mDNSfalse;
zd->question.ValidationRequired = 0;
zd->question.ValidatingResponse = 0;
zd->question.ProxyQuestion = 0;
- zd->question.qnameOrig = mDNSNULL;
- zd->question.AnonInfo = mDNSNULL;
zd->question.pid = mDNSPlatformGetPID();
zd->question.euid = 0;
zd->question.QuestionCallback = GetZoneData_QuestionCallback;
// StartGetZoneData is an internal routine (i.e. must be called with the lock already held)
mDNSexport ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *ZoneDataContext)
{
- DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, name);
- int initialskip = (AuthInfo && AuthInfo->AutoTunnel) ? DomainNameLength(name) - DomainNameLength(&AuthInfo->domain) : 0;
- ZoneData *zd = (ZoneData*)mDNSPlatformMemAllocate(sizeof(ZoneData));
- if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocate failed"); return mDNSNULL; }
- mDNSPlatformMemZero(zd, sizeof(ZoneData));
+ ZoneData *zd = (ZoneData*) mDNSPlatformMemAllocateClear(sizeof(*zd));
+ if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocateClear failed"); return mDNSNULL; }
AssignDomainName(&zd->ChildName, name);
zd->ZoneService = target;
- zd->CurrentSOA = (domainname *)(&zd->ChildName.c[initialskip]);
+ zd->CurrentSOA = &zd->ChildName;
zd->ZoneName.c[0] = 0;
zd->ZoneClass = 0;
zd->Host.c[0] = 0;
zd->Port = zeroIPPort;
zd->Addr = zeroAddr;
- zd->ZonePrivate = AuthInfo && AuthInfo->AutoTunnel ? mDNStrue : mDNSfalse;
+ zd->ZonePrivate = mDNSfalse;
zd->ZoneDataCallback = callback;
zd->ZoneDataContext = ZoneDataContext;
zd->question.QuestionContext = zd;
mDNS_DropLockBeforeCallback(); // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
- if (AuthInfo && AuthInfo->AutoTunnel && !mDNSIPPortIsZero(AuthInfo->port))
- {
- LogInfo("StartGetZoneData: Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
- // We bypass SOA and SRV queries if we know the hostname and port already from the configuration.
- // Today this is only true for AutoTunnel. As we bypass, we need to infer a few things:
- //
- // 1. Zone name is the same as the AuthInfo domain
- // 2. ZoneClass is kDNSClass_IN which should be a safe assumption
- //
- // If we want to make this bypass mechanism work for non-AutoTunnels also, (1) has to hold
- // good. Otherwise, it has to be configured also.
-
- AssignDomainName(&zd->ZoneName, &AuthInfo->domain);
- zd->ZoneClass = kDNSClass_IN;
- AssignDomainName(&zd->Host, &AuthInfo->hostname);
- zd->Port = AuthInfo->port;
- AssignDomainName(&zd->question.qname, &zd->Host);
- GetZoneData_StartQuery(m, zd, kDNSType_A);
- }
- else
- {
- if (AuthInfo && AuthInfo->AutoTunnel) LogInfo("StartGetZoneData: Not Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
- AssignDomainName(&zd->question.qname, zd->CurrentSOA);
- GetZoneData_StartQuery(m, zd, kDNSType_SOA);
- }
+ AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+ GetZoneData_StartQuery(m, zd, kDNSType_SOA);
mDNS_ReclaimLockAfterCallback();
return zd;
case regState_NATError:
if (!NATChanged) return;
+ fallthrough();
// if nat changed, register if we have a target (below)
case regState_NoTarget:
q->InterfaceID = mDNSInterface_Any;
q->flags = 0;
- q->Target = zeroAddr;
q->qtype = kDNSType_PTR;
q->qclass = kDNSClass_IN;
q->LongLived = mDNSfalse;
q->ForceMCast = mDNSfalse;
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
- q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
- q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = mDNSfalse;
+ q->UseBackgroundTraffic = mDNSfalse;
q->ValidationRequired = 0;
q->ValidatingResponse = 0;
q->ProxyQuestion = 0;
- q->qnameOrig = mDNSNULL;
- q->AnonInfo = mDNSNULL;
q->pid = mDNSPlatformGetPID();
q->euid = 0;
q->QuestionCallback = FoundStaticHostname;
if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
// allocate and format new address record
- *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+ *ptr = (HostnameInfo *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
if (!*ptr) { LogMsg("ERROR: mDNS_AddDynDNSHostName - malloc"); return; }
- mDNSPlatformMemZero(*ptr, sizeof(**ptr));
AssignDomainName(&(*ptr)->fqdn, fqdn);
(*ptr)->arv4.state = regState_Unregistered;
(*ptr)->arv6.state = regState_Unregistered;
m->StaticHostname.c[0] = 0;
m->NextSRVUpdate = NonZeroTime(m->timenow);
-
-#if APPLE_OSX_mDNSResponder
- UpdateAutoTunnelDomainStatuses(m);
-#endif
}
mDNS_Unlock(m);
}
}
-// We add three Additional Records for unicast resource record registrations
-// which is a function of AuthInfo and AutoTunnel properties
-mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo)
+mDNSlocal mDNSu32 RRAdditionalSize(DomainAuthInfo *AuthInfo)
{
- mDNSu32 leaseSize, hinfoSize, tsigSize;
+ mDNSu32 leaseSize, tsigSize;
mDNSu32 rr_base_size = 10; // type (2) class (2) TTL (4) rdlength (2)
// OPT RR : Emptyname(.) + base size + rdataOPT
leaseSize = 1 + rr_base_size + sizeof(rdataOPT);
- // HINFO: Resource Record Name + base size + RDATA
- // HINFO is added only for autotunnels
- hinfoSize = 0;
- if (AuthInfo && AuthInfo->AutoTunnel)
- hinfoSize = (m->hostlabel.c[0] + 1) + DomainNameLength(&AuthInfo->domain) +
- rr_base_size + (2 + m->HIHardware.c[0] + m->HISoftware.c[0]);
-
//TSIG: Resource Record Name + base size + RDATA
// RDATA:
// Algorithm name: hmac-md5.sig-alg.reg.int (8+7+3+3 + 5 bytes for length = 26 bytes)
tsigSize = 0;
if (AuthInfo) tsigSize = DomainNameLength(&AuthInfo->keyname) + rr_base_size + 58;
- return (leaseSize + hinfoSize + tsigSize);
+ return (leaseSize + tsigSize);
}
//Note: Make sure that RREstimatedSize is updated accordingly if anything that is done here
limit = ptr + AbsoluteMaxDNSMessageData;
AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- limit -= RRAdditionalSize(m, AuthInfo);
+ limit -= RRAdditionalSize(AuthInfo);
mDNS_CheckLock(m);
{
LogInfo("SendRecordRegistration UDP %s", ARDisplayString(m, rr));
if (!rr->nta) { LogMsg("SendRecordRegistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
- err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &rr->nta->Addr, rr->nta->Port, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
}
mDNSu8 *limit;
if (!anchorRR) {debugf("SendGroupRRMessage: Could not merge records"); return;}
- if (info && info->AutoTunnel) limit = m->omsg.data + AbsoluteMaxDNSMessageData;
- else limit = m->omsg.data + NormalMaxDNSMessageData;
+ limit = m->omsg.data + NormalMaxDNSMessageData;
// This has to go in the additional section and hence need to be done last
ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit);
}
else
{
- mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, mDNSNULL, info, mDNSfalse);
+ mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, info, mDNSfalse);
if (err) LogInfo("SendGroupRRMessage: Cannot send UDP message for %s", ARDisplayString(m, anchorRR));
else LogInfo("SendGroupRRMessage: Sent a group UDP update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit);
}
// Though we allow single record registrations for UDP to be AbsoluteMaxDNSMessageData (See
// SendRecordRegistration) to handle large TXT records, to avoid fragmentation we limit UDP
// message to NormalMaxDNSMessageData
- if (AuthInfo && AuthInfo->AutoTunnel) spaceleft = AbsoluteMaxDNSMessageData;
- else spaceleft = NormalMaxDNSMessageData;
+ spaceleft = NormalMaxDNSMessageData;
next = m->omsg.data;
- spaceleft -= RRAdditionalSize(m, AuthInfo);
+ spaceleft -= RRAdditionalSize(AuthInfo);
if (spaceleft <= 0)
{
LogMsg("SendGroupUpdates: ERROR!!: spaceleft is zero at the beginning");
LogInfo("hndlRecordUpdateReply: err %d ID %d state %d %s(%p)", err, mDNSVal16(rr->updateid), rr->state, ARDisplayString(m, rr), rr);
rr->updateError = err;
-#if APPLE_OSX_mDNSResponder
- if (err == mStatus_BadSig || err == mStatus_BadKey || err == mStatus_BadTime) UpdateAutoTunnelDomainStatuses(m);
-#endif
SetRecordRetry(m, rr, random);
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", end - msg->data);
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
if (NumUnreachableDNSServers > 0)
SymptomReporterDNSServerReachable(m, srcaddr);
#endif
if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
{
if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
- else uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport);
+ else
+ {
+ uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport);
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ qptr->metrics.dnsOverTCPState = DNSOverTCP_Truncated;
+#endif
+ }
}
}
{
mDNSu8 *end;
LLQOptData llq;
- mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData;
if (q->ReqLease)
if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
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,
- // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
- end = putHINFO(m, &m->omsg, end, q->AuthInfo, limit);
- if (!end) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-
- if (PrivateQuery(q))
- {
- DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo);
- if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
- }
-
- if (PrivateQuery(q) && !q->tcp)
- {
- LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- if (!q->nta)
- {
- // Note: If a question is in LLQ_Established state, we never free the zone data for the
- // question (PrivateQuery). If we free, we reset the state to something other than LLQ_Established.
- // This function is called only if the query is in LLQ_Established state and hence nta should
- // never be NULL. In spite of that, we have seen q->nta being NULL in the field. Just refetch the
- // zone data in that case.
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
- return;
- // ThisQInterval is not adjusted when we return from here which means that we will get called back
- // again immediately. As q->servAddr and q->servPort are still valid and the nta->Host is initialized
- // without any additional discovery for PrivateQuery, things work.
- }
- q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
- }
- else
{
mStatus err;
- // if AuthInfo and AuthInfo->AutoTunnel is set, we use the TCP socket but don't need to pass the AuthInfo as
- // we already protected the message above.
- LogInfo("sendLLQRefresh: using existing %s session %##s (%s)", PrivateQuery(q) ? "TLS" : "UDP",
- q->qname.c, DNSTypeName(q->qtype));
+ LogInfo("sendLLQRefresh: using existing UDP session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL, mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->tcp ? q->tcp->sock : mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSfalse);
if (err)
{
LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
{
q->servAddr = zoneInfo->Addr;
q->servPort = zoneInfo->Port;
- if (!PrivateQuery(q))
+ // We don't need the zone data as we use it only for the Host information which we
+ // don't need if we are not going to use TLS connections.
+ if (q->nta)
{
- // We don't need the zone data as we use it only for the Host information which we
- // don't need if we are not going to use TLS connections.
- if (q->nta)
- {
- if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- }
+ if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
+ CancelGetZoneData(m, q->nta);
+ q->nta = mDNSNULL;
}
q->ntries = 0;
debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
mDNS_Unlock(m);
}
-#ifdef DNS_PUSH_ENABLED
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
{
DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
mDNS_Lock(m);
// If we get here it means that the GetZoneData operation has completed.
- // We hold on to the zone data if it is AutoTunnel as we use the hostname
- // in zoneInfo during the TLS connection setup.
q->servAddr = zeroAddr;
q->servPort = zeroIPPort;
- if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0])
- {
- q->dnsPushState = DNSPUSH_SERVERFOUND;
- q->dnsPushServerAddr = zoneInfo->Addr;
- q->dnsPushServerPort = zoneInfo->Port;
- q->ntries = 0;
- LogInfo("DNSPushNotificationGotZoneData %#a:%d", &q->dnsPushServerAddr, mDNSVal16(q->dnsPushServerPort));
- SubscribeToDNSPushNotificationServer(m,q);
- }
- else
+ if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && zoneInfo->Host.c[0])
{
- q->dnsPushState = DNSPUSH_NOSERVER;
- StartLLQPolling(m,q);
- if (err == mStatus_NoSuchNameErr)
+ q->state = LLQ_DNSPush_Connecting;
+ LogInfo("DNSPushNotificationGotZoneData %##s%%%d", &zoneInfo->Host, ntohs(zoneInfo->Port.NotAnInteger));
+ q->dnsPushServer = SubscribeToDNSPushNotificationServer(m, q);
+ if (q->dnsPushServer == mDNSNULL || (q->dnsPushServer->connectState != DNSPushServerConnectionInProgress &&
+ q->dnsPushServer->connectState != DNSPushServerConnected &&
+ q->dnsPushServer->connectState != DNSPushServerSessionEstablished))
{
- // this actually failed, so mark it by setting address to all ones
- q->servAddr.type = mDNSAddrType_IPv4;
- q->servAddr.ip.v4 = onesIPv4Addr;
+ goto noServer;
}
}
- mDNS_Unlock(m);
-}
-#endif // DNS_PUSH_ENABLED
-
-// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
-mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
-{
- DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
-
- LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
-
- if (q->nta != zoneInfo) LogMsg("PrivateQueryGotZoneData:ERROR!!: nta (%p) != zoneInfo (%p) %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
-
- if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port) || !zoneInfo->Host.c[0])
- {
- LogInfo("PrivateQueryGotZoneData: ERROR!! %##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);
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- return;
- }
-
- if (!zoneInfo->ZonePrivate)
- {
- debugf("Private port lookup failed -- retrying without TLS -- %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->AuthInfo = mDNSNULL; // Clear AuthInfo so we try again non-private
- q->ThisQInterval = InitialQuestionInterval;
- q->LastQTime = m->timenow - q->ThisQInterval;
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- mDNS_Lock(m);
- SetNextQueryTime(m, q);
- mDNS_Unlock(m);
- return;
- // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
- }
-
- if (!PrivateQuery(q))
+ else
{
- LogMsg("PrivateQueryGotZoneData: ERROR!! Not a private query %##s (%s) AuthInfo %p", q->qname.c, DNSTypeName(q->qtype), q->AuthInfo);
- CancelGetZoneData(m, q->nta);
- q->nta = mDNSNULL;
- return;
+ noServer:
+ q->state = LLQ_InitialRequest;
+ startLLQHandshake(m,q);
}
-
- q->TargetQID = mDNS_NewMessageID(m);
- if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
- if (!q->nta) { LogMsg("PrivateQueryGotZoneData:ERROR!! nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
- q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, &q->nta->Host, q, mDNSNULL);
- if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; }
+ mDNS_Unlock(m);
}
+#endif
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && newRR->nta && !mDNSAddrIsRFC1918(&newRR->nta->Addr) &&
newRR->AutoTarget == Target_AutoHostAndNATMAP)
{
- DomainAuthInfo *AuthInfo;
- AuthInfo = GetAuthInfoForName(m, newRR->resrec.name);
- if (AuthInfo && AuthInfo->AutoTunnel)
- {
- domainname *t = GetRRDomainNameTarget(&newRR->resrec);
- LogMsg("RecordRegistrationGotZoneData: ERROR!! AutoTunnel has Target_AutoHostAndNATMAP for %s", ARDisplayString(m, newRR));
- if (t) t->c[0] = 0;
- newRR->resrec.rdlength = newRR->resrec.rdestimate = 0;
- newRR->state = regState_NoTarget;
- CancelGetZoneData(m, newRR->nta);
- newRR->nta = mDNSNULL;
- return;
- }
// During network transitions, we are called multiple times in different states. Setup NAT
// state just once for this record.
if (!newRR->NATinfo.clientContext)
limit = ptr + AbsoluteMaxDNSMessageData;
AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
- limit -= RRAdditionalSize(m, AuthInfo);
+ limit -= RRAdditionalSize(AuthInfo);
rr->updateid = mDNS_NewMessageID(m);
InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
mStatus err;
LogInfo("SendRecordDeregistration UDP %s", ARDisplayString(m, rr));
if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
- err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
+ err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &rr->nta->Addr, rr->nta->Port, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
//if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr); // Don't touch rr after this
}
mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
{
-#ifdef DNS_PUSH_ENABLED
- // First attempt to use DNS Push Notification.
- if (q->dnsPushState == DNSPUSH_INIT)
- DiscoverDNSPushNotificationServer(m, q);
-#endif // DNS_PUSH_ENABLED
- switch (q->state)
+ LogMsg("->uDNS_HandleLLQState: %##s %d", &q->qname, q->state);
+ switch(q->state)
{
+ case LLQ_Init:
+ // If DNS Push isn't supported, LLQ_Init falls through to LLQ_InitialRequest.
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ // First attempt to use DNS Push Notification.
+ DiscoverDNSPushNotificationServer(m, q);
+ break;
+
+ case LLQ_DNSPush_ServerDiscovery:
+ case LLQ_DNSPush_Connecting:
+ case LLQ_DNSPush_Established:
+ // Sanity check the server state to see if it matches. If we find that we aren't connected, when
+ // we think we should be, change our state.
+ if (q->dnsPushServer == NULL)
+ {
+ q->state = LLQ_Init;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ }
+ else
+ {
+ switch(q->dnsPushServer->connectState)
+ {
+ case DNSPushServerDisconnected:
+ case DNSPushServerConnectFailed:
+ case DNSPushServerNoDNSPush:
+ LogMsg("uDNS_HandleLLQState: %##s, server state %d doesn't match question state %d",
+ &q->dnsPushServer->serverName, q->state, q->dnsPushServer->connectState);
+ q->state = LLQ_Poll;
+ q->ThisQInterval = (mDNSPlatformOneSecond * 5);
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ break;
+ case DNSPushServerSessionEstablished:
+ LogMsg("uDNS_HandleLLQState: %##s, server connection established but question state is %d",
+ &q->dnsPushServer->serverName, q->state);
+ q->state = LLQ_DNSPush_Established;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ break;
+
+ case DNSPushServerConnectionInProgress:
+ case DNSPushServerConnected:
+ break;
+ }
+ }
+ break;
+#else
+ // Silence warnings; these are never reached without DNS Push
+ case LLQ_DNSPush_ServerDiscovery:
+ case LLQ_DNSPush_Connecting:
+ case LLQ_DNSPush_Established:
+#endif // MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
case LLQ_InitialRequest: startLLQHandshake(m, q); break;
- case LLQ_SecondaryRequest:
- // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
- if (PrivateQuery(q)) startLLQHandshake(m, q);
- else sendChallengeResponse(m, q, mDNSNULL);
- break;
+ case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
case LLQ_Established: sendLLQRefresh(m, q); break;
case LLQ_Poll: break; // Do nothing (handled below)
}
+ LogMsg("<-uDNS_HandleLLQState: %##s %d %d", &q->qname, q->state);
}
// The question to be checked is not passed in as an explicit parameter;
{
DNSServer *orig = q->qDNSServer;
if (orig)
- LogInfo("uDNS_CheckCurrentQuestion: 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);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: Sent %d unanswered queries for " PRI_DM_NAME " (" PUB_S ") to " PRI_IP_ADDR ":%d (" PRI_DM_NAME ")",
+ q->request_id, mDNSVal16(q->TargetQID), q->unansweredQueries, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), DM_NAME_PARAM(orig->domain.c));
+ }
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
SymptomReporterDNSServerUnreachable(orig);
#endif
PenalizeDNSServer(m, q, zeroID);
{
DNSServer *new;
DNSQuestion *qptr;
- q->triedAllServersOnce = 1;
+ q->triedAllServersOnce = mDNStrue;
// Re-initialize all DNS servers for this question. If we have a DNSServer, DNSServerChangeForQuestion will
// handle all the work including setting the new DNS server.
SetValidDNSServers(m, q);
new = GetServerForQuestion(m, q);
if (new)
{
- LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%d ThisQInterval %d",
- q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_checkCurrentQuestion: Retrying question %p " PRI_DM_NAME " (" PUB_S ") DNS Server " PRI_IP_ADDR ":%d ThisQInterval %d",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval);
DNSServerChangeForQuestion(m, q, new);
}
for (qptr = q->next ; qptr; qptr = qptr->next)
{
mDNSu8 *end;
mStatus err = mStatus_NoError;
- mDNSBool private = mDNSfalse;
InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
else
end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
}
- private = PrivateQuery(q);
if (end > m->omsg.data)
{
- //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
- if (private)
+ debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
+ q, q->qname.c, DNSTypeName(q->qtype),
+ q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
+#if APPLE_OSX_mDNSResponder
+ // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
+ // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
+ // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
+ // socket pair so that we can create a new pair.
+ if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
{
- if (q->nta) CancelGetZoneData(m, q->nta);
- q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q);
- if (q->state == LLQ_Poll) q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
+ mDNSPlatformUDPClose(q->LocalSocket);
+ q->LocalSocket = mDNSNULL;
+ }
+#endif
+ if (!q->LocalSocket)
+ {
+ q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
+ if (q->LocalSocket)
+ {
+ mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
+ mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv6, q);
+ }
}
+ if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
else
{
- debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
- q, q->qname.c, DNSTypeName(q->qtype),
- q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
-#if APPLE_OSX_mDNSResponder
- // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
- // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
- // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
- // socket pair so that we can create a new pair.
- if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+ // If we are in suspicious mode, restart question as TCP
+ mDNSs32 suspiciousTimeout = m->NextSuspiciousTimeout ? m->NextSuspiciousTimeout - m->timenow : 0;
+ if (suspiciousTimeout > 0 && suspiciousTimeout <= SUSPICIOUS_REPLY_DEFENSE_SECS * mDNSPlatformOneSecond)
{
- mDNSPlatformUDPClose(q->LocalSocket);
- q->LocalSocket = mDNSNULL;
+ uDNS_RestartQuestionAsTCP(m, q, &q->qDNSServer->addr, q->qDNSServer->port);
+ err = mStatus_NoError;
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ q->metrics.dnsOverTCPState = DNSOverTCP_SuspiciousDefense;
+#endif
}
+ else
#endif
- if (!q->LocalSocket)
{
- q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
- if (q->LocalSocket)
- {
- mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
- mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv6, q);
- }
+ err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, mDNSNULL, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, q->UseBackgroundTraffic);
}
- if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
- else
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ if (!err)
{
- err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass);
-#if AWD_METRICS
- if (!err)
+ MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
+ if (q->metrics.answered)
{
- MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
- if (q->metrics.answered)
- {
- q->metrics.querySendCount = 0;
- q->metrics.answered = mDNSfalse;
- }
- if (q->metrics.querySendCount++ == 0)
- {
- q->metrics.firstQueryTime = m->timenow;
- }
+ q->metrics.querySendCount = 0;
+ q->metrics.answered = mDNSfalse;
+ }
+ if (q->metrics.querySendCount++ == 0)
+ {
+ q->metrics.firstQueryTime = m->timenow;
}
-#endif
}
- }
+#endif
+ }
}
if (err == mStatus_HostUnreachErr)
{
DNSServer *newServer;
- LogInfo("uDNS_CheckCurrentQuestion: host unreachable error for DNS server %#a for question [%p] %##s (%s)",
- &q->qDNSServer->addr, q, q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: host unreachable error for DNS server " PRI_IP_ADDR " for question [%p] " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), &q->qDNSServer->addr, q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
if (!StrictUnicastOrdering)
{
newServer = GetServerForQuestion(m, q);
if (!newServer)
{
- q->triedAllServersOnce = 1;
+ q->triedAllServersOnce = mDNStrue;
SetValidDNSServers(m, q);
newServer = GetServerForQuestion(m, q);
}
if (newServer)
{
- LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%u ThisQInterval %d",
- q, q->qname.c, DNSTypeName(q->qtype), newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_checkCurrentQuestion: Retrying question %p " PRI_DM_NAME " (" PUB_S ") DNS Server " PRI_IP_ADDR ":%u ThisQInterval %d",
+ q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+ newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
DNSServerChangeForQuestion(m, q, newServer);
}
if (q->triedAllServersOnce)
q->unansweredQueries++;
if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
- if (private && q->state != LLQ_Poll)
- {
- // We don't want to retransmit too soon. Hence, we always schedule our first
- // retransmisson at 3 seconds rather than one second
- if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
- q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
- if (q->ThisQInterval > LLQ_POLL_INTERVAL)
- q->ThisQInterval = LLQ_POLL_INTERVAL;
- LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
- }
if (q->qDNSServer->isCell)
{
// We don't want to retransmit too soon. Schedule our first retransmisson at
// (When we have a group of identical questions, only the active representative of the group gets
// passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
// but we want *all* of the questions to get answer callbacks.)
- CacheRecord *rr;
+ CacheRecord *cr;
const mDNSu32 slot = HashSlotFromNameHash(q->qnamehash);
CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
if (!q->qDNSServer)
{
if (!mDNSOpaque128IsZero(&q->validDNSServers))
- LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question %##s (%s)",
- q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
// If we reached the end of list while picking DNS servers, then we don't want to deactivate the
// question. Try after 60 seconds. We find this by looking for valid DNSServers for this question,
// if we find any, then we must have tried them before we came here. This avoids maintaining
SetValidDNSServers(m, q);
if (mDNSOpaque128IsZero(&q->validDNSServers))
{
- LogInfo("uDNS_CheckCurrentQuestion: no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: no DNS server for " PRI_DM_NAME " (" PUB_S ")",
+ q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
q->ThisQInterval = 0;
}
else
q->qDNSServer = GetServerForQuestion(m, q);
for (qptr = q->next ; qptr; qptr = qptr->next)
if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
- LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d",
- q, q->SuppressUnusable, q->qname.c, DNSTypeName(q->qtype),
- q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d " PRI_DM_NAME " (" PUB_S ") with DNS Server " PRI_IP_ADDR ":%d after 60 seconds, ThisQInterval %d",
+ q->request_id, mDNSVal16(q->TargetQID), q, q->SuppressUnusable, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+ q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval);
}
}
else
{
q->ThisQInterval = 0;
- LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion DNS server " PRI_IP_ADDR ":%d for " PRI_DM_NAME " is disabled",
+ q->request_id, mDNSVal16(q->TargetQID), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), DM_NAME_PARAM(q->qname.c));
}
if (cg)
{
- for (rr = cg->members; rr; rr=rr->next)
+ for (cr = cg->members; cr; cr=cr->next)
{
- if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+ if (SameNameCacheRecordAnswersQuestion(cr, q))
{
- LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
- mDNS_PurgeCacheResourceRecord(m, rr);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] uDNS_CheckCurrentQuestion: Purged resourcerecord " PRI_S,
+ q->request_id, mDNSVal16(q->TargetQID), CRDisplayString(m, cr));
+ mDNS_PurgeCacheResourceRecord(m, cr);
}
}
}
if (!mDNSOpaque16IsZero(q->responseFlags))
m->rec.r.responseFlags = q->responseFlags;
// We're already using the m->CurrentQuestion pointer, so CacheRecordAdd can't use it to walk the question list.
- // To solve this problem we set rr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
+ // To solve this problem we set cr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
// momentarily defer generating answer callbacks until mDNS_Execute time.
CreateNewCacheEntry(m, slot, cg, NonZeroTime(m->timenow), mDNStrue, mDNSNULL);
ScheduleNextCacheCheckTime(m, slot, NonZeroTime(m->timenow));
mDNSs32 nexte;
DNSServer *d;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+ if (m->NextSuspiciousTimeout && m->NextSuspiciousTimeout <= m->timenow) m->NextSuspiciousTimeout = 0;
+#endif
m->NextuDNSEvent = m->timenow + FutureTime;
nexte = CheckRecordUpdates(m);
{
if (m->timenow - d->penaltyTime >= 0)
{
- LogInfo("DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "DNS server " PRI_IP_ADDR ":%d out of penalty box", &d->addr, mDNSVal16(d->port));
d->penaltyTime = 0;
}
else
}
if (m->CurrentQuestion)
- LogMsg("uDNS_Tasks ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "uDNS_Tasks ERROR m->CurrentQuestion already set: " PRI_DM_NAME " (" PRI_S ")",
+ DM_NAME_PARAM(m->CurrentQuestion->qname.c), DNSTypeName(m->CurrentQuestion->qtype));
+ }
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
{
else
{
// if domain not in list, add to list, mark as add (1)
- *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
+ *p = (SearchListElem *) mDNSPlatformMemAllocateClear(sizeof(**p));
if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
- mDNSPlatformMemZero(*p, sizeof(SearchListElem));
AssignDomainName(&(*p)->domain, domain);
(*p)->next = mDNSNULL;
(*p)->InterfaceID = InterfaceID;
if (AddRecord)
{
- ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
+ ARListElem *arElem = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*arElem));
if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); return; }
mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, AuthRecordLocalOnly, FreeARElemCallback, arElem);
MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
uDNS_SetupWABQueries(m);
}
-mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
+mDNSexport domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, int *searchIndex, mDNSBool ignoreDotLocal)
{
SearchListElem *p = SearchList;
int count = *searchIndex;
}
// Point to the next one in the list which we will look at next time.
(*searchIndex)++;
- // When we are appending search domains in a ActiveDirectory domain, the question's InterfaceID
- // set to mDNSInterface_Unicast. Match the unscoped entries in that case.
- if (((InterfaceID == mDNSInterface_Unicast) && (p->InterfaceID == mDNSInterface_Any)) ||
- p->InterfaceID == InterfaceID)
+ if (p->InterfaceID == InterfaceID)
{
LogInfo("uDNS_GetNextSearchDomain returning domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
return &p->domain;
// new DNS server. So, always try to establish a new connection.
if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, q, mDNSNULL);
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "uDNS_RestartQuestionAsTCP: suspicious timeout %d ticks",
+ m->NextSuspiciousTimeout ? m->NextSuspiciousTimeout - m->timenow : 0);
+#endif
}
mDNSlocal void FlushAddressCacheRecords(mDNS *const m)
#pragma mark - DNS Push Notification functions
#endif
-#ifdef DNS_PUSH_ENABLED
-mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+mDNSlocal void DNSPushProcessResponse(mDNS *const m, const DNSMessage *const msg,
+ DNSPushNotificationServer *server, ResourceRecord *mrr)
{
- DNSPushNotificationZone *zone;
- DNSPushNotificationServer *server;
- DNSPushNotificationZone *newZone;
- DNSPushNotificationServer *newServer;
+ // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
+ // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
+ // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
+ CacheRecord *CacheFlushRecords = (CacheRecord*)1;
+ CacheRecord **cfp = &CacheFlushRecords;
+ enum { removeName, removeClass, removeRRset, removeRR, addRR } action;
- // If we already have a question for this zone and if the server is the same, reuse it
- for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ // Ignore records we don't want to cache.
+
+ // Don't want to cache OPT or TSIG pseudo-RRs
+ if (mrr->rrtype == kDNSType_TSIG)
{
- if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
+ return;
+ }
+ if (mrr->rrtype == kDNSType_OPT)
+ {
+ return;
+ }
+
+ if ((mrr->rrtype == kDNSType_CNAME) && SameDomainName(mrr->name, &mrr->rdata->u.name))
+ {
+ LogInfo("DNSPushProcessResponse: CNAME loop domain name %##s", mrr->name->c);
+ return;
+ }
+
+ // TTL == -1: delete individual record
+ // TTL == -2: wildcard delete
+ // CLASS != ANY, TYPE != ANY: delete all records of specified type and class
+ // CLASS != ANY, TYPE == ANY: delete all RRs of specified class
+ // CLASS == ANY: delete all RRs on the name, regardless of type or class (TYPE is ignored).
+ // If TTL is zero, this is a delete, not an add.
+ if ((mDNSs32)mrr->rroriginalttl == -1)
+ {
+ LogMsg("DNSPushProcessResponse: Got remove on %##s with type %s",
+ mrr->name, DNSTypeName(mrr->rrtype));
+ action = removeRR;
+ }
+ else if ((mDNSs32)mrr->rroriginalttl == -2)
+ {
+ if (mrr->rrclass == kDNSQClass_ANY)
{
- DNSPushNotificationServer *zoneServer = mDNSNULL;
- for (zoneServer = zone->servers; zoneServer != mDNSNULL; zoneServer = zoneServer->next)
+ LogMsg("DNSPushProcessResponse: Got Remove Name on %##s", mrr->name);
+ action = removeName;
+ }
+ else if (mrr->rrtype == kDNSQType_ANY)
+ {
+ LogMsg("DNSPushProcessResponse: Got Remove Name on %##s", mrr->name);
+ action = removeClass;
+ }
+ else
+ {
+ LogMsg("DNSPushProcessResponse: Got Remove RRset on %##s, type %s, rdlength %d",
+ mrr->name, DNSTypeName(mrr->rrtype), mrr->rdlength);
+ action = removeRRset;
+ }
+ }
+ else
+ {
+ action = addRR;
+ }
+
+ if (action != addRR)
+ {
+ if (m->rrcache_size)
+ {
+ CacheRecord *rr;
+ // Remember the unicast question that we found, which we use to make caching
+ // decisions later on in this function
+ CacheGroup *cg = CacheGroupForName(m, mrr->namehash, mrr->name);
+ for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
{
- if (mDNSSameAddress(&q->dnsPushServerAddr, &zoneServer->serverAddr))
+ if ( action == removeName ||
+ (action == removeClass && rr->resrec.rrclass == mrr->rrclass) ||
+ (rr->resrec.rrclass == mrr->rrclass &&
+ ((action == removeRRset && rr->resrec.rrtype == mrr->rrtype) ||
+ (action == removeRR && rr->resrec.rrtype == mrr->rrtype &&
+ SameRDataBody(mrr, &rr->resrec.rdata->u, SameDomainName)))))
{
- zone->numberOfQuestions++;
- zoneServer->numberOfQuestions++;
- return zoneServer->connection;
+ LogInfo("DNSPushProcessResponse purging %##s (%s) %s",
+ rr->resrec.name, DNSTypeName(mrr->rrtype), CRDisplayString(m, rr));
+ // We've found a cache entry to delete. Now what?
+ mDNS_PurgeCacheResourceRecord(m, rr);
}
}
}
}
-
- // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
- for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
+ else
{
- if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr))
- {
- newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
- newZone->numberOfQuestions = 1;
- newZone->zoneName = q->nta->ChildName;
- newZone->servers = server;
-
- // Add the new zone to the begining of the list
- newZone->next = m->DNSPushZones;
- m->DNSPushZones = newZone;
-
- server->numberOfQuestions++;
- return server->connection;
+ // It's an add.
+ LogMsg("DNSPushProcessResponse: Got add RR on %##s, type %s, length %d",
+ mrr->name, DNSTypeName(mrr->rrtype), mrr->rdlength);
+
+ // When we receive DNS Push responses, we assume a long cache lifetime --
+ // This path is only reached for DNS Push responses; as long as the connection to the server is
+ // live, the RR should stay ypdated.
+ mrr->rroriginalttl = kLLQ_DefLease /* XXX */;
+
+ // Use the DNS Server we remember from the question that created this DNS Push server structure.
+ mrr->rDNSServer = server->qDNSServer;
+
+ // 2. See if we want to add this packet resource record to our cache
+ // We only try to cache answers if we have a cache to put them in
+ if (m->rrcache_size)
+ {
+ const mDNSu32 slot = HashSlotFromNameHash(mrr->namehash);
+ CacheGroup *cg = CacheGroupForName(m, mrr->namehash, mrr->name);
+ CacheRecord *rr = mDNSNULL;
+ CacheRecord *NSECCachePtr = (CacheRecord *)1;
+
+ // 2a. Check if this packet resource record is already in our cache.
+ rr = mDNSCoreReceiveCacheCheck(m, msg, uDNS_LLQ_Events, slot, cg, mDNSNULL, &cfp, &NSECCachePtr, mDNSNULL);
+
+ // If packet resource record not in our cache, add it now
+ // (unless it is just a deletion of a record we never had, in which case we don't care)
+ if (!rr && mrr->rroriginalttl > 0)
+ {
+ rr = CreateNewCacheEntry(m, slot, cg, 0,
+ mDNStrue, &server->connection->transport->remote_addr);
+ if (rr)
+ {
+ // Not clear that this is ever used, but for verisimilitude, set this to look like
+ // an authoritative response to a regular query.
+ rr->responseFlags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA;
+ rr->responseFlags.b[1] = kDNSFlag1_RC_NoErr | kDNSFlag0_AA;
+ }
+ }
}
}
+}
- // If we do not have any existing connections, create a new connection
- newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
- newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
-
- newServer->numberOfQuestions = 1;
- newServer->serverAddr = q->dnsPushServerAddr;
- newServer->connection = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->dnsPushServerAddr, q->dnsPushServerPort, &q->nta->Host, q, mDNSNULL);
-
- newZone->numberOfQuestions = 1;
- newZone->zoneName = q->nta->ChildName;
- newZone->servers = newServer;
-
- // Add the new zone to the begining of the list
- newZone->next = m->DNSPushZones;
- m->DNSPushZones = newZone;
-
- newServer->next = m->DNSPushServers;
- m->DNSPushServers = newServer;
- return newServer->connection;
+mDNSlocal void DNSPushProcessResponses(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *firstAnswer,
+ const mDNSu8 *const end, DNSPushNotificationServer *server)
+{
+ DNSQuestion *q;
+ const mDNSu8 *ptr = firstAnswer;
+ mDNSIPPort port;
+ port.NotAnInteger = 0;
+ ResourceRecord *mrr = &m->rec.r.resrec;
+
+ // Validate the contents of the message
+ // XXX Right now this code will happily parse all the valid data and then hit invalid data
+ // and give up. I don't think there's a risk here, but we should discuss it.
+ // XXX what about source validation? Like, if we have a VPN, are we safe? I think yes, but let's think about it.
+ while ((ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSNULL, kDNSRecordTypePacketAns, &m->rec)))
+ {
+ int gotOne = 0;
+ for (q = m->Questions; q; q = q->next)
+ {
+ if (q->LongLived &&
+ (q->qtype == mrr->rrtype || q->qtype == kDNSServiceType_ANY)
+ && q->qnamehash == mrr->namehash && SameDomainName(&q->qname, mrr->name))
+ {
+ LogMsg("DNSPushProcessResponses found %##s (%s) %d %s %s",
+ q->qname.c, DNSTypeName(q->qtype), q->state,
+ q->dnsPushServer ? (q->dnsPushServer->connection
+ ? q->dnsPushServer->connection->remote_name
+ : "<no push server>") : "<no push server>",
+ server->connection->remote_name);
+ if (q->dnsPushServer == server)
+ {
+ gotOne++;
+ DNSPushProcessResponse(m, msg, server, mrr);
+ break; // question list may have changed
+ }
+ }
+ }
+ if (!gotOne) {
+ LogMsg("DNSPushProcessResponses: no match for %##s %d %d", mrr->name, mrr->rrtype, mrr->rrclass);
+ }
+ mrr->RecordType = 0; // Clear RecordType to show we're not still using it
+ }
+}
+
+static void
+DNSPushStartConnecting(DNSPushNotificationServer *server)
+{
+ if (dso_connect(server->connectInfo))
+ {
+ server->connectState = DNSPushServerConnectionInProgress;
+ }
+ else
+ {
+ server->connectState = DNSPushServerConnectFailed;
+ }
}
-mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+mDNSexport void DNSPushReconcileConnection(mDNS *m, DNSQuestion *q)
{
- /* Use the same NAT setup as in the LLQ case */
- if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
+ DNSPushNotificationZone *zone;
+ DNSPushNotificationZone *nextZone;
+
+ if (q->dnsPushServer == mDNSNULL)
{
- 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);
return;
}
+
+ // Update the counts
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+ {
+ if (zone->server == q->dnsPushServer)
+ {
+ zone->numberOfQuestions--;
+ }
+ }
+ q->dnsPushServer->numberOfQuestions--;
- // Either we don't have {PCP, NAT-PMP, UPnP/IGD} support (ExternalPort is zero) or behind a Double NAT that may or
- // may not have {PCP, NAT-PMP, UPnP/IGD} support (NATResult is non-zero)
- if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
+ nextZone = mDNSNULL;
+ for (zone = m->DNSPushZones; zone != mDNSNULL; zone = nextZone)
{
- LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d",
- q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result);
- StartLLQPolling(m, q); // Actually sets up the NAT Auto Tunnel
+ nextZone = zone->next;
+ if (zone->numberOfQuestions == 0)
+ {
+ if (zone == m->DNSPushZones)
+ m->DNSPushZones = nextZone;
+ LogInfo("DNSPushReconcileConnection: zone %##s is being freed", &zone->zoneName);
+ mDNSPlatformMemFree(zone);
+ }
+ }
+
+ q->dnsPushServer = mDNSNULL;
+}
+
+static const char kDNSPushActivity_Subscription[] = "dns-push-subscription";
+
+static void DNSPushSendKeepalive(DNSPushNotificationServer *server, mDNSu32 inactivity_timeout, mDNSu32 keepalive_interval)
+{
+ dso_message_t state;
+ dso_transport_t *transport = server->connection->transport;
+ if (transport == NULL || transport->outbuf == NULL) {
+ // Should be impossible, don't crash.
+ LogInfo("DNSPushNotificationSendSubscribe: no transport!");
return;
}
+ dso_make_message(&state, transport->outbuf, transport->outbuf_size, server->connection, false, 0);
+ dso_start_tlv(&state, kDSOType_Keepalive);
+ dso_add_tlv_u32(&state, inactivity_timeout);
+ dso_add_tlv_u32(&state, keepalive_interval);
+ dso_finish_tlv(&state);
+ dso_message_write(server->connection, &state, mDNSfalse);
+}
- if (mDNSIPPortIsZero(q->dnsPushServerPort) && q->dnsPushState == DNSPUSH_INIT)
- {
- LogInfo("SubscribeToDNSPushNotificationServer: 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->dnsPushServerAddr = zeroAddr;
- // We know q->dnsPushServerPort is zero because of check above
- if (q->nta) CancelGetZoneData(m, q->nta);
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+static void DNSPushNotificationSendSubscriptionChange(mDNSBool subscribe, dso_state_t *dso, DNSQuestion *q)
+{
+ dso_message_t state;
+ dso_transport_t *transport = dso->transport;
+ mDNSu16 len;
+ if (transport == NULL || transport->outbuf == NULL) {
+ // Should be impossible, don't crash.
+ LogInfo("DNSPushNotificationSendSubscribe: no transport!");
return;
}
+ dso_make_message(&state, transport->outbuf, transport->outbuf_size, dso, subscribe ? false : true, q);
+ dso_start_tlv(&state, subscribe ? kDSOType_DNSPushSubscribe : kDSOType_DNSPushUnsubscribe);
+ len = DomainNameLengthLimit(&q->qname, q->qname.c + (sizeof q->qname));
+ dso_add_tlv_bytes(&state, q->qname.c, len);
+ dso_add_tlv_u16(&state, q->qtype);
+ dso_add_tlv_u16(&state, q->qclass);
+ dso_finish_tlv(&state);
+ dso_message_write(dso, &state, mDNSfalse);
+}
- if (q->tcp)
+static void DNSPushStop(mDNS *m, DNSPushNotificationServer *server)
+{
+ mDNSBool found = mDNStrue;
+ DNSQuestion *q;
+ while (found)
{
- LogInfo("SubscribeToDNSPushNotificationServer: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- DisposeTCPConn(q->tcp);
- q->tcp = mDNSNULL;
+ found = mDNSfalse;
+ server->connectState = DNSPushServerNoDNSPush;
+
+ for (q = m->Questions; q; q = q->next)
+ {
+ if (q->dnsPushServer == server)
+ {
+ DNSPushReconcileConnection(m, q);
+ q->dnsPushServer = NULL;
+ q->state = LLQ_Poll;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ break;
+ }
+ }
}
+}
- if (!q->nta)
+mDNSexport void DNSPushServerDrop(DNSPushNotificationServer *server)
+{
+ if (server->connection)
{
- // Normally we lookup the zone data and then call this function. And we never free the zone data
- // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
- // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
- // When we poll, we free the zone information as we send the query to the server (See
- // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
- // are still behind Double NAT, we would have returned early in this function. But we could
- // have switched to a network with no NATs and we should get the zone data again.
- LogInfo("SubscribeToDNSPushNotificationServer: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
- return;
+ dso_drop(server->connection);
+ server->connection = NULL;
}
- else if (!q->nta->Host.c[0])
+ if (server->connectInfo)
{
- // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
- LogMsg("SubscribeToDNSPushNotificationServer: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
+ dso_connect_state_drop(server->connectInfo);
}
- q->tcp = GetTCPConnectionToPushServer(m,q);
- // If TCP failed (transient networking glitch) try again in five seconds
- q->ThisQInterval = (q->tcp != mDNSNULL) ? q->ThisQInterval = 0 : (mDNSPlatformOneSecond * 5);
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
}
-
-mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+static void DNSPushServerFree(mDNS *m, DNSPushNotificationServer *server)
{
- mDNSu8 *end = mDNSNULL;
- InitializeDNSMessage(&m->omsg.h, zeroID, SubscribeFlags);
- end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (!end)
+ DNSPushNotificationServer **sp;
+ DNSPushServerDrop(server);
+
+ sp = &m->DNSPushServers;
+ while (*sp)
{
- LogMsg("ERROR: SubscribeToDNSPushNotificationServer putQuestion failed");
- return;
+ if (*sp == server)
+ {
+ *sp = server->next;
+ break;
+ }
+ else
+ {
+ sp = &server->next;
+ }
}
+ mDNSPlatformMemFree(server);
+}
- mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+static void DNSPushDSOCallback(void *context, const void *event_context,
+ dso_state_t *dso, dso_event_type_t eventType)
+{
+ const DNSMessage *message;
+ DNSPushNotificationServer *server = context;
+ dso_activity_t *activity;
+ const dso_query_receive_context_t *receive_context;
+ const dso_disconnect_context_t *disconnect_context;
+ const dso_keepalive_context_t *keepalive_context;
+ DNSQuestion *q;
+ uint16_t rcode;
+ mDNSs32 reconnect_when = 0;
+ mDNS *m = server->m;
- // update question state
- q->dnsPushState = DNSPUSH_ESTABLISHED;
- q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
- q->LastQTime = m->timenow;
- SetNextQueryTime(m, q);
+ mDNS_CheckLock(m);
+
+ switch(eventType)
+ {
+ case kDSOEventType_DNSMessage:
+ // We shouldn't get here because we won't use this connection for DNS messages.
+ message = event_context;
+ LogMsg("DNSPushDSOCallback: DNS Message (opcode=%d) received from %##s",
+ (message->h.flags.b[0] & kDNSFlag0_OP_Mask) >> 3, &server->serverName);
+ break;
+
+ case kDSOEventType_DNSResponse:
+ // We shouldn't get here because we already handled any DNS messages
+ message = event_context;
+ LogMsg("DNSPushDSOCallback: DNS Response (opcode=%d) received from %##s",
+ (message->h.flags.b[0] & kDNSFlag0_OP_Mask) >> 3, &server->serverName);
+ break;
+
+ case kDSOEventType_DSOMessage:
+ message = event_context;
+ if (dso->primary.opcode == kDSOType_DNSPushUpdate) {
+ DNSPushProcessResponses(server->m, message, dso->primary.payload,
+ dso->primary.payload + dso->primary.length, server);
+ } else {
+ dso_send_not_implemented(dso, &message->h);
+ LogMsg("DNSPushDSOCallback: Unknown DSO Message (Primary TLV=%d) received from %##s",
+ dso->primary.opcode, &server->serverName);
+ }
+ break;
+
+ case kDSOEventType_DSOResponse:
+ receive_context = event_context;
+ q = receive_context->query_context;
+ rcode = receive_context->rcode;
+ if (q) {
+ // If we got an error on a subscribe, we need to evaluate what went wrong
+ if (rcode == kDNSFlag1_RC_NoErr) {
+ LogMsg("DNSPushDSOCallback: Subscription for %##s/%d/%d succeeded.", q->qname.c, q->qtype, q->qclass);
+ q->state = LLQ_DNSPush_Established;
+ server->connectState = DNSPushServerSessionEstablished;
+ } else {
+ // Don't use this server.
+ q->dnsPushServer->connectState = DNSPushServerNoDNSPush;
+ q->state = LLQ_Poll;
+ q->ThisQInterval = 0;
+ q->LastQTime = m->timenow;
+ SetNextQueryTime(m, q);
+ LogMsg("DNSPushDSOCallback: Subscription for %##s/%d/%d failed.", q->qname.c, q->qtype, q->qclass);
+ }
+ } else {
+ LogMsg("DNSPushDSOCallback: DSO Response (Primary TLV=%d) (RCODE=%d) (no query) received from %##s",
+ dso->primary.opcode, receive_context->rcode, &server->serverName);
+ server->connectState = DNSPushServerSessionEstablished;
+ }
+ break;
+
+ case kDSOEventType_Finalize:
+ LogMsg("DNSPushDSOCallback: Finalize");
+ break;
+
+ case kDSOEventType_Connected:
+ LogMsg("DNSPushDSOCallback: Connected to %##s", &server->serverName);
+ server->connectState = DNSPushServerConnected;
+ for (activity = dso->activities; activity; activity = activity->next) {
+ DNSPushNotificationSendSubscriptionChange(mDNStrue, dso, activity->context);
+ }
+ break;
+
+ case kDSOEventType_ConnectFailed:
+ DNSPushStop(m, server);
+ LogMsg("DNSPushDSOCallback: Connection to %##s failed", &server->serverName);
+ break;
+
+ case kDSOEventType_Disconnected:
+ disconnect_context = event_context;
+
+ // If a network glitch broke the connection, try to reconnect immediately. But if this happens
+ // twice, don't just blindly reconnect.
+ if (disconnect_context->reconnect_delay == 0) {
+ if ((server->lastDisconnect + 90 * mDNSPlatformOneSecond) - m->timenow > 0) {
+ reconnect_when = 3600000; // If we get two disconnects in quick succession, wait an hour before trying again.
+ } else {
+ DNSPushStartConnecting(server);
+ LogMsg("DNSPushDSOCallback: Connection to %##s disconnected, trying immediate reconnect",
+ &server->serverName);
+ }
+ } else {
+ reconnect_when = disconnect_context->reconnect_delay;
+ }
+ if (reconnect_when != 0) {
+ LogMsg("DNSPushDSOCallback: Holding server %##s out as not reconnectable for %lf seconds",
+ &server->serverName, 1000.0 * (reconnect_when - m->timenow) / (double)mDNSPlatformOneSecond);
+ dso_schedule_reconnect(m, server->connectInfo, reconnect_when);
+ }
+ server->lastDisconnect = m->timenow;
+ server->connection = mDNSNULL;
+ break;
+
+ // We don't reconnect unless there is demand. The reason we have this event is so that we can
+ // leave the DNSPushNotificationServer data structure around to _prevent_ attempts to reconnect
+ // before the reconnect delay interval has expired. When we get this call, we just free up the
+ // server.
+ case kDSOEventType_ShouldReconnect:
+ // This should be unnecessary, but it would be bad to accidentally have a question pointing at
+ // a server that had been freed, so make sure we don't.
+ LogMsg("DNSPushDSOCallback: ShouldReconnect timer for %##s fired, disposing of it.", &server->serverName);
+ DNSPushStop(m, server);
+ DNSPushServerFree(m, server);
+ break;
+
+ case kDSOEventType_Keepalive:
+ LogMsg("DNSPushDSOCallback: Keepalive timer for %##s fired.", &server->serverName);
+ keepalive_context = event_context;
+ DNSPushSendKeepalive(server, keepalive_context->inactivity_timeout, keepalive_context->keepalive_interval);
+ break;
+ case kDSOEventType_KeepaliveRcvd:
+ LogMsg("DNSPushDSOCallback: Keepalive message received from %##s.", &server->serverName);
+ break;
+
+ case kDSOEventType_Inactive:
+ // The set of activities went to zero, and we set the idle timeout. And it expired without any
+ // new activities starting. So we can disconnect.
+ LogMsg("DNSPushDSOCallback: Inactivity timer for %##s fired, disposing of it.", &server->serverName);
+ DNSPushStop(m, server);
+ DNSPushServerFree(m, server);
+ break;
+
+ case kDSOEventType_RetryDelay:
+ disconnect_context = event_context;
+ DNSPushStop(m, server);
+ dso_schedule_reconnect(m, server->connectInfo, disconnect_context->reconnect_delay);
+ break;
+ }
}
-mDNSlocal void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
+DNSPushNotificationServer *GetConnectionToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
{
DNSPushNotificationZone *zone;
DNSPushNotificationServer *server;
- DNSPushNotificationServer *nextServer;
- DNSPushNotificationZone *nextZone;
+ DNSPushNotificationZone *newZone;
+ DNSPushNotificationServer *newServer;
+ char name[MAX_ESCAPED_DOMAIN_NAME];
- // Update the counts
+ // If we already have a question for this zone and if the server is the same, reuse it
for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
{
- if (SameDomainName(&zone->zoneName, &q->nta->ChildName))
+ LogMsg("GetConnectionToDNSPushNotificationServer: zone compare zone %##s question %##s", &zone->zoneName, &q->nta->ChildName);
+ if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
{
- zone->numberOfQuestions--;
- for (server = zone->servers; server != mDNSNULL; server = server->next)
- {
- if (mDNSSameAddress(&server->serverAddr, &q->dnsPushServerAddr))
- server->numberOfQuestions--;
+ DNSPushNotificationServer *zoneServer = mDNSNULL;
+ zoneServer = zone->server;
+ if (zoneServer != mDNSNULL) {
+ LogMsg("GetConnectionToDNSPushNotificationServer: server compare server %##s question %##s",
+ &zoneServer->serverName, &q->nta->Host);
+ if (SameDomainName(&q->nta->Host, &zoneServer->serverName))
+ {
+ LogMsg("GetConnectionToDNSPushNotificationServer: server and zone already present.");
+ zone->numberOfQuestions++;
+ zoneServer->numberOfQuestions++;
+ return zoneServer;
+ }
}
}
}
- // Now prune the lists
- server = m->DNSPushServers;
- nextServer = mDNSNULL;
- while(server != mDNSNULL)
+ // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
+ for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
{
- nextServer = server->next;
- if (server->numberOfQuestions <= 0)
+ LogMsg("GetConnectionToDNSPushNotificationServer: server compare server %##s question %##s",
+ &server->serverName, &q->nta->Host);
+ if (SameDomainName(&q->nta->Host, &server->serverName))
{
- DisposeTCPConn(server->connection);
- if (server == m->DNSPushServers)
- m->DNSPushServers = nextServer;
- mDNSPlatformMemFree(server);
- server = nextServer;
+ newZone = (DNSPushNotificationZone *) mDNSPlatformMemAllocateClear(sizeof(*newZone));
+ if (newZone == NULL)
+ {
+ return NULL;
+ }
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->server = server;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ server->numberOfQuestions++;
+ LogMsg("GetConnectionToDNSPushNotificationServer: server already present.");
+ return server;
}
- else server = server->next;
}
- zone = m->DNSPushZones;
- nextZone = mDNSNULL;
- while(zone != mDNSNULL)
+ // If we do not have any existing connections, create a new connection
+ newServer = (DNSPushNotificationServer *) mDNSPlatformMemAllocateClear(sizeof(*newServer));
+ if (newServer == NULL)
{
- nextZone = zone->next;
- if (zone->numberOfQuestions <= 0)
- {
- if (zone == m->DNSPushZones)
- m->DNSPushZones = nextZone;
- mDNSPlatformMemFree(zone);
- zone = nextZone;
- }
- else zone = zone->next;
+ return NULL;
+ }
+ newZone = (DNSPushNotificationZone *) mDNSPlatformMemAllocateClear(sizeof(*newZone));
+ if (newZone == NULL)
+ {
+ mDNSPlatformMemFree(newServer);
+ return NULL;
+ }
+
+ newServer->m = m;
+ newServer->numberOfQuestions = 1;
+ AssignDomainName(&newServer->serverName, &q->nta->Host);
+ newServer->port = q->nta->Port;
+ newServer->qDNSServer = q->qDNSServer;
+ ConvertDomainNameToCString(&newServer->serverName, name);
+ newServer->connection = dso_create(mDNSfalse, 10, name, DNSPushDSOCallback, newServer, NULL);
+ if (newServer->connection == NULL)
+ {
+ mDNSPlatformMemFree(newServer);
+ mDNSPlatformMemFree(newZone);
+ return NULL;
+ }
+ newServer->connectInfo = dso_connect_state_create(name, mDNSNULL, newServer->port, 10,
+ AbsoluteMaxDNSMessageData, AbsoluteMaxDNSMessageData,
+ DNSPushDSOCallback, newServer->connection, newServer, "GetDSOConnectionToPushServer");
+ if (newServer->connectInfo)
+ {
+ dso_connect_state_use_tls(newServer->connectInfo);
+ DNSPushStartConnecting(newServer);
}
+ else
+ {
+ newServer->connectState = DNSPushServerConnectFailed;
+ }
+ newZone->numberOfQuestions = 1;
+ newZone->zoneName = q->nta->ChildName;
+ newZone->server = newServer;
+
+ // Add the new zone to the begining of the list
+ newZone->next = m->DNSPushZones;
+ m->DNSPushZones = newZone;
+
+ newServer->next = m->DNSPushServers;
+ m->DNSPushServers = newServer;
+ LogMsg("GetConnectionToDNSPushNotificationServer: allocated new server.");
+ return newServer;
}
-mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+DNSPushNotificationServer *SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
{
- mDNSu8 *end = mDNSNULL;
- InitializeDNSMessage(&m->omsg.h, q->TargetQID, UnSubscribeFlags);
- end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
- if (!end)
+ DNSPushNotificationServer *server = GetConnectionToDNSPushNotificationServer(m, q);
+ char name[MAX_ESCAPED_DOMAIN_NAME + 9]; // type(hex)+class(hex)+name
+ dso_activity_t *activity;
+ if (server == mDNSNULL) return server;
+
+ // Now we have a connection to a push notification server. It may be pending, or it may be active,
+ // but either way we can add a DNS Push subscription to the server object.
+ mDNS_snprintf(name, sizeof name, "%04x%04x", q->qtype, q->qclass);
+ ConvertDomainNameToCString(&q->qname, &name[8]);
+ activity = dso_add_activity(server->connection, name, kDNSPushActivity_Subscription, q, mDNSNULL);
+ if (activity == mDNSNULL)
{
- LogMsg("ERROR: UnSubscribeToDNSPushNotificationServer - putQuestion failed");
- return;
+ LogInfo("SubscribeToDNSPushNotificationServer: failed to add question %##s", &q->qname);
+ return mDNSNULL;
+ }
+ // If we're already connected, send the subscribe request immediately.
+ if (server->connectState == DNSPushServerConnected || server->connectState == DNSPushServerSessionEstablished)
+ {
+ DNSPushNotificationSendSubscriptionChange(mDNStrue, server->connection, q);
}
+ return server;
+}
- mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ LogInfo("DiscoverDNSPushNotificationServer: 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);
+ if (q->nta) CancelGetZoneData(m, q->nta);
+ q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+ q->state = LLQ_DNSPush_ServerDiscovery;
+}
- reconcileDNSPushConnection(m, q);
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+ dso_activity_t *activity;
+
+ if (q->dnsPushServer != mDNSNULL)
+ {
+ if (q->dnsPushServer->connection != mDNSNULL)
+ {
+ if (q->dnsPushServer->connectState == DNSPushServerSessionEstablished ||
+ q->dnsPushServer->connectState == DNSPushServerConnected)
+ {
+ // Ignore any response we get to a pending subscribe.
+ dso_ignore_response(q->dnsPushServer->connection, q);
+ DNSPushNotificationSendSubscriptionChange(mDNSfalse, q->dnsPushServer->connection, q);
+ }
+ // activities linger even if we are not connected.
+ activity = dso_find_activity(q->dnsPushServer->connection, mDNSNULL, kDNSPushActivity_Subscription, q);
+ if (activity != mDNSNULL) {
+ dso_drop_activity(q->dnsPushServer->connection, activity);
+ }
+ }
+ DNSPushReconcileConnection(m, q);
+ }
+ // We let the DSO Idle mechanism clean up the connection to the server.
}
+#endif // MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
-#endif // DNS_PUSH_ENABLED
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
#endif
(void) m;
}
-mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
+mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
{
(void) m;
(void) info;
(void) b64keydata;
(void) hostname;
(void) port;
- (void) autoTunnel;
return mStatus_UnsupportedErr;
}
}
mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
- const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSu32 resGroupID,
- mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+ const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46,
+ mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
{
(void) m;
(void) d;
(void) timeout;
(void) isCell;
(void) isExpensive;
+ (void) isCLAT46;
+ (void) isConstrained;
(void) resGroupID;
(void) reqA;
(void) reqAAAA;
#endif // !UNICAST_DISABLED
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
#include "mDNSEmbeddedAPI.h"
#include "DNSCommon.h"
+#include <sys/types.h>
+#include "dns_sd.h"
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+#include "dso.h"
+#include "dso-transport.h"
+#endif
#ifdef __cplusplus
extern "C" {
// validation (for optional case only) for any questions that uses this server
#define MAX_DNSSEC_RETRANSMISSIONS 3
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+// Push notification structures
+struct mDNS_DNSPushNotificationServer
+{
+ dso_connect_state_t *connectInfo; // DSO Connection state information
+ dso_state_t *connection; // DNS Stateful Operations/TCP Connection pointer, might be null.
+ mDNSu32 numberOfQuestions; // Number of questions for this server
+ DNSPushServer_ConnectState connectState; // Current status of connection attempt to this server
+ mDNSs32 lastDisconnect; // Last time we got a disconnect, used to avoid constant reconnects
+ domainname serverName; // The hostname returned by the _dns-push-tls._tcp.<zone> SRV lookup
+ mDNSIPPort port; // The port from the SRV lookup
+ DNSServer *qDNSServer; // DNS server stolen from the question that created this server structure.
+ mDNS *m;
+ DNSPushNotificationServer *next;
+} ;
+
+struct mDNS_DNSPushNotificationZone
+{
+ domainname zoneName;
+ DNSPushNotificationServer *server; // DNS Push Notification Servers for this zone
+ mDNSu32 numberOfQuestions; // Number of questions for this zone
+ DNSPushNotificationZone *next;
+} ;
+#endif
+
// Entry points into unicast-specific routines
extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
extern void startLLQHandshake(mDNS *m, DNSQuestion *q);
extern void sendLLQRefresh(mDNS *m, DNSQuestion *q);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
extern void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
extern void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
-extern void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern DNSPushNotificationServer *GetConnectionToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern DNSPushNotificationServer *SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
extern void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern void DNSPushReconcileConnection(mDNS *m, DNSQuestion *q);
+extern void DNSPushServerDrop(DNSPushNotificationServer *server);
+#endif
extern void SleepRecordRegistrations(mDNS *m);
extern void uDNS_SetupWABQueries(mDNS *const m);
extern void uDNS_StartWABQueries(mDNS *const m, int queryType);
extern void uDNS_StopWABQueries(mDNS *const m, int queryType);
-extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
+extern domainname *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, int *searchIndex, mDNSBool ignoreDotLocal);
extern void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
extern void natTraversalHandleAddressReply(mDNS *const m, mDNSu16 err, mDNSv4Addr ExtAddr);
extern void natTraversalHandlePortMapReply(mDNS *const m, NATTraversalInfo *n, const mDNSInterfaceID InterfaceID, mDNSu16 err, mDNSIPPort extport, mDNSu32 lease, NATTProtocol protocol);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
// DNS Push Notification
extern void SubscribeToDNSPushNotification(mDNS *m, DNSQuestion *q);
+#endif
-
+extern CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
+ const mDNSu32 slot, CacheGroup *cg, DNSQuestion *unicastQuestion,
+ CacheRecord ***cfp, CacheRecord **NSECCachePtr, mDNSInterfaceID InterfaceID);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ApplePlatformFeatures_h
+#define __ApplePlatformFeatures_h
+
+#include <TargetConditionals.h>
+
+// Feature: Bonjour-On-Demand
+// Radar: <rdar://problem/23523784>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_BONJOUR_ON_DEMAND)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_BONJOUR_ON_DEMAND 1
+#endif
+
+// Feature: Cache memory limit
+// Radar: <rdar://problem/15629764>
+// Enabled: Yes, but only for device OSes, such as iOS, tvOS, and watchOS, i.e., when TARGET_OS_IPHONE is 1.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_CACHE_MEM_LIMIT)
+ #if !defined(TARGET_OS_IPHONE)
+ #error "Expected TARGET_OS_IPHONE to be defined."
+ #endif
+ #if TARGET_OS_IPHONE
+ #define MDNSRESPONDER_SUPPORTS_APPLE_CACHE_MEM_LIMIT 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_APPLE_CACHE_MEM_LIMIT 0
+ #endif
+#endif
+
+// Feature: D2D
+// Radar: <rdar://problem/28062515>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_D2D)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_D2D 1
+#endif
+
+// Feature: DNS64 IPv6 synthesis.
+// Radar: <rdar://problem/32297396>
+// Enabled: Yes, but only for iOS and macOS, which support the DNS proxy network extension.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_DNS64)
+ #if (!defined(TARGET_OS_IOS) || !defined(TARGET_OS_OSX))
+ #error "Expected TARGET_OS_IOS and TARGET_OS_OSX to be defined."
+ #endif
+ #if (TARGET_OS_IOS || TARGET_OS_OSX)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_DNS64 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_APPLE_DNS64 0
+ #endif
+#endif
+
+// Feature: DNS-SD XPC service
+// Radar: <rdar://problem/43866363>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE 1
+#endif
+
+// Feature: Ignore /etc/hosts file on customer builds.
+// Radar: <rdar://problem/34745220>
+// Enabled: Yes, except for macOS.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_IGNORE_HOSTS_FILE)
+ #if !defined(TARGET_OS_OSX)
+ #error "Expected TARGET_OS_OSX to be defined."
+ #endif
+ #if !TARGET_OS_OSX
+ #define MDNSRESPONDER_SUPPORTS_APPLE_IGNORE_HOSTS_FILE 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_APPLE_IGNORE_HOSTS_FILE 0
+ #endif
+#endif
+
+// Feature: AWD metrics collection
+// Radar: <rdar://problem/24146300>
+// Enabled: Yes, but for iOS only.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_METRICS)
+ #if !defined(TARGET_OS_IOS)
+ #error "Expected TARGET_OS_IOS to be defined."
+ #endif
+ #if TARGET_OS_IOS
+ #define MDNSRESPONDER_SUPPORTS_APPLE_METRICS 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_APPLE_METRICS 0
+ #endif
+#endif
+
+// Feature: Support for having finer granularity of log redaction, by using os_log based-log routine.
+// Radar: <rdar://problem/42814956>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_OS_LOG)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_OS_LOG 1
+#endif
+
+// Feature: Preallocate mDNSResponder's cache memory. For testing purposes only.
+// Radar: <rdar://problem/29545890>
+// Enabled: No.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_PREALLOCATED_CACHE)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_PREALLOCATED_CACHE 0
+#endif
+
+// Feature: Randomized AWDL Hostname
+// Radar: <rdar://problem/47525004>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_RANDOM_AWDL_HOSTNAME)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_RANDOM_AWDL_HOSTNAME 1
+#endif
+
+// Feature: Reachability trigger
+// Radar: <rdar://problem/11374446>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_REACHABILITY_TRIGGER)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_REACHABILITY_TRIGGER 1
+#endif
+
+// Feature: "SlowActivation" processing for flapping interfaces.
+// Disabled to address stale Bonjour record issues during flapping network interface transitions.
+// Radar: <rdar://problem/44694746>
+// Enabled: No.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_SLOW_ACTIVATION)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_SLOW_ACTIVATION 0
+#endif
+
+// Feature: Suspicious Reply Defense
+// Radar: <rdar://problem/50050767>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_SUSPICIOUS_REPLY_DEFENSE)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_SUSPICIOUS_REPLY_DEFENSE 1
+#endif
+
+// Feature: Symptoms Reporting
+// Radar: <rdar://problem/20194922>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_SYMPTOMS)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_SYMPTOMS 1
+#endif
+
+// Feature: Support for performing dot-local queries via mDNS and DNS in parallel.
+// Radar: <rdar://problem/4786302>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_UNICAST_DOTLOCAL)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_UNICAST_DOTLOCAL 1
+#endif
+
+// Feature: Allow browses and registrations over interfaces that aren't ready yet.
+// Radar: <rdar://problem/20181903>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_UNREADY_INTERFACES)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_UNREADY_INTERFACES 1
+#endif
+
+// Feature: Support for Web Content Filter
+// Radar: <rdar://problem/7409981>
+// Enabled: Yes, if SDK has <WebFilterDNS/WebFilterDNS.h>.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_WEB_CONTENT_FILTER)
+ #if __has_include(<WebFilterDNS/WebFilterDNS.h>)
+ #define MDNSRESPONDER_SUPPORTS_APPLE_WEB_CONTENT_FILTER 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_APPLE_WEB_CONTENT_FILTER 0
+ #endif
+#endif
+
+#endif // __ApplePlatformFeatures_h
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>Project</key>
- <string>mDNSResponder</string>
- <key>RadarComponents</key>
- <dict>
- <key>Name</key>
- <string>mDNSResponder</string>
- <key>Version</key>
- <string>all</string>
- </dict>
- <key>Tests</key>
- <array>
- <dict>
- <key>TestName</key>
- <string>GAIPerf Advanced</string>
- <key>Description</key>
- <string>Tests correctness of resolving hostnames via DNS using the GAIPerf Advanced test suite.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <false/>
- <key>Timeout</key>
- <integer>600</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>gaiperf</string>
- <string>--suite</string>
- <string>advanced</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--skipPathEval</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 1-1-1</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>1</string>
- <string>--txtSize</string>
- <string>1</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>1</string>
- <string>--countAAAA</string>
- <string>1</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 1-1-1 (No Additionals)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records. Responses from mdnsreplier contain no additional answers.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>1</string>
- <string>--txtSize</string>
- <string>1</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>1</string>
- <string>--countAAAA</string>
- <string>1</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--noAdditionals</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 10-100-2</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>10</string>
- <string>--txtSize</string>
- <string>100</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>2</string>
- <string>--countAAAA</string>
- <string>2</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 10-100-2 (No Additionals)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. Responses from mdnsreplier contain no additonal answers.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>10</string>
- <string>--txtSize</string>
- <string>100</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>2</string>
- <string>--countAAAA</string>
- <string>2</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--noAdditionals</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 100-500-5</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>100</string>
- <string>--txtSize</string>
- <string>500</string>
- <string>--browseTime</string>
- <string>5</string>
- <string>--countA</string>
- <string>5</string>
- <string>--countAAAA</string>
- <string>5</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 100-500-5 (No Additionals)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records. Responses from mdnsreplier contain no additonal answers.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>100</string>
- <string>--txtSize</string>
- <string>500</string>
- <string>--browseTime</string>
- <string>5</string>
- <string>--countA</string>
- <string>5</string>
- <string>--countAAAA</string>
- <string>5</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--noAdditionals</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 1-1-1 (No Cache Flush)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records. Cache is not flushed beforehand.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>1</string>
- <string>--txtSize</string>
- <string>1</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>1</string>
- <string>--countAAAA</string>
- <string>1</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 1-1-1 (No Cache Flush, No Additionals)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>1</string>
- <string>--txtSize</string>
- <string>1</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>1</string>
- <string>--countAAAA</string>
- <string>1</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--noAdditionals</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 10-100-2 (No Cache Flush)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. Cache is not flushed beforehand.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>10</string>
- <string>--txtSize</string>
- <string>100</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>2</string>
- <string>--countAAAA</string>
- <string>2</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 10-100-2 (No Cache Flush, No Additionals)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>10</string>
- <string>--txtSize</string>
- <string>100</string>
- <string>--browseTime</string>
- <string>3</string>
- <string>--countA</string>
- <string>2</string>
- <string>--countAAAA</string>
- <string>2</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--noAdditionals</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 100-500-5 (No Cache Flush)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records. Cache is not flushed beforehand.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>100</string>
- <string>--txtSize</string>
- <string>500</string>
- <string>--browseTime</string>
- <string>5</string>
- <string>--countA</string>
- <string>5</string>
- <string>--countAAAA</string>
- <string>5</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery 100-500-5 (No Cache Flush, No Additionals)</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>100</string>
- <string>--txtSize</string>
- <string>500</string>
- <string>--browseTime</string>
- <string>5</string>
- <string>--countA</string>
- <string>5</string>
- <string>--countAAAA</string>
- <string>5</string>
- <string>--ipv4</string>
- <string>--ipv6</string>
- <string>--noAdditionals</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery w/Packet Drops 10</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>30</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>10</string>
- <string>--txtSize</string>
- <string>100</string>
- <string>--browseTime</string>
- <string>16</string>
- <string>--countA</string>
- <string>2</string>
- <string>--countAAAA</string>
- <string>2</string>
- <string>--ipv6</string>
- <string>--udrop</string>
- <string>0.5</string>
- <string>--mdrop</string>
- <string>0.5</string>
- <string>--maxDropCount</string>
- <string>3</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNS Discovery w/Packet Drops 100</string>
- <key>Description</key>
- <string>Tests mDNS discovery and resolution of 100 service instances with 100-byte TXT records and two pairs of A and AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>30</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>mdnsdiscovery</string>
- <string>--instanceCount</string>
- <string>100</string>
- <string>--txtSize</string>
- <string>100</string>
- <string>--browseTime</string>
- <string>18</string>
- <string>--countA</string>
- <string>2</string>
- <string>--countAAAA</string>
- <string>2</string>
- <string>--ipv6</string>
- <string>--udrop</string>
- <string>0.5</string>
- <string>--mdrop</string>
- <string>0.5</string>
- <string>--maxDropCount</string>
- <string>3</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--flushCache</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>DotLocal Queries</string>
- <key>Description</key>
- <string>Tests DNS and mDNS queries for domain names in the local domain.</string>
- <key>AsRoot</key>
- <false/>
- <key>RequiresWiFi</key>
- <true/>
- <key>Timeout</key>
- <integer>40</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>dotlocal</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>TCP Fallback</string>
- <key>Description</key>
- <string>Tests mDNSResponder's TCP fallback mechanism, which is triggered by UDP responses with invalid message IDs that would otherwise be acceptable.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <false/>
- <key>Timeout</key>
- <integer>60</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/local/bin/dnssdutil</string>
- <string>test</string>
- <string>gaiperf</string>
- <string>--suite</string>
- <string>basic</string>
- <string>--format</string>
- <string>json</string>
- <string>--appendNewLine</string>
- <string>--skipPathEval</string>
- <string>--badUDPMode</string>
- </array>
- </dict>
- <dict>
- <key>TestName</key>
- <string>mDNSResponder Leaks</string>
- <key>Description</key>
- <string>Checks mDNSResponder for memory leaks.</string>
- <key>AsRoot</key>
- <true/>
- <key>RequiresWiFi</key>
- <false/>
- <key>Timeout</key>
- <integer>10</integer>
- <key>IgnoreOutput</key>
- <true/>
- <key>Command</key>
- <array>
- <string>/usr/bin/leaks</string>
- <string>mDNSResponder</string>
- </array>
- </dict>
- </array>
-</dict>
-</plist>
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2015-2019 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.
if (!*ptr)
{
- *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
- mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+ *ptr = (requestList_t *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
(*ptr)->type = type;
(*ptr)->flags = flags;
AssignDomainName(&(*ptr)->name, name);
if (!*ptr)
{
- *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
- mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+ *ptr = (responseList_t *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
(*ptr)->peerBloomFilter = peerBloomFilter;
memcpy(& (*ptr)->peerMac, ptrToMAC, sizeof(mDNSEthAddr));
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14205.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14205.2"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="SafariExtensionViewController">
+ <connections>
+ <outlet property="domainBrowserView" destination="37z-K3-tt2" id="lMe-Hz-bIu"/>
+ <outlet property="mainSplitView" destination="j4B-ff-oDf" id="As5-d3-ZaT"/>
+ <outlet property="serviceBrowserView" destination="Z6A-YV-gRJ" id="vPa-V8-NPE"/>
+ <outlet property="view" destination="j4B-ff-oDf" id="Ajs-fF-Ums"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <splitView arrangesAllSubviews="NO" dividerStyle="paneSplitter" id="j4B-ff-oDf">
+ <rect key="frame" x="0.0" y="0.0" width="309" height="200"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <subviews>
+ <customView fixedFrame="YES" id="Z6A-YV-gRJ" customClass="CNServiceBrowserView">
+ <rect key="frame" x="0.0" y="0.0" width="309" height="114"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <connections>
+ <outlet property="delegate" destination="-2" id="Aj5-LX-1WO"/>
+ </connections>
+ </customView>
+ <customView fixedFrame="YES" id="37z-K3-tt2" customClass="CNDomainBrowserView">
+ <rect key="frame" x="0.0" y="124" width="309" height="76"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="YES"/>
+ </userDefinedRuntimeAttributes>
+ <connections>
+ <outlet property="delegate" destination="-2" id="oQE-Gn-Jaw"/>
+ </connections>
+ </customView>
+ </subviews>
+ <holdingPriorities>
+ <real value="250"/>
+ <real value="250"/>
+ </holdingPriorities>
+ <connections>
+ <outlet property="delegate" destination="-2" id="umg-fZ-b72"/>
+ </connections>
+ <point key="canvasLocation" x="-752" y="-484"/>
+ </splitView>
+ </objects>
+</document>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-only</key>
+ <true/>
+ <key>com.apple.security.network.client</key>
+ <true/>
+</dict>
+</plist>
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@protocol CNServiceBrowserViewDelegate;
+
+IB_DESIGNABLE
+
+@interface CNServiceBrowserView : NSView
+
+@property (strong) IBInspectable NSArray * serviceTypes;
+@property (strong) IBInspectable NSDictionary * localizedServiceTypesDictionary;
+@property (weak) IBOutlet id<CNServiceBrowserViewDelegate> delegate;
+
+- (void)newServiceBrowse:(NSArray *)domainPath;
+
+@end
+
+@protocol CNServiceBrowserViewDelegate <NSObject>
+
+@optional
+
+- (void)bonjourServiceSelected:(NSString *)service type:(NSString *)type atDomain:(NSString *)domain;
+- (void)doubleAction:(NSURL *)url;
+
+@end
+
--- /dev/null
+/*
+ * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "CNServiceBrowserView.h"
+#import "CNDomainBrowserPathUtils.h"
+#include <dns_sd.h>
+
+#import <SafariServices/SafariServices.h>
+
+#define SHOW_SERVICETYPE_IF_SEARCH_COUNT 0
+
+const NSString * _CNInstanceKey_fullName = @"fullName";
+const NSString * _CNInstanceKey_name = @"name";
+const NSString * _CNInstanceKey_serviceType = @"serviceType";
+const NSString * _CNInstanceKey_domainPath = @"domainPath";
+const NSString * _CNInstanceKey_resolveUrl = @"resolveUrl";
+const NSString * _CNInstanceKey_resolveInstance = @"resolveInstance";
+
+@interface _DNSServiceRefWrapper : NSObject
+{
+ DNSServiceRef _ref;
+}
+
+- (instancetype)initWithRef:(DNSServiceRef)ref;
+@end
+
+@implementation _DNSServiceRefWrapper
+
+- (instancetype)initWithRef:(DNSServiceRef)ref
+{
+ if( self = [super init] )
+ {
+ _ref = ref;
+ }
+ return( self );
+}
+
+- (void)dealloc
+{
+ if( _ref ) DNSServiceRefDeallocate( _ref );
+}
+
+@end
+
+@implementation NSArray( CaseInsensitiveStringArrayCompare )
+
+- (BOOL)caseInsensitiveStringMatch:(NSArray *)inArray
+{
+ BOOL match = YES;
+
+ if( self.count != [inArray count] ) match = NO; // Nil zero len ok
+ else
+ {
+ NSInteger i = 0;
+ for( NSString * next in self )
+ {
+ NSString * inNext = inArray[i++];
+ if( ![inNext isKindOfClass: [NSString class]] || ![next isKindOfClass: [NSString class]] )
+ {
+ match = NO;
+ break;
+ }
+ else if( [next caseInsensitiveCompare: inNext] != NSOrderedSame )
+ {
+ match = NO;
+ break;
+ }
+ }
+ }
+
+ return( match );
+}
+
+@end
+
+@protocol CNServiceTypeLocalizerDelegate <NSObject>
+@property (strong) NSDictionary * localizedServiceTypesDictionary;
+@end
+
+@interface CNServiceTypeLocalizer : NSValueTransformer
+{
+ id<CNServiceTypeLocalizerDelegate> _delegate;
+}
+- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate;
+
+@end
+
+@implementation CNServiceTypeLocalizer
+
+- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate
+{
+ if( self = [super init] )
+ {
+ _delegate = delegate;
+ }
+ return( self );
+}
+
++ (Class)transformedValueClass
+{
+ return [NSString class];
+}
+
++ (BOOL)allowsReverseTransformation
+{
+ return NO;
+}
+
+- (nullable id)transformedValue:(nullable id)value
+{
+ id result = value;
+
+ if( value && _delegate && [_delegate respondsToSelector: @selector(localizedServiceTypesDictionary)] )
+ {
+ NSString * localizedValue = [_delegate.localizedServiceTypesDictionary objectForKey: value];
+ if( localizedValue ) result = localizedValue;
+ }
+
+ return( result );
+}
+
+@end
+
+@implementation NSBrowser( PathArray )
+
+- (NSArray *)pathArrayToColumn:(NSInteger)column includeSelectedRow:(BOOL)includeSelection
+{
+ NSMutableArray * pathArray = [NSMutableArray array];
+ if( !includeSelection ) column--;
+ for( NSInteger c = 0 ; c <= column ; c++ )
+ {
+ NSBrowserCell *cell = [self selectedCellInColumn: c];
+ if( cell ) [pathArray addObject: [cell stringValue]];
+ }
+
+ return( pathArray );
+}
+
+@end
+
+static void 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 browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context );
+
+@interface CNServiceBrowserView ()
+
+@property (strong) NSTableView * instanceTable;
+@property (strong) NSArrayController * instanceC;
+@property (strong) NSTableColumn * instanceNameColumn;
+@property (strong) NSTableColumn * instanceServiceTypeColumn;
+@property (strong) NSTableColumn * instancePathPopupColumn;
+
+@property (strong) CNServiceTypeLocalizer * serviceTypeLocalizer;
+
+@property (strong) NSArray * currentDomainPath;
+@property (strong) NSMutableArray * instanceRs;
+@property (strong) NSMutableDictionary * instanceD;
+@property (strong) NSMutableArray * instanceA;
+
+@property (strong) dispatch_queue_t instanceBrowseQ;
+
+@end
+
+@implementation CNServiceBrowserView
+
+@synthesize serviceTypes = _serviceTypes;
+
+- (instancetype)initWithFrame:(NSRect)frameRect
+{
+ if( self = [super initWithFrame: frameRect] )
+ {
+ [self commonInit];
+ }
+ return( self );
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)coder
+{
+ if( self = [super initWithCoder: coder] )
+ {
+ [self commonInit];
+ }
+ return( self );
+}
+
+
+- (void)contentViewsInit
+{
+ NSRect frame = self.frame;
+ self.instanceC = [[NSArrayController alloc] init];
+ self.serviceTypeLocalizer = [[CNServiceTypeLocalizer alloc] initWithDelegate: (id<CNServiceTypeLocalizerDelegate>)self];
+
+ // My table view
+ NSTableView * tableView = [[NSTableView alloc] initWithFrame: frame];
+ tableView.columnAutoresizingStyle = NSTableViewFirstColumnOnlyAutoresizingStyle;
+ tableView.allowsColumnReordering = NO;
+ tableView.delegate = (id<NSTableViewDelegate>)self;
+ tableView.doubleAction = @selector( doubleAction:);
+ [tableView bind: NSContentBinding toObject: self.instanceC withKeyPath: @"arrangedObjects" options: nil];
+ self.instanceTable = tableView;
+
+ // Scroll view for table
+ NSScrollView * tableContainer = [[NSScrollView alloc] initWithFrame: frame];
+ tableContainer.autoresizingMask = (NSViewHeightSizable | NSViewWidthSizable);
+ [tableContainer setDocumentView: tableView];
+
+ // Name column
+ NSTableColumn * column = [[NSTableColumn alloc] init];
+ column.resizingMask = (NSTableColumnAutoresizingMask);
+ column.width = frame.size.width / 3;
+ column.minWidth = column.width / 2;
+ NSTextFieldCell * cell = [[NSTextFieldCell alloc] init];
+ cell.truncatesLastVisibleLine = YES;
+ column.dataCell = cell;
+ [column.headerCell setStringValue: NSLocalizedString( @"_dnsBrowser.instances.name", nil )];
+ [column bind: NSValueBinding toObject: self.instanceC withKeyPath: @"arrangedObjects.name" options: nil];
+ [tableView addTableColumn: column];
+ self.instanceNameColumn = column;
+
+ // Service type column
+ column = [[NSTableColumn alloc] init];
+ column.resizingMask = (NSTableColumnNoResizing);
+ column.width = frame.size.width / 3;
+ column.dataCell = [[NSTextFieldCell alloc] init];
+ [column.headerCell setStringValue: NSLocalizedString( @"_dnsBrowser.instances.type", nil )];
+ [column bind: NSValueBinding toObject: self.instanceC withKeyPath: @"arrangedObjects.serviceType" options: @{ NSValueTransformerBindingOption: self.serviceTypeLocalizer }];
+ [tableView addTableColumn: column];
+ self.instanceServiceTypeColumn = column;
+
+ // Path popup column
+ column = [[NSTableColumn alloc] init];
+ column.resizingMask = (NSTableColumnNoResizing);
+ column.width = frame.size.width / 3;
+ NSPopUpButtonCell * popUpCell = [[NSPopUpButtonCell alloc] init];
+ popUpCell.pullsDown = YES;
+ popUpCell.arrowPosition = NSPopUpArrowAtBottom;
+ popUpCell.autoenablesItems = YES;
+ popUpCell.preferredEdge = NSRectEdgeMaxY;
+ popUpCell.bezelStyle = NSBezelStyleTexturedSquare;
+ popUpCell.font = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
+ column.dataCell = popUpCell;
+ [column.headerCell setStringValue: NSLocalizedString( @"_dnsBrowser.instances.domain", nil )];
+ [column bind: NSContentBinding toObject: self.instanceC withKeyPath: @"arrangedObjects.domainPath" options: nil];
+ [tableView addTableColumn: column];
+ self.instancePathPopupColumn = column;
+
+ [self addSubview: tableContainer];
+}
+
+- (void)commonInit
+{
+ self.serviceTypes = @[@"_http._tcp"];
+ self.instanceRs = [NSMutableArray array];
+ self.instanceD = [NSMutableDictionary dictionary];
+ self.instanceA = [NSMutableArray array];
+
+ [self contentViewsInit];
+}
+
+- (void) setServiceTypes:(NSArray *)serviceTypes
+{
+ if( ![_serviceTypes isEqualTo: serviceTypes] )
+ {
+ _serviceTypes = serviceTypes;
+ }
+}
+
+- (NSArray *) serviceTypes
+{
+ return( _serviceTypes );
+}
+
+- (BOOL)foundInstancesWithMoreThanOneServiceType
+{
+ BOOL result = NO;
+
+#if SHOW_SERVICETYPE_IF_SEARCH_COUNT
+ result = (_serviceTypes.count > 1);
+#else
+ if( _instanceD.count )
+ {
+ NSString * serviceType;
+ for( NSDictionary *next in [_instanceD allValues] )
+ {
+ if( !serviceType )
+ {
+ serviceType = next[_CNInstanceKey_serviceType];
+ continue;
+ }
+ else if( [next[_CNInstanceKey_serviceType] caseInsensitiveCompare: serviceType] != NSOrderedSame )
+ {
+ result = YES;
+ break;
+ }
+ }
+ }
+#endif
+
+ return( result );
+}
+
+- (BOOL)foundInstancesInMoreThanCurrentDomainPath
+{
+ BOOL result = NO;
+
+ if( _instanceD.count )
+ {
+ NSArray * selectedPathArray = [[_currentDomainPath reverseObjectEnumerator] allObjects];
+ if( !selectedPathArray.count ) selectedPathArray = [NSArray arrayWithObject: @"local"];
+ for( NSDictionary *next in [_instanceD allValues] )
+ {
+ if( [next[_CNInstanceKey_domainPath] caseInsensitiveStringMatch: selectedPathArray] ) continue;
+ else
+ {
+ result = YES;
+ break;
+ }
+ }
+ }
+
+#if DEBUG_DOMAIN_POPUPS
+ return( YES );
+#else
+ return( result );
+#endif
+}
+
+#pragma mark - Notifications
+
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+ if( _delegate && [_delegate respondsToSelector: @selector(bonjourServiceSelected:type:atDomain:)] &&
+ notification.object == self.instanceTable )
+ {
+ NSTableView * table = (NSTableView *)notification.object;
+ NSDictionary * record = nil;
+ if( table.selectedRow >= 0 && table.selectedRow < (NSInteger)[self.instanceC.content count] ) record = (NSDictionary *)self.instanceC.content[table.selectedRow];
+
+ [_delegate bonjourServiceSelected: record[_CNInstanceKey_name]
+ type: record[_CNInstanceKey_serviceType]
+ atDomain: record ? DomainPathToDNSDomain( [[record[_CNInstanceKey_domainPath] reverseObjectEnumerator] allObjects] ) : nil];
+ }
+}
+
+
+#pragma mark - Delegates
+
+- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
+{
+ (void)tableColumn; // Unused
+ (void)row; // Unused
+ if( tableView == self.instanceTable )
+ {
+ if( [cell isKindOfClass: [NSPopUpButtonCell class]] )
+ {
+ NSPopUpButtonCell * popCell = cell;
+ if( popCell.numberOfItems > 1 ) popCell.arrowPosition = NSPopUpArrowAtBottom;
+ else popCell.arrowPosition = NSPopUpNoArrow;
+ }
+ }
+}
+
+#if 0
+- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn
+{
+}
+#endif
+
+- (void) handleBrowseResults
+{
+ dispatch_async( dispatch_get_main_queue(), ^{
+ [self bonjourBrowserServiceBrowseUpdate: self->_instanceA];
+ });
+}
+
+- (void)bonjourBrowserServiceBrowseUpdate:(NSArray *)services
+{
+ self.instanceC.content = [services sortedArrayUsingComparator: ^( id obj1, id obj2 ) {
+ return (NSComparisonResult)[ obj1[_CNInstanceKey_name] compare: obj2[_CNInstanceKey_name]];
+ }];
+ [self adjustInstancesColumnWidths];
+}
+
+- (void) adjustInstancesColumnWidths
+{
+ self.instanceServiceTypeColumn.hidden = ![self foundInstancesWithMoreThanOneServiceType];
+ self.instancePathPopupColumn.hidden = ![self foundInstancesInMoreThanCurrentDomainPath];
+
+ if( !self.instanceServiceTypeColumn.hidden || !self.instancePathPopupColumn.hidden )
+ {
+ BOOL sizeChanged = NO;
+ CGFloat maxWidthType = 0;
+ CGFloat maxWidthDomain = 0;
+ BOOL needRoomForPopup = NO;
+ NSDictionary * fontAttrType = @{ NSFontAttributeName: ((NSTextFieldCell *)self.instanceServiceTypeColumn.dataCell).font };
+ NSDictionary * fontAttrDomain = @{ NSFontAttributeName: ((NSTextFieldCell *)self.instancePathPopupColumn.dataCell).font };
+
+ for( NSDictionary * next in self.instanceC.content )
+ {
+ NSString * serviceType = [self.serviceTypeLocalizer transformedValue: next[_CNInstanceKey_serviceType]];
+ NSSize nextSize = [serviceType sizeWithAttributes: fontAttrType];
+ maxWidthType = MAX( nextSize.width, maxWidthType );
+
+ NSArray * path = next[_CNInstanceKey_domainPath];
+ nextSize = [path[0] sizeWithAttributes: fontAttrDomain];
+ maxWidthDomain = MAX( nextSize.width, maxWidthDomain );
+ if( path.count > 1 ) needRoomForPopup = YES;
+ }
+
+#define EDGE_GAP 5
+#define POPUP_ARROW 22
+
+ if( !self.instanceServiceTypeColumn.hidden )
+ {
+ maxWidthType += (EDGE_GAP * 2);
+ if( self.instanceServiceTypeColumn.width != maxWidthType )
+ {
+ self.instanceServiceTypeColumn.width = self.instanceServiceTypeColumn.minWidth = self.instanceServiceTypeColumn.maxWidth = maxWidthType;
+ sizeChanged = YES;
+ }
+ }
+
+ if( !self.instancePathPopupColumn.hidden )
+ {
+ maxWidthDomain += (EDGE_GAP * 2) + needRoomForPopup ? POPUP_ARROW : 0;
+ if( self.instancePathPopupColumn.width != maxWidthDomain )
+ {
+ self.instancePathPopupColumn.width = self.instancePathPopupColumn.minWidth = self.instancePathPopupColumn.maxWidth = maxWidthDomain;
+ sizeChanged = YES;
+ }
+ }
+
+ if( sizeChanged )
+ {
+ [self.instancePathPopupColumn.tableView sizeToFit];
+ }
+ }
+}
+
+#pragma mark - Dispatch
+
+static void finalizer( void * context )
+{
+ CNServiceBrowserView *self = (__bridge CNServiceBrowserView *)context;
+// NSLog( @"finalizer: %@", self );
+ (void)CFBridgingRelease( (__bridge void *)self );
+}
+
+#pragma mark - Commands
+
+- (void)doubleAction:(id)sender
+{
+ if( _delegate && [_delegate respondsToSelector: @selector(doubleAction:)] &&
+ sender == self.instanceTable )
+ {
+ NSTableView * table = (NSTableView *)sender;
+ NSDictionary * record = nil;
+ if( table.selectedRow >= 0 && table.selectedRow < (NSInteger)[self.instanceC.content count] ) record = (NSDictionary *)self.instanceC.content[table.selectedRow];
+ [_delegate doubleAction: record[_CNInstanceKey_resolveUrl]];
+ }
+}
+
+- (void)newServiceBrowse:(NSArray *)domainPath
+{
+ if( _serviceTypes.count)
+ {
+ self.instanceC.content = nil;
+ [self browseForServiceTypes: _serviceTypes inDomainPath: domainPath];
+ }
+}
+
+- (void)browseForServiceTypes:(NSArray *)serviceTypes inDomainPath:(NSArray *)domainPath
+{
+ if( serviceTypes.count /*&& domainPath.count*/ )
+ {
+ _serviceTypes = [serviceTypes copy];
+ _currentDomainPath = [domainPath copy];
+
+ NSString * domainStr = DomainPathToDNSDomain( _currentDomainPath );
+
+ [_instanceRs removeAllObjects];
+ if( !_instanceBrowseQ )
+ {
+ self.instanceBrowseQ = dispatch_queue_create( "DNSServiceBrowse", DISPATCH_QUEUE_PRIORITY_DEFAULT );
+ dispatch_set_context( _instanceBrowseQ, (void *)CFBridgingRetain( self ) );
+ dispatch_set_finalizer_f( _instanceBrowseQ, finalizer );
+ }
+
+ dispatch_sync( _instanceBrowseQ, ^{
+ [self->_instanceD removeAllObjects];
+ [self->_instanceA removeAllObjects];
+ });
+
+ DNSServiceErrorType error;
+ DNSServiceRef mainRef;
+ if( (error = DNSServiceCreateConnection( &mainRef )) != 0 )
+ NSLog(@"DNSServiceCreateConnection failed error: %ld", error);
+ else
+ {
+ for( NSString * nextService in _serviceTypes )
+ {
+ DNSServiceRef ref = mainRef;
+ if( (error = DNSServiceBrowse( &ref, kDNSServiceFlagsShareConnection, 0, [nextService UTF8String], [domainStr UTF8String], browseReply, (__bridge void *)self )) != 0 )
+ NSLog(@"DNSServiceBrowse failed error: %ld", error);
+ else
+ {
+ [_instanceRs addObject: [[_DNSServiceRefWrapper alloc] initWithRef: ref]];
+ }
+ }
+ [_instanceRs addObject: [[_DNSServiceRefWrapper alloc] initWithRef: mainRef]];
+ if( !error )
+ {
+ error = DNSServiceSetDispatchQueue( mainRef, _instanceBrowseQ );
+ if( error ) NSLog( @"DNSServiceSetDispatchQueue error: %d", error );
+ }
+ }
+ }
+}
+
+- (void)resolveServiceInstance:(NSMutableDictionary *)record
+{
+ __weak NSDictionary * weakRecord = record;
+ DNSServiceRef ref;
+ DNSServiceErrorType error;
+ NSString * domainPath = DomainPathToDNSDomain( record[_CNInstanceKey_domainPath] );
+
+ if( (error = DNSServiceResolve( &ref, (DNSServiceFlags)0, kDNSServiceInterfaceIndexAny, [record[_CNInstanceKey_name] UTF8String], [record[_CNInstanceKey_serviceType] UTF8String], [domainPath UTF8String], resolveReply, (__bridge void *)weakRecord )) != 0 )
+ {
+ NSLog(@"DNSServiceResolve failed error: %ld", error);
+ }
+ else
+ {
+ record[_CNInstanceKey_resolveInstance] = [[_DNSServiceRefWrapper alloc] initWithRef: ref];
+ error = DNSServiceSetDispatchQueue( ref, _instanceBrowseQ );
+ if( error ) NSLog( @"resolve DNSServiceSetDispatchQueue error: %d", error );
+ }
+}
+
+#pragma mark - Static Callbacks
+
+static void resolveReply( DNSServiceRef sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode,
+ const char *fullname,
+ const char *hosttarget,
+ uint16_t port, /* In network byte order */
+ uint16_t txtLen,
+ const unsigned char *txtRecord,
+ void *context )
+{
+ (void)sdRef; // Unused
+ (void)flags; // Unused
+ (void)interfaceIndex; // Unused
+ (void)errorCode; // Unused
+ (void)fullname; // Unused
+ __weak NSMutableDictionary * record = (__bridge __weak NSMutableDictionary *)context;
+ if( record && hosttarget )
+ {
+ NSURLComponents * urlComponents = [[NSURLComponents alloc] init];
+ urlComponents.scheme = @"http";
+ urlComponents.host = [NSString stringWithUTF8String: hosttarget];
+ if( TXTRecordContainsKey( txtLen, txtRecord, "path" ) )
+ {
+ uint8_t valueLen;
+ const u_char * valuePtr = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen );
+ urlComponents.path = (__bridge_transfer NSString *)CFStringCreateWithBytes( kCFAllocatorDefault, valuePtr, valueLen, kCFStringEncodingUTF8, false );
+ }
+ if( port ) urlComponents.port = [NSNumber numberWithShort: NTOHS( port )];
+ record[_CNInstanceKey_resolveUrl] = urlComponents.URL;
+ }
+}
+
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context )
+{
+ (void)sdRef; // Unused
+ (void)interfaceIndex; // Unused
+ (void)errorCode; // Unused
+ CNServiceBrowserView *self = (__bridge CNServiceBrowserView *)context;
+ char fullNameBuffer[kDNSServiceMaxDomainName];
+ if( DNSServiceConstructFullName( fullNameBuffer, serviceName, regtype, replyDomain ) == kDNSServiceErr_NoError )
+ {
+ NSString *fullName = @(fullNameBuffer);
+ NSString *name = [NSString stringWithUTF8String: serviceName];
+ NSArray *pathArray = DNSDomainToDomainPath( [NSString stringWithUTF8String: replyDomain] );
+
+ if( flags & kDNSServiceFlagsAdd )
+ {
+ BOOL okToAdd = YES;
+ NSString * newServiceType = [[NSString stringWithUTF8String: regtype] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: @"."]];
+ NSString * oldServiceType = [self.instanceD objectForKey: name][_CNInstanceKey_serviceType];
+ if( oldServiceType && ![newServiceType isEqualToString: oldServiceType] )
+ {
+ NSInteger newIndex = [self.serviceTypes indexOfObject: newServiceType];
+ NSInteger oldIndex = [self.serviceTypes indexOfObject: oldServiceType];
+ if( newIndex != NSNotFound && oldIndex != NSNotFound && oldIndex < newIndex ) okToAdd = NO;
+ }
+ if( okToAdd )
+ {
+ NSMutableDictionary * record = [NSMutableDictionary dictionary];
+ record[_CNInstanceKey_fullName] = fullName;
+ record[_CNInstanceKey_name] = name;
+ record[_CNInstanceKey_serviceType] = newServiceType;
+ record[_CNInstanceKey_domainPath] = [[pathArray reverseObjectEnumerator] allObjects];
+ [self.instanceD setObject: record
+ forKey: name];
+ [self resolveServiceInstance: record];
+ }
+ }
+ else
+ {
+ NSString * newServiceType = [[NSString stringWithUTF8String: regtype] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: @"."]];
+ NSDictionary * oldRecord = [self.instanceD objectForKey: name];
+ if( [oldRecord[_CNInstanceKey_serviceType] isEqualToString: newServiceType] )
+ {
+ [self.instanceD removeObjectForKey: name];
+ }
+ }
+
+ if( !(flags & kDNSServiceFlagsMoreComing) )
+ {
+ dispatch_async( dispatch_get_main_queue(), ^{
+ [self.instanceA setArray: [[self.instanceD allValues] sortedArrayUsingComparator: ^( id obj1, id obj2 ) {
+ return (NSComparisonResult)[obj1[_CNInstanceKey_name] compare: obj2[_CNInstanceKey_name] options: NSCaseInsensitiveSearch];
+ }]];
+ [self handleBrowseResults];
+ });
+ }
+ }
+}
+
+@end
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleDisplayName</key>
+ <string>Bonjour Safari Extension</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.1</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+ <key>NSExtension</key>
+ <dict>
+ <key>NSExtensionPointIdentifier</key>
+ <string>com.apple.Safari.extension</string>
+ <key>NSExtensionPrincipalClass</key>
+ <string>SafariExtensionHandler</string>
+ <key>SFSafariToolbarItem</key>
+ <dict>
+ <key>Action</key>
+ <string>Popover</string>
+ <key>Identifier</key>
+ <string>Button</string>
+ <key>Image</key>
+ <string>ToolbarItemIcon.png</string>
+ <key>Label</key>
+ <string>Browse</string>
+ </dict>
+ <key>SFSafariWebsiteAccess</key>
+ <dict>
+ <key>Level</key>
+ <string>All</string>
+ </dict>
+ </dict>
+ <key>NSHumanReadableDescription</key>
+ <string>Bonjour service browsing done correctly!</string>
+</dict>
+</plist>
--- /dev/null
+/*
+ Localizable.strings
+ Domain Browser
+
+ Created by Phil on 1/7/16.
+ Copyright © 2016 Phil. All rights reserved.
+*/
+
+"_dnsBrowser.instances.name" = "Name";
+"_dnsBrowser.instances.type" = "Kind";
+"_dnsBrowser.instances.domain" = "Domain";
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <SafariServices/SafariServices.h>
+
+@interface SafariExtensionHandler : SFSafariExtensionHandler
+
+@end
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "SafariExtensionHandler.h"
+#import "SafariExtensionViewController.h"
+
+//#define SHOW_BROWSE_COUNT 1
+
+#if SHOW_BROWSE_COUNT
+#include <dns_sd.h>
+
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context );
+#endif
+
+@interface SafariExtensionHandler ()
+
+@property (strong) NSMutableDictionary * instanceD;
+#if SHOW_BROWSE_COUNT
+@property (strong) dispatch_queue_t instanceBrowseQ;
+@property (assign) DNSServiceRef instanceRef; // Never released!!!
+#endif
+
+@end
+
+@implementation SafariExtensionHandler
+
+- (instancetype)init
+{
+ if( self = [super init] )
+ {
+#if SHOW_BROWSE_COUNT
+ self.instanceD = [NSMutableDictionary dictionary];
+ [self startInstanceBrowse];
+#endif
+ }
+ return( self );
+}
+
+- (void)validateToolbarItemInWindow:(SFSafariWindow *)window validationHandler:(void (^)(BOOL enabled, NSString *badgeText))validationHandler {
+ // This method will be called whenever some state changes in the passed in window. You should use this as a chance to enable or disable your toolbar item and set badge text.
+ (void)window; // Unused
+ validationHandler(YES, _instanceD.count ? [NSNumber numberWithInteger: _instanceD.count].stringValue : @"");
+}
+
+- (SFSafariExtensionViewController *)popoverViewController {
+ return [SafariExtensionViewController sharedController];
+}
+
+#if SHOW_BROWSE_COUNT
+- (void)startInstanceBrowse
+{
+ if( !_instanceBrowseQ )
+ {
+ self.instanceBrowseQ = dispatch_queue_create( "DNSAllServiceBrowse", DISPATCH_QUEUE_PRIORITY_DEFAULT );
+ dispatch_set_context( _instanceBrowseQ, (void *)CFBridgingRetain( self ) );
+ dispatch_set_finalizer_f( _instanceBrowseQ, finalizer );
+ }
+
+ dispatch_sync( _instanceBrowseQ, ^{
+ [_instanceD removeAllObjects];
+ });
+
+ DNSServiceErrorType error;
+ if( (error = DNSServiceBrowse( &_instanceRef, 0/*no flags*/, 0, @"_http._tcp".UTF8String, "", browseReply, (__bridge void *)self )) != 0 )
+ NSLog(@"DNSServiceBrowse failed error: %ld", error);
+
+ if( !error )
+ {
+ error = DNSServiceSetDispatchQueue( _instanceRef, _instanceBrowseQ );
+ if( error ) NSLog( @"DNSServiceSetDispatchQueue error: %d", error );
+ }
+}
+
+#pragma mark - Dispatch
+
+static void finalizer( void * context )
+{
+ SafariExtensionHandler *self = (__bridge SafariExtensionHandler *)context;
+ NSLog( @"finalizer: %@", self );
+ (void)CFBridgingRelease( (__bridge void *)self );
+}
+
+#pragma mark - DNS callbacks
+
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context )
+{
+ (void)sdRef; // Unused
+ (void)interfaceIndex; // Unused
+ (void)errorCode; // Unused
+ SafariExtensionHandler *self = (__bridge SafariExtensionHandler *)context;
+ char fullNameBuffer[kDNSServiceMaxDomainName];
+ if( DNSServiceConstructFullName( fullNameBuffer, serviceName, regtype, replyDomain ) == kDNSServiceErr_NoError )
+ {
+ NSString *fullName = @(fullNameBuffer);
+
+ if( flags & kDNSServiceFlagsAdd )
+ {
+ [self.instanceD setObject: fullName
+ forKey: fullName];
+ }
+ else
+ {
+ [self.instanceD removeObjectForKey: fullName];
+ }
+ }
+}
+#endif
+
+@end
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <SafariServices/SafariServices.h>
+
+#import "CNServiceBrowserView.h"
+#import "CNDomainBrowserView.h"
+
+@interface SafariExtensionViewController : SFSafariExtensionViewController
+
+@property (weak) IBOutlet NSSplitView * mainSplitView;
+@property (weak) IBOutlet CNServiceBrowserView * serviceBrowserView;
+@property (weak) IBOutlet CNDomainBrowserView * domainBrowserView;
+
++ (SafariExtensionViewController *)sharedController;
+
+@end
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "SafariExtensionViewController.h"
+#import "CNDomainBrowserPathUtils.h"
+
+@interface SafariExtensionViewController ()
+
+@end
+
+@implementation SafariExtensionViewController
+
++ (SafariExtensionViewController *)sharedController {
+ static SafariExtensionViewController *sharedController = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ sharedController = [[SafariExtensionViewController alloc] init];
+ });
+ return sharedController;
+}
+
+- (void)viewWillAppear
+{
+ [super viewWillAppear];
+ [_domainBrowserView startBrowse];
+ [_mainSplitView adjustSubviews];
+}
+
+- (void) viewWillDisappear
+{
+ [super viewWillDisappear];
+ [_domainBrowserView stopBrowse];
+}
+
+#pragma mark - BServiceBrowser Delegates
+
+- (void)bonjourServiceSelected:(NSString *)service type:(NSString *)type atDomain:(NSString *)domain
+{
+ (void)service; // unused
+ (void)type; // unused
+ (void)domain; // unused
+}
+
+- (void)doubleAction:(NSURL *)url
+{
+ if (url)
+ {
+ [SFSafariApplication getActiveWindowWithCompletionHandler:^(SFSafariWindow * _Nullable activeWindow) {
+ [activeWindow openTabWithURL: url makeActiveIfPossible: YES completionHandler:^(SFSafariTab * _Nullable tab) {
+ (void)tab; // Unused
+ }];
+ }];
+ [self dismissPopover];
+ }
+}
+
+#pragma mark - BonjourBrowser Delegates
+
+- (void)domainBrowserDomainUpdate:(NSString *)defaultDomain
+{
+ [_serviceBrowserView newServiceBrowse: DNSDomainToDomainPath(defaultDomain)];
+ if( !_domainBrowserView.selectedDNSDomain.length )
+ {
+ [_mainSplitView setPosition: [_mainSplitView maxPossiblePositionOfDividerAtIndex: 0] ofDividerAtIndex: 0];
+ }
+ else
+ {
+ [_mainSplitView adjustSubviews];
+ [_domainBrowserView showSelectedRow];
+ }
+}
+
+- (void)domainBrowserDomainSelected:(NSString *)domain
+{
+ [_serviceBrowserView newServiceBrowse: DNSDomainToDomainPath(domain)];
+}
+
+#pragma mark - SplitView Delegate
+
+- (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex
+{
+ (void)splitView; // Unused
+#define TOP_MIN 40
+ CGFloat pos;
+ CGFloat bottomMinHeight = [_domainBrowserView minimumHeight];
+
+ if( proposedPosition < TOP_MIN )
+ {
+ pos = TOP_MIN;
+ }
+ else if( proposedPosition < [_mainSplitView maxPossiblePositionOfDividerAtIndex: dividerIndex] - bottomMinHeight )
+ {
+ pos = proposedPosition;
+ }
+ else
+ {
+ pos = [_mainSplitView maxPossiblePositionOfDividerAtIndex: dividerIndex] - bottomMinHeight;
+ }
+
+ // Make sure selected rows stay in view
+ [_domainBrowserView showSelectedRow];
+
+ return( pos );
+}
+
+- (BOOL)splitView:(NSSplitView *)splitView shouldHideDividerAtIndex:(NSInteger)dividerIndex
+{
+ (void)splitView; // Unused
+ (void)dividerIndex; // Unused
+ return( ![_domainBrowserView foundInstanceInMoreThanLocalDomain] );
+}
+
+- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)view
+{
+ (void)splitView; // Unused
+ (void)view; // Unused
+ return YES; // Having this override seems to make some non-wanted resizes to not occur
+}
+
+@end
--- /dev/null
+document.addEventListener("DOMContentLoaded", function(event) {
+ safari.extension.dispatchMessage("Hello World!");
+});
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface AppDelegate : NSObject <NSApplicationDelegate>
+
+
+@end
+
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ // Insert code here to initialize your application
+ (void)aNotification; // Unused
+}
+
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification {
+ // Insert code here to tear down your application
+ (void)aNotification; // Unused
+}
+
+
+@end
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "16x16",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "32x32",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "128x128",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "256x256",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "mac",
+ "size" : "512x512",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="13168.4" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
+ <dependencies>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13168.4"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--Application-->
+ <scene sceneID="JPo-4y-FX3">
+ <objects>
+ <application id="hnw-xV-0zn" sceneMemberID="viewController">
+ <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
+ <items>
+ <menuItem title="Bonjour Browser" id="1Xt-HY-uBw">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Bonjour Browser" systemMenu="apple" id="uQy-DD-JDr">
+ <items>
+ <menuItem title="About Bonjour Browser" id="5kV-Vb-QxS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
+ <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
+ <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
+ <menuItem title="Services" id="NMo-om-nkz">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
+ <menuItem title="Hide Bonjour Browser" keyEquivalent="h" id="Olw-nP-bQN">
+ <connections>
+ <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All" id="Kd2-mp-pUS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
+ <menuItem title="Quit Bonjour Browser" keyEquivalent="q" id="4sb-4s-VLi">
+ <connections>
+ <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="File" id="dMs-cI-mzQ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="File" id="bib-Uj-vzu">
+ <items>
+ <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
+ <connections>
+ <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
+ <connections>
+ <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open Recent" id="tXI-mr-wws">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
+ <items>
+ <menuItem title="Clear Menu" id="vNY-rz-j42">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
+ <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
+ <connections>
+ <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
+ <connections>
+ <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
+ <connections>
+ <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
+ <connections>
+ <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
+ <menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
+ <connections>
+ <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Edit" id="5QF-Oa-p0T">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Edit" id="W48-6f-4Dl">
+ <items>
+ <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
+ <connections>
+ <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
+ <connections>
+ <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
+ <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
+ <connections>
+ <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
+ <connections>
+ <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
+ <connections>
+ <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Delete" id="pa3-QI-u2k">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
+ <connections>
+ <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
+ <menuItem title="Find" id="4EN-yA-p0u">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Find" id="1b7-l0-nxx">
+ <items>
+ <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
+ <connections>
+ <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
+ <connections>
+ <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
+ <items>
+ <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
+ <connections>
+ <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
+ <connections>
+ <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
+ <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Substitutions" id="9ic-FL-obx">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
+ <items>
+ <menuItem title="Show Substitutions" id="z6F-FW-3nz">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
+ <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Quotes" id="hQb-2v-fYv">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Dashes" id="rgM-f4-ycn">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Links" id="cwL-P1-jid">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Data Detectors" id="tRr-pd-1PS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Text Replacement" id="HFQ-gK-NFA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Transformations" id="2oI-Rn-ZJC">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
+ <items>
+ <menuItem title="Make Upper Case" id="vmV-6d-7jI">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Make Lower Case" id="d9M-CD-aMd">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Capitalize" id="UEZ-Bs-lqG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Speech" id="xrE-MZ-jX0">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
+ <items>
+ <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Format" id="jxT-CU-nIS">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Format" id="GEO-Iw-cKr">
+ <items>
+ <menuItem title="Font" id="Gi5-1S-RQB">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
+ <items>
+ <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"/>
+ <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"/>
+ <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"/>
+ <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
+ <connections>
+ <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
+ <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"/>
+ <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"/>
+ <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
+ <menuItem title="Kern" id="jBQ-r6-VK2">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Kern" id="tlD-Oa-oAM">
+ <items>
+ <menuItem title="Use Default" id="GUa-eO-cwY">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use None" id="cDB-IK-hbR">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Tighten" id="46P-cB-AYj">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Loosen" id="ogc-rX-tC1">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Ligatures" id="o6e-r0-MWq">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
+ <items>
+ <menuItem title="Use Default" id="agt-UL-0e3">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use None" id="J7y-lM-qPV">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Use All" id="xQD-1f-W4t">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Baseline" id="OaQ-X3-Vso">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Baseline" id="ijk-EB-dga">
+ <items>
+ <menuItem title="Use Default" id="3Om-Ey-2VK">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Superscript" id="Rqc-34-cIF">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Subscript" id="I0S-gh-46l">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Raise" id="2h7-ER-AoG">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Lower" id="1tx-W0-xDw">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
+ <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
+ <connections>
+ <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
+ <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Text" id="Fal-I4-PZk">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Text" id="d9c-me-L2H">
+ <items>
+ <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
+ <connections>
+ <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
+ <connections>
+ <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Justify" id="J5U-5w-g23">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
+ <connections>
+ <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
+ <menuItem title="Writing Direction" id="H1b-Si-o9J">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
+ <items>
+ <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem id="YGs-j5-SAR">
+ <string key="title"> Default</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
+ </connections>
+ </menuItem>
+ <menuItem id="Lbh-J2-qVU">
+ <string key="title"> Left to Right</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
+ </connections>
+ </menuItem>
+ <menuItem id="jFq-tB-4Kx">
+ <string key="title"> Right to Left</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
+ <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ </menuItem>
+ <menuItem id="Nop-cj-93Q">
+ <string key="title"> Default</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
+ </connections>
+ </menuItem>
+ <menuItem id="BgM-ve-c93">
+ <string key="title"> Left to Right</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
+ </connections>
+ </menuItem>
+ <menuItem id="RB4-Sm-HuC">
+ <string key="title"> Right to Left</string>
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
+ <menuItem title="Show Ruler" id="vLm-3I-IUL">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="View" id="H8h-7b-M4v">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="View" id="HyV-fh-RgO">
+ <items>
+ <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
+ <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
+ <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+ <connections>
+ <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Window" id="aUF-d1-5bR">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
+ <items>
+ <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
+ <connections>
+ <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom" id="R4o-n2-Eq4">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
+ <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Help" id="wpr-3q-Mcd">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
+ <items>
+ <menuItem title="Bonjour Browser Help" keyEquivalent="?" id="FKE-Sm-Kum">
+ <connections>
+ <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ <connections>
+ <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
+ </connections>
+ </application>
+ <customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
+ <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="0.0"/>
+ </scene>
+ <!--Window Controller-->
+ <scene sceneID="R2V-B0-nI4">
+ <objects>
+ <windowController id="B8D-0N-5wS" sceneMemberID="viewController">
+ <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="196" y="240" width="480" height="270"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
+ <connections>
+ <outlet property="delegate" destination="B8D-0N-5wS" id="fUp-Xf-31I"/>
+ </connections>
+ </window>
+ <connections>
+ <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
+ </connections>
+ </windowController>
+ <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="250"/>
+ </scene>
+ <!--View Controller-->
+ <scene sceneID="hIz-AP-VOD">
+ <objects>
+ <viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController">
+ <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
+ <rect key="frame" x="0.0" y="0.0" width="480" height="98"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="f6l-UI-b0D">
+ <rect key="frame" x="18" y="61" width="444" height="17"/>
+ <textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" title="Bonjour Extension is now available in Safari Preferences -> Extensions." id="6Xu-Rw-IYC">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5MO-TQ-SSP">
+ <rect key="frame" x="207" y="13" width="66" height="32"/>
+ <buttonCell key="cell" type="push" title="Quit" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="4ZK-hH-R4H">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="quitApplication:" target="XfG-lQ-9wD" id="hQ6-fO-Ta5"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="f6l-UI-b0D" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="20" symbolic="YES" id="5Ip-jd-yAV"/>
+ <constraint firstAttribute="trailing" secondItem="f6l-UI-b0D" secondAttribute="trailing" constant="20" symbolic="YES" id="8gP-Ct-bgO"/>
+ <constraint firstAttribute="bottom" secondItem="5MO-TQ-SSP" secondAttribute="bottom" constant="20" symbolic="YES" id="DJs-6e-2R0"/>
+ <constraint firstItem="f6l-UI-b0D" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="20" symbolic="YES" id="I3T-04-FFK"/>
+ <constraint firstItem="5MO-TQ-SSP" firstAttribute="centerX" secondItem="m2S-Jp-Qdl" secondAttribute="centerX" id="Vv7-8v-iuF"/>
+ <constraint firstItem="5MO-TQ-SSP" firstAttribute="top" secondItem="f6l-UI-b0D" secondAttribute="bottom" constant="20" symbolic="YES" id="rPC-vd-MAr"/>
+ </constraints>
+ </view>
+ </viewController>
+ <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="75" y="575"/>
+ </scene>
+ </scenes>
+</document>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-only</key>
+ <true/>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+ <key>NSMainStoryboardFile</key>
+ <string>Main</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface ViewController : NSViewController
+
+
+@end
+
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "ViewController.h"
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ // Do any additional setup after loading the view.
+}
+
+
+- (void)setRepresentedObject:(id)representedObject {
+ [super setRepresentedObject:representedObject];
+
+ // Update the view, if already loaded.
+}
+
+- (IBAction)quitApplication:(id)sender
+{
+ (void)sender; // Unused
+ [NSApplication.sharedApplication terminate: sender];
+}
+
+@end
--- /dev/null
+/*
+ *
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, const char * argv[]) {
+ return NSApplicationMain(argc, argv);
+}
if (pRecord == NULL)
{
pRecord = (CStringNode*) Cache.FindwithAddRecord(&nHashValue);
- strcpy(pRecord->m_Value, RecordName.GetBuffer());
+ strlcpy(pRecord->m_Value, RecordName.GetBuffer(), sizeof(pRecord->m_Value));
}
if (pRecord == NULL)
return;
CDeviceNode dummyDevice;
- CDeviceNode *device = &dummyDevice;
+ CDeviceNode *device;
CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
}
BJ_UINT64 nHashValue = 0;
- char deviceOS = '?';
nHashValue = Hash(RecordName.GetBuffer());
CStringShortNode* pRecord = Cache->Find(&nHashValue);
if (pRecord == NULL)
{
pRecord = (CStringShortNode*) Cache->FindwithAddRecord(&nHashValue);
- strcpy(pRecord->m_Value, RecordName.GetBuffer());
+ if (pRecord)
+ strlcpy(pRecord->m_Value, RecordName.GetBuffer(), sizeof(pRecord->m_Value));
}
if (pRecord == NULL)
}
CDeviceNode dummyDevice;
- CDeviceNode *device = &dummyDevice;
+ CDeviceNode *device;
CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
pRecord->m_nBytes += 10 + nBytes;
- deviceOS = device->GetDeviceOS();
device->frameTotal.Increment(m_nFrameCount);
if (pRecord->m_nLastFrameIndex != m_nFrameCount)
m_nDeviceTotaliOSCount = 0;
m_nDeviceTotalOSXCount = 0;
m_DeviceAskingTree.GetDeviceOSTypes(m_DeviceAskingTree.GetRoot(),pIp2NameMap,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount,nDeviceUnknown);
- if (m_DeviceAskingTree.GetCount() != m_nDeviceAskingiOSCount + m_nDeviceAskingOSXCount+nDeviceUnknown)
- {
- nDeviceUnknown = 0;
- }
nDeviceUnknown = 0;
m_DeviceAnsweringTree.GetDeviceOSTypes(m_DeviceAnsweringTree.GetRoot(),pIp2NameMap,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount,nDeviceUnknown);
- if (m_DeviceAnsweringTree.GetCount() != m_nDeviceAnsweringiOSCount + m_nDeviceAnsweringOSXCount+nDeviceUnknown)
- {
- nDeviceUnknown = 0;
- }
nDeviceUnknown = 0;
m_DeviceTotalTree.GetDeviceOSTypes(m_DeviceTotalTree.GetRoot(), pIp2NameMap, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, nDeviceUnknown);
- if (m_DeviceTotalTree.GetCount() != m_nDeviceTotaliOSCount + m_nDeviceTotalOSXCount + nDeviceUnknown)
- {
- nDeviceUnknown = 0;
- }
}
void CStringNode::Print(bool bCursers,bool bDescendingSort,BJ_UINT32 &nIndex, BJ_UINT32 nStartIndex,BJ_UINT32 nEndIndex)
m_nAnswerFrames = pSrc->m_nAnswerFrames;
m_nAnswerFramesiOS = pSrc->m_nAnswerFramesiOS;
m_nAnswerFramesOSX = pSrc->m_nAnswerFramesOSX;
- strcpy(m_Value,pSrc->m_Value);
+ strlcpy(m_Value,pSrc->m_Value,sizeof(m_Value));
m_nDeviceAskingCount = pSrc->m_nDeviceAskingCount;
m_nDeviceAskingiOSCount = pSrc->m_nDeviceAskingiOSCount;
m_nDeviceAskingOSXCount = pSrc->m_nDeviceAskingOSXCount;
m_nFrames = pSrc->m_nFrames;
m_nQuestionFrames = pSrc->m_nQuestionFrames;
m_nAnswerFrames = pSrc->m_nAnswerFrames;
- strcpy(m_Value,pSrc->m_Value);
+ strlcpy(m_Value,pSrc->m_Value,sizeof(m_Value));
m_nDeviceAskingCount = pSrc->m_nDeviceAskingCount;
m_nDeviceAnsweringCount = pSrc->m_nDeviceAnsweringCount;
m_nDeviceTotalCount = pSrc->m_nDeviceTotalCount;
CServiceNode *pNode= m_Cache.FindwithAddRecord(&RecordName);
- if (pNode->pNext == NULL)
+ if ((pNode->pNext == NULL) && nextCollectBy)
pNode->pNext = nextCollectBy->Factory();
- pNode->pNext->Collect(pFrame,nextCollectBy?nextCollectBy->pNext:NULL);
+ if (pNode->pNext)
+ pNode->pNext->Collect(pFrame,nextCollectBy?nextCollectBy->pNext:NULL);
}
}
if (pFrame->m_SourceIPAddress.IsIPv6())
{
- if (pIPv6Next == NULL)
+ if ((pIPv6Next == NULL) && nextCollectBy)
pIPv6Next = nextCollectBy->Factory();
- pIPv6Next->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+ if (pIPv6Next)
+ pIPv6Next->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
}
}
void CollectByIPAddressType::Export(FILE* hFile,BJString sPrevColumns)
//temp
BJ_UINT16 nRdataLen = 0;
- BJ_UINT16 nRdataLen2 = 0;
if (pTemp > m_pEndBuffer)
{
if (nRdataLen > 1024*10)
{
printf("large Rdata ??");
- nRdataLen2 = (pTemp[8] << 8) | pTemp[9];
-
}
// printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,m_dnsItems[ndnsIndex].RecType,nClass,nTTL,m_dnsItems[ndnsIndex].nRdataLen);
pTemp += 10 + pRecord->m_nRdataLen;
BJString& BJString::operator=(const BJString& str)
{
- Set(str.GetBuffer());
+ if (&str != this)
+ Set(str.GetBuffer());
return *this;
}
bool BJString::operator==(const char* str)
BJString temp = buffer;
Create((BJ_UINT32)(strlen(buffer) + strlen(str)));
- strcpy(buffer,temp.GetBuffer());
- strcat(buffer,str);
+ strlcpy(buffer, temp.GetBuffer(), length + 1);
+ strlcat(buffer, str, length + 1);
return *this;
}
BJString& BJString::operator+=(const BJString&str)
len = 250;
Create(len);
if (buffer && str)
- strcpy(buffer, str);
+ strlcpy(buffer, str, length + 1);
}
void BJString::Set(const char* str, BJ_UINT32 len)
BJString temp = buffer;
Create((BJ_UINT32)(strlen(buffer) + strlen(str)));
if (buffer && temp.buffer)
- strcpy(buffer,temp.GetBuffer());
+ strlcpy(buffer, temp.GetBuffer(), length + 1);
}
strncat(buffer,str,len);
}
void BJString::Create(BJ_UINT32 len)
{
- if (length >= len)
- {
- if (length > 0)
- memset(buffer, 0, len+1);
- return;
- }
-
if (buffer)
{
+ if (length >= len)
+ {
+ memset(buffer, 0, len + 1);
+ return;
+ }
delete buffer;
buffer = NULL;
length = 0;
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2011-2019 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.
#include "DNSSECSupport.h"
#if TARGET_OS_IPHONE
-#include "SecRSAKey.h" // For RSA_SHA1 etc. verification
+#include <Security/SecRSAKey.h> // For RSA_SHA1 etc. verification
#else
#include <Security/Security.h>
#endif
{
case ENC_BASE32:
case ENC_BASE64:
- ptr = (encContext *)mDNSPlatformMemAllocate(sizeof(encContext));
+ ptr = (encContext *) mDNSPlatformMemAllocateClear(sizeof(*ptr));
if (!ptr) return mStatus_NoMemoryErr;
break;
default:
switch (ctx->alg)
{
case SHA1_DIGEST_TYPE:
- ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
+ ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
if (!ptr) return mStatus_NoMemoryErr;
CC_SHA1_Init((CC_SHA1_CTX *)ptr);
break;
case SHA256_DIGEST_TYPE:
- ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
+ ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
if (!ptr) return mStatus_NoMemoryErr;
CC_SHA256_Init((CC_SHA256_CTX *)ptr);
break;
{
case CRYPTO_RSA_NSEC3_SHA1:
case CRYPTO_RSA_SHA1:
- ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
+ ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
if (!ptr) return mStatus_NoMemoryErr;
CC_SHA1_Init((CC_SHA1_CTX *)ptr);
break;
case CRYPTO_RSA_SHA256:
- ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
+ ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
if (!ptr) return mStatus_NoMemoryErr;
CC_SHA256_Init((CC_SHA256_CTX *)ptr);
break;
case CRYPTO_RSA_SHA512:
- ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
+ ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
if (!ptr) return mStatus_NoMemoryErr;
CC_SHA512_Init((CC_SHA512_CTX *)ptr);
break;
}
CFBooleanRef boolRef = SecTransformExecute(verifyXForm, &error);
- ret = boolRef ? CFBooleanGetValue(boolRef) : false;
- if (boolRef) CFRelease(boolRef);
+ ret = (boolRef != NULL) ? CFBooleanGetValue(boolRef) : false;
+ if (boolRef != NULL) CFRelease(boolRef);
CFRelease(verifyXForm);
if (error != NULL)
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
-D2DStatus D2DTerminate() __attribute__((weak_import));
+D2DStatus D2DTerminate(void) __attribute__((weak_import));
#pragma mark - D2D Support
if (!*ptr)
{
- *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
- mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+ *ptr = (D2DBrowseListElem *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
(*ptr)->type = type;
AssignDomainName(&(*ptr)->name, name);
}
LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r));
}
- *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
+ *D2DListp = (D2DRecordListElem *) mDNSPlatformMemAllocateClear(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
if (!*D2DListp) return mStatus_NoMemoryErr;
AuthRecord *rr = &(*D2DListp)->ar;
}
}
+mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags)
+{
+ // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
+ if ( (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger)))
+ || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE))
+ && IsLocalDomain(domain))
+ {
+ return mDNStrue;
+ }
+ else
+ return mDNSfalse;
+}
+
+// Used to derive the original D2D specific flags specified by the client in the registration
+// when we don't have access to the original flag (kDNSServiceFlags*) values.
+mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
+{
+ mDNSu32 flags = 0;
+ if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
+ flags |= kDNSServiceFlagsIncludeP2P;
+ else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
+ flags |= kDNSServiceFlagsIncludeAWDL;
+ return flags;
+}
+
void initializeD2DPlugins(mDNS *const m)
{
// We only initialize if mDNSCore successfully initialized.
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2018 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.
void xD2DAddToCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
void xD2DRemoveFromCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
+extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags);
+extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
+extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
+extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
+extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
+extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
+extern void external_connection_release(const domainname *instance);
+
+extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface);
+extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface);
+extern void D2D_start_advertising_record(AuthRecord *ar);
+extern void D2D_stop_advertising_record(AuthRecord *ar);
+
#if ENABLE_BLE_TRIGGERED_BONJOUR
// Just define as the current max value for now for BLE.c prototype.
// TODO: Will need to define in DeviceToDeviceManager.framework if we convert the
* limitations under the License.
*/
-#include <TargetConditionals.h>
-
-// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
-
-#if TARGET_OS_IOS
#include "DNS64.h"
-#include <AssertMacros.h>
-
-#if __has_include(<nw/private.h>)
- #include <nw/private.h>
-#else
- #include <network/nat64.h>
-#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
+#include <AssertMacros.h>
+#include <nw/private.h>
#include <stdlib.h>
#include <string.h>
#include "dns_sd.h"
#include "dns_sd_internal.h"
+#include "mDNSMacOSX.h"
#include "uDNS.h"
//===========================================================================================================================
// Local Prototypes
//===========================================================================================================================
-mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
-mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
-mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr);
-mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void);
-mDNSlocal void DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
-mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr);
+mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
+mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
+mDNSlocal mDNSBool _DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr);
+mDNSlocal mDNSu32 _DNS64IPv4OnlyFQDNHash(void);
+mDNSlocal void _DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
+mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex);
+mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr);
//===========================================================================================================================
// DNS64StateMachine
if ((inQ->qtype == kDNSType_AAAA) &&
(inRR->rrtype == kDNSType_AAAA) &&
(inRR->rrclass == kDNSClass_IN) &&
- ((inQ->qnamehash != DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
+ ((inQ->qnamehash != _DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
inQ->qDNSServer &&
- nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface))
+ _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)))
{
- DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
+ _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
return (mDNStrue);
}
else if ((inQ->qtype == kDNSType_PTR) &&
(inRR->rrtype == kDNSType_PTR) &&
(inRR->rrclass == kDNSClass_IN) &&
inQ->qDNSServer &&
- nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface) &&
- DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
+ _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)) &&
+ _DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
{
- DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
+ _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
return (mDNStrue);
}
}
(inRR->rrtype == kDNSType_AAAA) &&
(inRR->rrclass == kDNSClass_IN))
{
- DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
+ _DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
return (mDNStrue);
}
else
{
- DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
+ _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
return (mDNStrue);
}
break;
// whether or not to change it to a reverse IPv4 question.
case kDNS64State_PrefixDiscoveryPTR:
- DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
+ _DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
return (mDNStrue);
break;
(inRR->rrtype == kDNSType_A) &&
(inRR->rrclass == kDNSClass_IN) &&
inQ->qDNSServer &&
- DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
+ _DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
{
inQ->dns64.state = kDNS64State_QueryA2;
}
else
{
- DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
+ _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
return (mDNStrue);
}
}
require_action_quiet(q->qDNSServer, exit, err = mStatus_BadParamErr);
- err = DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
+ err = _DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
require_noerr_quiet(err, exit);
newRR = *inRR;
struct in6_addr v6Addr;
inQ->dns64.state = kDNS64State_ReverseIPv6;
- if (inQ->qDNSServer && DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
+ if (inQ->qDNSServer && _DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
{
mStatus err;
nw_nat64_prefix_t * prefixes;
struct in_addr v4Addr;
char qnameStr[MAX_REVERSE_MAPPING_NAME_V4];
- err = DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
+ err = _DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
require_noerr_quiet(err, exit);
for (i = 0; i < prefixCount; i++)
if (q->dns64.state != kDNS64State_Initial)
{
SetValidDNSServers(m, q);
- q->triedAllServersOnce = 0;
+ q->triedAllServersOnce = mDNSfalse;
newServer = GetServerForQuestion(m, q);
if (q->qDNSServer != newServer)
{
}
//===========================================================================================================================
-// DNS64GetIPv6Addrs
+// _DNS64GetIPv6Addrs
//===========================================================================================================================
#define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID) \
((RR)->RecordType != kDNSRecordTypePacketNegative) && \
!(RR)->InterfaceID)
-mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
+mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
{
mStatus err;
const CacheGroup * cg;
uint32_t addrCount;
uint32_t recordCount;
- cg = CacheGroupForName(m, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
+ cg = CacheGroupForName(m, _DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
require_action_quiet(cg, exit, err = mStatus_NoSuchRecord);
recordCount = 0;
}
//===========================================================================================================================
-// DNS64GetPrefixes
+// _DNS64GetPrefixes
//===========================================================================================================================
-mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
+mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
{
mStatus err;
struct in6_addr * v6Addrs;
nw_nat64_prefix_t * prefixes;
int32_t prefixCount;
- err = DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
+ err = _DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
require_noerr_quiet(err, exit);
prefixCount = nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs, v6AddrCount, &prefixes);
}
//===========================================================================================================================
-// DNS64GetReverseIPv6Addr
+// _DNS64GetReverseIPv6Addr
//===========================================================================================================================
#define kReverseIPv6Domain ((const domainname *) "\x3" "ip6" "\x4" "arpa")
-mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
+mDNSlocal mDNSBool _DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
{
const mDNSu8 * ptr;
int i;
}
//===========================================================================================================================
-// DNS64IPv4OnlyFQDNHash
+// _DNS64IPv4OnlyFQDNHash
//===========================================================================================================================
-mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void)
+mDNSlocal mDNSu32 _DNS64IPv4OnlyFQDNHash(void)
{
static dispatch_once_t sHashOnce;
static mDNSu32 sHash;
}
//===========================================================================================================================
-// DNS64RestartQuestion
+// _DNS64RestartQuestion
//===========================================================================================================================
-mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
+mDNSlocal void _DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
{
mDNS_StopQuery_internal(m, inQ);
memcpy(inQ->dns64.qnameStash, &inQ->qname, sizeof(inQ->dns64.qnameStash));
AssignDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN);
- inQ->qnamehash = DNS64IPv4OnlyFQDNHash();
+ inQ->qnamehash = _DNS64IPv4OnlyFQDNHash();
inQ->qtype = kDNSType_AAAA;
break;
}
//===========================================================================================================================
-// DNS64TestIPv6Synthesis
+// _DNS64InterfaceSupportsNAT64
+//===========================================================================================================================
+
+mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex)
+{
+ mdns_interface_monitor_t monitor = GetInterfaceMonitorForIndex(inIfIndex);
+ if (monitor && !mdns_interface_monitor_has_ipv4_connectivity(monitor) &&
+ mdns_interface_monitor_has_ipv6_connectivity(monitor))
+ {
+ return (mDNStrue);
+ }
+ return (mDNSfalse);
+}
+
+//===========================================================================================================================
+// _DNS64TestIPv6Synthesis
//===========================================================================================================================
-mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
+mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
{
mStatus err;
nw_nat64_prefix_t * prefixes = NULL;
struct in6_addr synthV6;
mDNSBool result = mDNSfalse;
- err = DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
+ err = _DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
require_noerr_quiet(err, exit);
memcpy(&v4Addr.s_addr, inV4Addr->b, 4);
if (prefixes) free(prefixes);
return (result);
}
-#endif // TARGET_OS_IOS
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2011-2019 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.
#include <sys/event.h>
#include <netinet/tcp.h>
-mDNSexport mDNS mDNSStorage;
+extern mDNS mDNSStorage;
#define ValidSocket(s) ((s) >= 0)
return -1;
}
- tcpInfo->reply = mallocL("ProxyTCPInfo", tcpInfo->replyLen);
+ tcpInfo->reply = (DNSMessage *) mallocL("ProxyTCPInfo", tcpInfo->replyLen);
if (!tcpInfo->reply)
{
LogMsg("ProxyTCPRead: Memory failure");
mDNSIPPort senderPort;
ProxyTCPInfo_t *ti = (ProxyTCPInfo_t *)context;
TCPSocket *sock = &ti->sock;
- KQSocketSet *kq = &sock->ss;
struct tcp_info tcp_if;
socklen_t size = sizeof(tcp_if);
int32_t intf_id = 0;
return;
}
// We read all the data and hence not interested in read events anymore
- KQueueSet(s1, EV_DELETE, EVFILT_READ, sock->kqEntry);
+ KQueueSet(s1, EV_DELETE, EVFILT_READ, &sock->kqEntry);
mDNSPlatformMemZero(&to, sizeof(to));
mDNSPlatformMemZero(&from, sizeof(from));
// We pass sock for the TCPSocket and the "ti" for context as that's what we want to free at the end.
// In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument)
// would be NULL.
- kq->m->p->TCPProxyCallback(sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
+ ti->sock.m->p->TCPProxyCallback(sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
UnicastDNSPort, (mDNSInterfaceID)(uintptr_t)intf_id, ti);
}
struct sockaddr_storage ss;
socklen_t sslen = sizeof(ss);
const int on = 1;
- KQSocketSet *listenSet = (KQSocketSet *)context;
+ TCPSocket *listenSock = (TCPSocket *)context;
(void) filter;
while ((newfd = accept(s1, (struct sockaddr *)&ss, &sslen)) != -1)
{
int err;
- int *s;
- KQueueEntry *k;
- KQSocketSet *kq;
// Even though we just need a single KQueueEntry, for simplicity we re-use
// the KQSocketSet
- ProxyTCPInfo_t *ti = mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t));
+ ProxyTCPInfo_t * const ti = (ProxyTCPInfo_t *)callocL("ProxyTCPContext", sizeof(*ti));
if (!ti)
{
LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
close(newfd);
return;
}
- mDNSPlatformMemZero(ti, sizeof(ProxyTCPInfo_t));
-
- TCPSocket *sock = &ti->sock;
-
- kq = &sock->ss;
- kq->sktv4 = -1;
- kq->sktv6 = -1;
- kq->m = listenSet->m;
+ TCPSocket * const sock = &ti->sock;
+ sock->fd = -1;
+ sock->m = listenSock->m;
fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
if (ss.ss_family == AF_INET)
{
- s = &kq->sktv4;
- k = &kq->kqsv4;
// Receive interface identifiers
err = setsockopt(newfd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
if (err)
}
else
{
- s = &kq->sktv6;
- k = &kq->kqsv6;
// We want to receive destination addresses and receive interface identifiers
err = setsockopt(newfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
if (err)
return;
}
}
- *s = newfd;
// mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
// from which we can infer the destination address family. Hence we need to remember that here.
// Instead of remembering the address family, we remember the right fd.
sock->fd = newfd;
- sock->kqEntry = k;
- k->KQcallback = ProxyTCPSocketCallBack;
- k->KQcontext = ti;
- k->KQtask = "TCP Proxy packet reception";
+ sock->kqEntry.KQcallback = ProxyTCPSocketCallBack;
+ sock->kqEntry.KQcontext = ti;
+ sock->kqEntry.KQtask = "TCP Proxy packet reception";
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- k->readSource = mDNSNULL;
- k->writeSource = mDNSNULL;
- k->fdClosed = mDNSfalse;
+ sock->kqEntry.readSource = mDNSNULL;
+ sock->kqEntry.writeSource = mDNSNULL;
+ sock->kqEntry.fdClosed = mDNSfalse;
#endif
- KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+ sock->connected = mDNStrue;
+ sock->m = listenSock->m;
+ KQueueSet(newfd, EV_ADD, EVFILT_READ, &sock->kqEntry);
}
}
return(err);
}
-mDNSlocal mStatus SetupTCPProxySocket(int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
+mDNSlocal mStatus SetupTCPProxySocket(int skt, TCPSocket *sock, u_short sa_family, mDNSBool useBackgroundTrafficClass)
{
- int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
- KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
mStatus err;
-
- cp->m = &mDNSStorage;
- // XXX may not be used by the TCP codepath
- cp->closeFlag = mDNSNULL;
+ mDNS *m = &mDNSStorage;
// for TCP sockets, the traffic class is set once and not changed
// setTrafficClass(skt, useBackgroundTrafficClass);
(void) useBackgroundTrafficClass;
+ (void) sa_family;
// All the socket setup has already been done
err = listen(skt, NUM_PROXY_TCP_CONNS);
}
fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
- *s = skt;
- k->KQcallback = ProxyTCPAccept;
- k->KQcontext = cp;
- k->KQtask = "TCP Accept";
+ sock->fd = skt;
+ sock->kqEntry.KQcallback = ProxyTCPAccept;
+ sock->kqEntry.KQcontext = sock;
+ sock->kqEntry.KQtask = "TCP Accept";
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- k->readSource = mDNSNULL;
- k->writeSource = mDNSNULL;
- k->fdClosed = mDNSfalse;
+ sock->kqEntry.readSource = mDNSNULL;
+ sock->kqEntry.writeSource = mDNSNULL;
+ sock->kqEntry.fdClosed = mDNSfalse;
#endif
- KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+ sock->m = m;
+ KQueueSet(skt, EV_ADD, EVFILT_READ, &sock->kqEntry);
return mStatus_NoError;
}
mDNSlocal void SetupDNSProxySkts(int fd[4])
{
mDNS *const m = &mDNSStorage;
- int i;
+ int i;
mStatus err;
KQSocketSet *udpSS;
- KQSocketSet *tcpSS;
+ TCPSocket *v4, *v6;
udpSS = &m->p->UDPProxy.ss;
- tcpSS = &m->p->TCPProxy.ss;
udpSS->port = UnicastDNSPort;
- tcpSS->port = UnicastDNSPort;
+ v4 = &m->p->TCPProxyV4;
+ v6 = &m->p->TCPProxyV6;
+ v4->m = m;
+ v4->port = UnicastDNSPort;
+ v6->m = m;
+ v6->port = UnicastDNSPort;
LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd[0], fd[1], fd[2], fd[3]);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
- err = SetupTCPProxySocket(fd[2], tcpSS, AF_INET, mDNSfalse);
+ err = SetupTCPProxySocket(fd[2], v4, AF_INET, mDNSfalse);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
- err = SetupTCPProxySocket(fd[3], tcpSS, AF_INET6, mDNSfalse);
+ err = SetupTCPProxySocket(fd[3], v6, AF_INET6, mDNSfalse);
if (err)
LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
{
ProxyTCPInfo_t *ti;
TCPSocket *sock;
- KQSocketSet *kq;
if (!context)
return;
ti = (ProxyTCPInfo_t *)context;
sock = &ti->sock;
- kq = &sock->ss;
- if (kq->sktv4 != -1)
- {
- shutdown(kq->sktv4, 2);
- mDNSPlatformCloseFD(&kq->kqsv4, kq->sktv4);
- }
- if (kq->sktv6 != -1)
+ if (sock->fd >= 0)
{
- shutdown(kq->sktv6, 2);
- mDNSPlatformCloseFD(&kq->kqsv6, kq->sktv6);
+ mDNSPlatformCloseFD(&sock->kqEntry, sock->fd);
+ sock->fd = -1;
}
- if (kq->closeFlag)
- *kq->closeFlag = 1;
if (ti->reply)
freeL("ProxyTCPInfoLen", ti->reply);
freeL("ProxyTCPContext", ti);
}
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2012-2019 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.
tmp = tmp->next;
}
- ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
+ ta = (TrustAnchor *) mDNSPlatformMemAllocateClear(sizeof(*ta));
if (!ta)
{
LogMsg("AddTrustAnchor: malloc failure ta");
LogMsg("ConvertDigest: digest type %d not supported", digestType);
return mDNSNULL;
}
- dig = mDNSPlatformMemAllocate(*diglen);
+ dig = (mDNSu8 *) mDNSPlatformMemAllocate(*diglen);
if (!dig)
{
LogMsg("ConvertDigest: malloc failure");
(void) m;
- TrustAnchor *ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
+ TrustAnchor *ta = (TrustAnchor *) mDNSPlatformMemAllocateClear(sizeof(*ta));
if (!ta)
{
LogMsg("FetchRootTA: TrustAnchor alloc failed");
return;
}
- memset(ta, 0, sizeof(TrustAnchor));
url = CFURLCreateWithString(NULL, urlString, NULL);
if (!url)
char *digest = "F122E47B5B7D2B6A5CC0A21EADA11D96BB9CC927";
mDNSu8 *dig = ConvertDigest(digest, 1, &diglen);
- AddTrustAnchor(m, testZone, 23044, 5, 1, diglen, dig);
+ if (dig) AddTrustAnchor(m, testZone, 23044, 5, 1, diglen, dig);
char *digest1 = "D795AE5E1AFB200C6139474199B70EAD3F3484553FD97BE5A43704B8A4791F21";
dig = ConvertDigest(digest1, 2, &diglen);
- AddTrustAnchor(m, testZone, 23044, 5, 2, diglen, dig);
+ if (dig) AddTrustAnchor(m, testZone, 23044, 5, 2, diglen, dig);
// Add the TA for root zone manually here. We will dynamically fetch the root TA and
// update it shortly. If that fails e.g., disconnected from the network, we still
// have something to work with.
char *digest2 = "49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5";
dig = ConvertDigest(digest2, 2, &diglen);
- AddTrustAnchor(m, (const domainname *)"\000", 19036, 8, 2, diglen, dig);
+ if (dig) AddTrustAnchor(m, (const domainname *)"\000", 19036, 8, 2, diglen, dig);
#if !TARGET_OS_IPHONE
DNSSECProbeQuestion.ThisQInterval = -1;
- (void)startBrowser;
- (void)stopBrowser;
+- (BOOL)foundInstanceInMoreThanLocalDomain;
+
@property (readonly) NSArray * defaultDomainPath;
@property (readonly) NSArray * flattenedDNSDomains;
@implementation _CNDomainBrowser
-void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
+static void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
- (instancetype)initWithDelegate:(id<_CNDomainBrowserDelegate>)delegate
{
dispatch_set_finalizer_f(queue, finalizer);
DNSServiceRef ref;
- if (DNSServiceEnumerateDomains(&ref, _browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self))
- NSLog(@"DNSServiceEnumerateDomains failed");
+ DNSServiceErrorType error;
+ if ((error = DNSServiceEnumerateDomains(&ref, self->_browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self)) != 0)
+ NSLog(@"DNSServiceEnumerateDomains failed err: %ld", error);
else
{
- _browseDomainR = ref;
- (void)DNSServiceSetDispatchQueue(_browseDomainR, queue);
+ self->_browseDomainR = ref;
+ (void)DNSServiceSetDispatchQueue(self->_browseDomainR, queue);
}
});
}
}
}
+- (BOOL)foundInstanceInMoreThanLocalDomain
+{
+ BOOL result = YES;
+
+ if( self.browseDomainD.count )
+ {
+ for( NSDictionary *next in [self.browseDomainD allValues] )
+ {
+ if( [next[_CNSubDomainKey_reverseDomainPath][0] isEqual: @"local"] ) continue;
+ else
+ {
+ result = YES;
+ break;
+ }
+ }
+ }
+
+ return( result );
+}
+
- (NSArray *)defaultDomainPath
{
NSArray * revDomainArray = nil;
if ([_delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
{
dispatch_async(self.callbackQueue, ^{
- [_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
+ [self->_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
});
}
}
static void finalizer(void * context)
{
_CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
- NSLog(@"finalizer: %@", self);
+// NSLog(@"finalizer: %@", self);
(void)CFBridgingRelease((__bridge void *)self);
}
#pragma mark - Static Callbacks
-void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+static void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *replyDomain, void *context)
{
(void)sdRef;
_CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
NSString *key = [NSString stringWithUTF8String: replyDomain];
- if (self.ignoreLocal && [key isEqualToString: @"local."]) return;
- if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."]) return;
+ if (self.ignoreLocal && [key isEqualToString: @"local."]) goto exit;
+ if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."]) goto exit;
if (!(flags & kDNSServiceFlagsAdd))
{
_CNSubDomainKey_defaultFlag: (flags & kDNSServiceFlagsDefault) ? @YES : @NO }
forKey: key];
}
-
+
+exit:
if (!(flags & kDNSServiceFlagsMoreComing))
{
[self reloadBrowser];
- (void)startBrowse;
- (void)stopBrowse;
+- (CGFloat)minimumHeight;
+- (void)showSelectedRow;
+- (BOOL)foundInstanceInMoreThanLocalDomain;
+
@end
@protocol CNDomainBrowserViewDelegate <NSObject>
@optional
-- (void)bonjourBrowserDomainSelected:(NSString *)domain;
-- (void)bonjourBrowserDomainUpdate:(NSString *)defaultDomain;
+- (void)domainBrowserDomainSelected:(NSString *)domain;
+- (void)domainBrowserDomainUpdate:(NSString *)defaultDomain;
@end
#import "_CNDomainBrowser.h"
#import "CNDomainBrowserPathUtils.h"
-#define DEBUG_POPUP_CELLS 0
-#define SHOW_SERVICETYPE_IF_SEARCH_COUNT 0
-#define TEST_LEGACYBROWSE 0
-
#define BROWSER_CELL_SPACING 4
-
-@protocol CNServiceTypeLocalizerDelegate <NSObject>
-@property (strong) NSDictionary * localizedServiceTypesDictionary;
-@end
-
-@interface CNServiceTypeLocalizer : NSValueTransformer
-{
- id<CNServiceTypeLocalizerDelegate> _delegate;
-}
-- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate;
-
-@end
-
-@implementation CNServiceTypeLocalizer
-
-- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate
-{
- if (self = [super init])
- {
- _delegate = delegate;
- }
- return(self);
-}
-
-+ (Class)transformedValueClass
-{
- return [NSString class];
-}
-
-+ (BOOL)allowsReverseTransformation
-{
- return NO;
-}
-
-- (nullable id)transformedValue:(nullable id)value
-{
- id result = value;
-
- if (value && _delegate && [_delegate respondsToSelector: @selector(localizedServiceTypesDictionary)])
- {
- NSString * localizedValue = [_delegate.localizedServiceTypesDictionary objectForKey: value];
- if (localizedValue) result = localizedValue;
- }
-
- return(result);
-}
-
-@end
+#define INITIAL_LEGACYBROWSE 1
@implementation NSBrowser(PathArray)
@interface CNDomainBrowserView ()
@property (strong) _CNDomainBrowser * bonjour;
-@property (strong) NSSplitView * mainSplitView;
@property (strong) NSTableView * instanceTable;
@property (strong) NSArrayController * instanceC;
@property (strong) NSTableColumn * instancePathPopupColumn;
@property (strong) NSBrowser * browser;
-
-@property (strong) CNServiceTypeLocalizer * serviceTypeLocalizer;
+#if INITIAL_LEGACYBROWSE
+@property (assign) BOOL initialPathSet;
+#endif
@end
{
NSRect frame = self.frame;
self.instanceC = [[NSArrayController alloc] init];
- self.serviceTypeLocalizer = [[CNServiceTypeLocalizer alloc] initWithDelegate: (id<CNServiceTypeLocalizerDelegate>)self];
-
+
// Bottom browser
frame.origin.x = frame.origin.y = 0;
NSBrowser * browserView = [[NSBrowser alloc] initWithFrame: frame];
browserView.hasHorizontalScroller = YES;
browserView.columnResizingType = NSBrowserNoColumnResizing;
browserView.minColumnWidth = 50;
+ browserView.translatesAutoresizingMaskIntoConstraints = NO;
self.browser = browserView;
[self addSubview: browserView];
+
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:_browser
+ attribute:NSLayoutAttributeLeft
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeLeft
+ multiplier:1
+ constant:0]];
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:_browser
+ attribute:NSLayoutAttributeRight
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeRight
+ multiplier:1
+ constant:0]];
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:_browser
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeBottom
+ multiplier:1
+ constant:0]];
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:_browser
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeTop
+ multiplier:1
+ constant:0]];
}
- (void)commonInit
[self contentViewsInit];
}
-- (void)viewWillMoveToWindow:(NSWindow *)newWindow
+- (void)viewWillMoveToSuperview:(NSView *)newSuperview
{
- [super viewWillMoveToWindow: newWindow];
- if (newWindow)
+ [super viewWillMoveToSuperview: newSuperview];
+ if (newSuperview && !_bonjour)
{
- [self.mainSplitView adjustSubviews];
+ [self awakeFromNib];
}
}
- (void)stopBrowse
{
[self.bonjour stopBrowser];
+ _initialPathSet = NO;
}
- (BOOL)isBrowsing
return(self.bonjour.isBrowsing);
}
+- (CGFloat)minimumHeight
+{
+ return self.selectedDNSDomain.length ? [self.browser frameOfRow: [self.browser selectedRowInColumn: self.browser.lastVisibleColumn] inColumn: self.browser.lastVisibleColumn].size.height : 0.0;
+}
+
+- (void)showSelectedRow
+{
+ for( NSInteger i = self.browser.firstVisibleColumn ; i <= self.browser.lastVisibleColumn ; i++ )
+ {
+ NSInteger selRow = [self.browser selectedRowInColumn: i];
+ if( selRow != NSNotFound ) [self.browser scrollRowToVisible: selRow inColumn: i];
+ }
+}
+
+- (BOOL)foundInstanceInMoreThanLocalDomain
+{
+ return( [_bonjour foundInstanceInMoreThanLocalDomain] );
+}
+
+
#pragma mark - Notifications
- (void)browser:(NSBrowser *)sender selectionDidChange:(NSArray *)pathArray
{
- if (_delegate && [_delegate respondsToSelector: @selector(bonjourBrowserDomainSelected:)] &&
+ if (_delegate && [_delegate respondsToSelector: @selector(domainBrowserDomainSelected:)] &&
sender == self.browser)
{
- [_delegate bonjourBrowserDomainSelected: pathArray ? DomainPathToDNSDomain(pathArray) : nil];
+ [_delegate domainBrowserDomainSelected: pathArray ? DomainPathToDNSDomain(pathArray) : nil];
}
}
{
(void)defaultDomainPath;
[self.browser loadColumnZero];
- [self setDomainSelectionToPathArray: self.bonjour.defaultDomainPath];
+#if INITIAL_LEGACYBROWSE
+ if( !_initialPathSet )
+ {
+ _initialPathSet = YES;
+ [_delegate domainBrowserDomainUpdate: [NSString string]];
+ }
+ else
+#endif
+ {
+ [self setDomainSelectionToPathArray: self.bonjour.defaultDomainPath];
+ if (_delegate && [_delegate respondsToSelector: @selector(domainBrowserDomainUpdate:)])
+ {
+ [_delegate domainBrowserDomainUpdate: defaultDomainPath ? DomainPathToDNSDomain(defaultDomainPath) : [NSString string]];
+ }
+ }
}
#pragma mark - Commands
{
(void)sender;
NSArray * pathArray = [self.browser pathArrayToColumn: self.browser.selectedColumn includeSelectedRow: YES];
- if (!pathArray.count) pathArray = self.bonjour.defaultDomainPath;
+ if (!pathArray.count && (([NSEvent modifierFlags] & NSEventModifierFlagOption ) != NSEventModifierFlagOption)) pathArray = self.bonjour.defaultDomainPath;
[self setDomainSelectionToPathArray: pathArray];
[self browser: self.browser selectionDidChange: pathArray];
}
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2004-2019 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.
// Note that this function assumes src is already NULL terminated
mDNSlocal void AllocAndCopy(char **const dst, const char *const src)
{
+ size_t srcLen;
if (src == mDNSNULL) return;
- if ((strlen((char*)src)) >= UINT32_MAX || (*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
+ srcLen = strlen(src) + 1;
+ if ((srcLen > UINT32_MAX) || ((*dst = mDNSPlatformMemAllocate((mDNSu32)srcLen)) == mDNSNULL))
{
LogMsg("AllocAndCopy: can't allocate string");
return;
}
- strcpy((char*)*dst, (char*)src);
+ memcpy(*dst, src, srcLen);
}
// This function does a simple parse of an HTTP URL that may include a hostname, port, and path
mDNSBool closed = mDNSfalse;
long n = 0;
long nsent = 0;
- static int LNTERRORcount = 0;
+ static mDNSu32 LNTERRORcount = 0;
if (tcpInfo->sock != sock)
{
exit:
if (err || status)
{
- mDNS *m = tcpInfo->m;
+ mDNS *const m = tcpInfo->m;
+ static mDNSs32 lastErrorTime = 0;
+
+ if ((LNTERRORcount > 0) && (((mDNSu32)(m->timenow - lastErrorTime)) >= ((mDNSu32)mDNSPlatformOneSecond)))
+ {
+ LNTERRORcount = 0;
+ }
+ lastErrorTime = m->timenow;
if ((++LNTERRORcount % 1000) == 0)
{
- LogMsg("ERROR: tcpconnectioncallback -> got error status %d times", LNTERRORcount);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "ERROR: tcpconnectioncallback -> got error status %u times", LNTERRORcount);
assert(LNTERRORcount < 1000);
// Recovery Mechanism to bail mDNSResponder out of trouble: It has been seen that we can get into
// this loop: [tcpKQSocketCallback()--> doTcpSocketCallback()-->tcpconnectionCallback()-->mDNSASLLog()],
else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
- info->sock = mDNSPlatformTCPSocket(kTCPSocketFlags_Zero, &srcport, mDNSfalse);
+ info->sock = mDNSPlatformTCPSocket(kTCPSocketFlags_Zero, Addr->type, &srcport, mDNSNULL, mDNSfalse);
if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
- err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
+ err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info);
if (err == mStatus_ConnPending) err = mStatus_NoError;
else if (err == mStatus_ConnEstablished)
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)
+ if ((info = (tcpLNTInfo *) mDNSPlatformMemAllocate(sizeof(*info))) == mDNSNULL)
{ LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
*info = n->tcpInfo;
--- /dev/null
+//
+// liblog_mdnsresponder.m
+// liblog_mdnsresponder
+//
+
+#import <Foundation/Foundation.h>
+#import <arpa/inet.h>
+#import <os/log_private.h>
+#import "DNSCommon.h"
+#undef DomainNameLength // undefines DomainNameLength since we need to use DomainNameLength that is also defined in DNSMessage.h
+#import "DNSMessage.h"
+
+// MDNS Mutable Attribute String
+#define MDNSAS(str) [[NSAttributedString alloc] initWithString:(str)]
+#define MDNSASWithFormat(format, ...) MDNSAS(([[NSString alloc] initWithFormat:format, ##__VA_ARGS__]))
+#define MAX_MDNS_ADDR_STRING_LENGTH 45
+
+// os_log(OS_LOG_DEFAULT, "IP Address(IPv4/IPv6): %{mdnsresponder:ip_addr}.20P", <the address of mDNSAddr structure>);
+static NS_RETURNS_RETAINED NSAttributedString *
+MDNSOLCopyFormattedStringmDNSIPAddr(id value)
+{
+ const mDNSAddr *mdns_addr_p;
+ char buffer[MAX_MDNS_ADDR_STRING_LENGTH + 1];
+ buffer[MAX_MDNS_ADDR_STRING_LENGTH] = 0;
+
+ if ([(NSObject *)value isKindOfClass:[NSData class]]) {
+ NSData *data = (NSData *)value;
+ if (data.bytes == NULL || data.length == 0) {
+ return MDNSAS(@"<NULL IP ADDRESS>");
+ }
+
+ if (data.length != sizeof(mDNSAddr)) {
+ return MDNSASWithFormat(@"<fail decode - size> %zd != %zd", (size_t)data.length, sizeof(mDNSAddr));
+ }
+
+ mdns_addr_p = (const mDNSAddr *)data.bytes;
+ } else {
+ return MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]);
+ }
+
+ bool failed_conversion = false;
+ switch (mdns_addr_p->type) {
+ case mDNSAddrType_IPv4:
+ {
+ __unused char sizecheck_buffer[(sizeof(buffer) >= INET_ADDRSTRLEN) ? 1 : -1];
+ if (!inet_ntop(AF_INET, (const void *)&mdns_addr_p->ip.v4.NotAnInteger, buffer, sizeof(buffer)))
+ failed_conversion = true;
+ break;
+ }
+ case mDNSAddrType_IPv6:
+ {
+ __unused char sizecheck_buffer[(sizeof(buffer) >= INET6_ADDRSTRLEN) ? 1 : -1];
+ if (!inet_ntop(AF_INET6, (const void *)mdns_addr_p->ip.v6.b, buffer, sizeof(buffer)))
+ failed_conversion = true;
+ break;
+ }
+ default:
+ failed_conversion = true;
+ break;
+ }
+ if (failed_conversion) {
+ return MDNSAS(@"<failed conversion>");
+ }
+
+ NSString *str = @(buffer);
+ return MDNSAS(str ? str : @("<Could not create NSString>"));
+}
+
+// os_log(OS_LOG_DEFAULT, "MAC Address: %{mdnsresponder:mac_addr}.6P", <the address of 6-byte MAC address>);
+#define MAC_ADDRESS_LEN 6
+static NS_RETURNS_RETAINED NSAttributedString *
+MDNSOLCopyFormattedStringmDNSMACAddr(id value)
+{
+ const uint8_t *mac_addr = NULL;
+ char buffer[MAX_MDNS_ADDR_STRING_LENGTH + 1];
+ buffer[MAX_MDNS_ADDR_STRING_LENGTH] = 0;
+
+ if ([(NSObject *)value isKindOfClass:[NSData class]]) {
+ NSData *data = (NSData *)value;
+ if (data.bytes == NULL || data.length == 0) {
+ return MDNSAS(@"<NULL MAC ADDRESS>");
+ }
+
+ if (data.length != MAC_ADDRESS_LEN) {
+ return MDNSASWithFormat(@"<fail decode - size> %zd != %zd", (size_t)data.length, MAC_ADDRESS_LEN);
+ }
+
+ mac_addr = (const uint8_t *)data.bytes;
+ } else {
+ return MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]);
+ }
+
+ int ret_snprintf = snprintf(buffer, MAX_MDNS_ADDR_STRING_LENGTH, "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+ if (ret_snprintf < 0) {
+ return MDNSAS(@"<failed conversion>");
+ }
+
+ NSString *str = @(buffer);
+ return MDNSAS(str ? str : @("<Could not create NSString>"));
+}
+
+// os_log(OS_LOG_DEFAULT, "Domain Name: %{mdnsresponder:domain_name}.*P", <the address of domainname structure>);
+// Leave some extra space to allow log routine to put error message when decode fails at the end of the buffer.
+static NS_RETURNS_RETAINED NSAttributedString *
+MDNSOLCopyFormattedStringmDNSLabelSequenceName(id value)
+{
+ char buffer[kDNSServiceMaxDomainName];
+ NSData *data = (NSData *)value;
+ OSStatus ret;
+
+ if ([(NSObject *)value isKindOfClass:[NSData class]]) {
+ if (data.bytes == NULL || data.length == 0) {
+ return MDNSAS(@"<NULL DOMAIN NAME>");
+ }
+ } else {
+ return MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]);
+ }
+
+ buffer[0] = '\0';
+ ret = DomainNameToString((const uint8_t *)data.bytes, ((const uint8_t *) data.bytes) + data.length, buffer, NULL);
+ if (ret != kNoErr) {
+ snprintf(buffer, sizeof(buffer), "<Malformed Domain Name>");
+ }
+
+ NSString *str = @(buffer);
+ return MDNSAS(str ? str : @("<Could not create NSString>"));
+}
+
+struct MDNSOLFormatters {
+ const char *type;
+ NS_RETURNS_RETAINED NSAttributedString *(*function)(id);
+};
+
+NS_RETURNS_RETAINED
+NSAttributedString *
+OSLogCopyFormattedString(const char *type, id value, __unused os_log_type_info_t info)
+{
+ static const struct MDNSOLFormatters formatters[] = {
+ { .type = "ip_addr", .function = MDNSOLCopyFormattedStringmDNSIPAddr },
+ { .type = "mac_addr", .function = MDNSOLCopyFormattedStringmDNSMACAddr },
+ { .type = "domain_name", .function = MDNSOLCopyFormattedStringmDNSLabelSequenceName },
+ };
+
+ for (int i = 0; i < (int)(sizeof(formatters) / sizeof(formatters[0])); i++) {
+ if (strcmp(type, formatters[i].type) == 0) {
+ return formatters[i].function(value);
+ }
+ }
+
+ return nil;
+}
/*
- * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2016-2019 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.
#define __Metrics_h
#include "mDNSEmbeddedAPI.h"
-#include <TargetConditionals.h>
#ifdef __cplusplus
extern "C" {
#endif
-#if TARGET_OS_IOS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
mStatus MetricsInit(void);
-void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell);
-void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell);
+void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell);
void MetricsUpdateDNSQuerySize(mDNSu32 inSize);
void MetricsUpdateDNSResponseSize(mDNSu32 inSize);
-void LogMetrics(void);
+void LogMetricsToFD(int fd);
#endif
#ifdef __cplusplus
/*
- * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2016-2019 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.
#import "Metrics.h"
-#if (TARGET_OS_IOS)
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
#import <CoreUtils/SoftLinking.h>
#import <WirelessDiagnostics/AWDDNSDomainStats.h>
#import <WirelessDiagnostics/AWDMDNSResponderDNSMessageSizeStats.h>
#import <WirelessDiagnostics/AWDMDNSResponderDNSStatistics.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStats.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDNSServer.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDomain.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsHostname.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsResult.h>
#import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
#import <WirelessDiagnostics/AWDMetricIds_MDNSResponder.h>
#import <WirelessDiagnostics/WirelessDiagnostics.h>
#define AWDMDNSResponderDNSStatisticsSoft getAWDMDNSResponderDNSStatisticsClass()
#define AWDDNSDomainStatsSoft getAWDDNSDomainStatsClass()
-// Classes for resolve stats
-
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult)
-
-#define AWDMDNSResponderResolveStatsSoft getAWDMDNSResponderResolveStatsClass()
-#define AWDMDNSResponderResolveStatsDNSServerSoft getAWDMDNSResponderResolveStatsDNSServerClass()
-#define AWDMDNSResponderResolveStatsDomainSoft getAWDMDNSResponderResolveStatsDomainClass()
-#define AWDMDNSResponderResolveStatsHostnameSoft getAWDMDNSResponderResolveStatsHostnameClass()
-#define AWDMDNSResponderResolveStatsResultSoft getAWDMDNSResponderResolveStatsResultClass()
-
// Classes for services stats
SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
#define countof(X) (sizeof(X) / sizeof(X[0]))
#define countof_field(TYPE, FIELD) countof(((TYPE *)0)->FIELD)
-#define increment_saturate(VAR, MAX) do {if ((VAR) < (MAX)) {++(VAR);}} while (0)
#define ForgetMem(X) do {if(*(X)) {free(*(X)); *(X) = NULL;}} while(0)
//===========================================================================================================================
#define kQueryStatsSendCountBinCount (kQueryStatsMaxQuerySendCount + 1)
#define kQueryStatsLatencyBinCount 55
#define kQueryStatsExpiredAnswerStateCount (ExpiredAnswer_EnumCount)
-#define kResolveStatsMaxObjCount 2000
+#define kQueryStatsDNSOverTCPStateCount (DNSOverTCP_EnumCount)
//===========================================================================================================================
// Data structures
uint16_t responseLatencyBins[kQueryStatsLatencyBinCount];
uint16_t negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
uint16_t negResponseLatencyBins[kQueryStatsLatencyBinCount];
- uint16_t expiredAnswerStateBins[kQueryStatsExpiredAnswerStateCount];
+ uint32_t expiredAnswerStateBins[kQueryStatsExpiredAnswerStateCount];
+ uint32_t dnsOverTCPStateBins[kQueryStatsDNSOverTCPStateCount];
} DNSHist;
check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
-check_compile_time(countof_field(DNSHist, expiredAnswerStateBins) == (kQueryStatsExpiredAnswerStateCount));
+check_compile_time(countof_field(DNSHist, expiredAnswerStateBins) == (kQueryStatsExpiredAnswerStateCount));
+check_compile_time(countof_field(DNSHist, dnsOverTCPStateBins) == (kQueryStatsDNSOverTCPStateCount));
// Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
// latency histogram bins to observe these time interval upper bounds.
} QueryStatsArgs;
-// Data structures for resolve stats.
-
-static const char * const kResolveStatsDomains[] =
-{
- "apple.com.",
- "icloud.com.",
- "mzstatic.com.",
- "me.com."
-};
-
-check_compile_time(countof(kResolveStatsDomains) == 4);
-
-typedef struct ResolveStatsDomain ResolveStatsDomain;
-typedef struct ResolveStatsHostname ResolveStatsHostname;
-typedef struct ResolveStatsDNSServer ResolveStatsDNSServer;
-typedef struct ResolveStatsIPv4AddrSet ResolveStatsIPv4AddrSet;
-typedef struct ResolveStatsIPv6Addr ResolveStatsIPv6Addr;
-typedef struct ResolveStatsNegAAAASet ResolveStatsNegAAAASet;
-
-struct ResolveStatsDomain
-{
- ResolveStatsDomain * next; // Next domain object in list.
- const char * domainStr;
- uint8_t * domain; // Domain for which these stats are collected.
- int labelCount; // Number of labels in domain name. Used for domain name comparisons.
- ResolveStatsHostname * hostnameList; // List of hostname objects in this domain.
-};
-
-check_compile_time(sizeof(ResolveStatsDomain) <= 40);
-
-struct ResolveStatsHostname
-{
- ResolveStatsHostname * next; // Next hostname object in list.
- ResolveStatsIPv4AddrSet * addrV4List; // List of IPv4 addresses to which this hostname resolved.
- ResolveStatsIPv6Addr * addrV6List; // List of IPv6 addresses to which this hostname resolved.
- ResolveStatsNegAAAASet * negV6List; // List of negative AAAA response objects.
- uint8_t name[1]; // Variable length storage for hostname as length-prefixed labels.
-};
-
-check_compile_time(sizeof(ResolveStatsHostname) <= 64);
-
-struct ResolveStatsDNSServer
-{
- ResolveStatsDNSServer * next; // Next DNS server object in list.
- uint8_t id; // 8-bit ID assigned to this DNS server used by IP address objects.
- mDNSBool isForCell; // True if this DNS server belongs to a cellular interface.
- mDNSBool isAddrV6; // True if this DNS server has an IPv6 address instead of IPv4.
- uint8_t addrBytes[1]; // Variable length storage for DNS server's IP address.
-};
-
-check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
-
-typedef struct
-{
- uint16_t count; // Number of times this IPv4 address was provided as a resolution result.
- uint8_t serverID; // 8-bit ID of the DNS server from which this IPv4 address came.
- uint8_t isNegative;
- uint8_t addrBytes[4]; // IPv4 address bytes.
-
-} IPv4AddrCounter;
-
-check_compile_time(sizeof(IPv4AddrCounter) <= 8);
-
-struct ResolveStatsIPv4AddrSet
-{
- ResolveStatsIPv4AddrSet * next; // Next set of IPv4 address counters in list.
- IPv4AddrCounter counters[3]; // Array of IPv4 address counters.
-};
-
-check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
-
-struct ResolveStatsIPv6Addr
-{
- ResolveStatsIPv6Addr * next; // Next IPv6 address object in list.
- uint16_t count; // Number of times this IPv6 address was provided as a resolution result.
- uint8_t serverID; // 8-bit ID of the DNS server from which this IPv6 address came.
- uint8_t addrBytes[16]; // IPv6 address bytes.
-};
-
-check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
-
-typedef struct
-{
- uint16_t count; // Number of times that a negative response was returned by a DNS server.
- uint8_t serverID; // 8-bit ID of the DNS server that sent the negative responses.
-
-} NegAAAACounter;
-
-check_compile_time(sizeof(NegAAAACounter) <= 4);
-
-struct ResolveStatsNegAAAASet
-{
- ResolveStatsNegAAAASet * next; // Next set of negative AAAA response counters in list.
- NegAAAACounter counters[6]; // Array of negative AAAA response counters.
-};
-
-check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
-
-typedef enum
-{
- kResponseType_IPv4Addr = 1,
- kResponseType_IPv6Addr = 2,
- kResponseType_NegA = 3,
- kResponseType_NegAAAA = 4
-
-} ResponseType;
-
-typedef struct
-{
- ResponseType type;
- const uint8_t * data;
-
-} Response;
-
// Data structures for DNS message size stats.
#define kQuerySizeBinWidth 16
typedef struct
{
- uint16_t querySizeBins[kQuerySizeBinCount];
- uint16_t responseSizeBins[kResponseSizeBinCount];
+ uint32_t querySizeBins[kQuerySizeBinCount];
+ uint32_t responseSizeBins[kResponseSizeBinCount];
} DNSMessageSizeStats;
-check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
+check_compile_time(sizeof(DNSMessageSizeStats) <= 264);
//===========================================================================================================================
// Local Prototypes
mDNSlocal mStatus QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats);
mDNSlocal void QueryStatsFree(QueryStats *inStats);
mDNSlocal void QueryStatsFreeList(QueryStats *inList);
-mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell);
+mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell);
mDNSlocal const char * QueryStatsGetDomainString(const QueryStats *inStats);
mDNSlocal mDNSBool QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName);
mDNSlocal mDNSBool QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName);
mDNSlocal mDNSBool QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName);
mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName);
-// Resolve stats
-
-mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain);
-mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
-mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
-mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
-
-mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
-mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
-mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
-mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
-
-mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
-mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
-mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
-
-mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
-mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
-
-mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
-mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
-
-mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
-mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
-mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
-
// DNS message size stats
mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList);
-mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList);
-mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList);
-mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID);
mDNSlocal mStatus SubmitAWDMetricQueryStats(void);
-mDNSlocal mStatus SubmitAWDMetricResolveStats(void);
mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void);
mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
-mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
-mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
-mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
-mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
-mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth);
+mDNSlocal void LogDNSHistSetToFD(int fd, const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
+mDNSlocal void LogDNSHistToFD(int fd, const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
+mDNSlocal void LogDNSHistSendCountsToFD(int fd, const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
+mDNSlocal void LogDNSHistLatenciesToFD(int fd, const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
+mDNSlocal void LogDNSMessageSizeStatsToFD(int fd, const uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth);
+
+//===========================================================================================================================
+// Histogram Bin Helpers
+//===========================================================================================================================
+
+#define INCREMENT_BIN_DEFINITION(BIN_SIZE) \
+ mDNSlocal void IncrementBin ## BIN_SIZE (uint ## BIN_SIZE ## _t *inBin) \
+ { \
+ if (*inBin < UINT ## BIN_SIZE ## _MAX) ++(*inBin); \
+ } \
+ extern int _MetricsDummyVariable
+
+INCREMENT_BIN_DEFINITION(16);
+INCREMENT_BIN_DEFINITION(32);
+
+// Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
+// bin and all bins with non-zero values.
+
+#define COPY_BINS_DEFINITION(BIN_SIZE) \
+ mDNSlocal size_t CopyBins ## BIN_SIZE (uint32_t *inDstBins, uint ## BIN_SIZE ## _t *inSrcBins, size_t inBinCount) \
+ { \
+ if (inBinCount == 0) return (0); \
+ size_t minCount = 1; \
+ for (size_t i = 0; i < inBinCount; ++i) \
+ { \
+ inDstBins[i] = inSrcBins[i]; \
+ if (inDstBins[i] > 0) minCount = i + 1; \
+ } \
+ return (minCount); \
+ } \
+ extern int _MetricsDummyVariable
-mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
+COPY_BINS_DEFINITION(16);
+COPY_BINS_DEFINITION(32);
//===========================================================================================================================
// Globals
//===========================================================================================================================
-static AWDServerConnection * gAWDServerConnection = nil;
-static QueryStats * gQueryStatsList = NULL;
-static ResolveStatsDomain * gResolveStatsList = NULL;
-static ResolveStatsDNSServer * gResolveStatsServerList = NULL;
-static unsigned int gResolveStatsNextServerID = 0;
-static int gResolveStatsObjCount = 0;
-static DNSMessageSizeStats * gDNSMessageSizeStats = NULL;
+static AWDServerConnection * gAWDServerConnection = nil;
+static QueryStats * gQueryStatsList = NULL;
+static DNSMessageSizeStats * gDNSMessageSizeStats = NULL;
// Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
}
forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
- [gAWDServerConnection
- registerQueriableMetricCallback: ^(UInt32 inMetricID)
- {
- SubmitAWDMetric(inMetricID);
- }
- forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
-
[gAWDServerConnection
registerQueriableMetricCallback: ^(UInt32 inMetricID)
{
if( gAWDServerConnection )
{
CreateQueryStatsList(&gQueryStatsList);
- CreateResolveStatsList(&gResolveStatsList);
DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
}
// MetricsUpdateDNSQueryStats
//===========================================================================================================================
-mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell)
+mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell)
{
QueryStats * stats;
mDNSBool match;
match = stats->test(stats, inQueryName);
if (match)
{
- QueryStatsUpdate(stats, inType, inRR, inSendCount, inExpiredAnswerState, inLatencyMs, inForCell);
+ QueryStatsUpdate(stats, inType, inRR, inSendCount, inExpiredAnswerState, inDNSOverTCPState, inLatencyMs, inForCell);
if (stats->terminal) break;
}
}
return;
}
-//===========================================================================================================================
-// MetricsUpdateDNSResolveStats
-//===========================================================================================================================
-
-mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
-{
- ResolveStatsDomain * domainStats;
- domainname hostname;
- size_t hostnameLen;
- mDNSBool isQueryInDomain;
- int skipCount;
- int skipCountLast = -1;
- int queryLabelCount;
- const domainname * queryParentDomain;
- Response response;
-
- require_quiet(gAWDServerConnection, exit);
- require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
- require_quiet(inRR->rDNSServer, exit);
-
- queryLabelCount = CountLabels(inQueryName);
-
- for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
- {
- isQueryInDomain = mDNSfalse;
- skipCount = queryLabelCount - domainStats->labelCount;
- if (skipCount >= 0)
- {
- if (skipCount != skipCountLast)
- {
- queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
- skipCountLast = skipCount;
- }
- isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
- }
- if (!isQueryInDomain) continue;
-
- hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
- if (hostnameLen >= sizeof(hostname.c)) continue;
-
- memcpy(hostname.c, inQueryName->c, hostnameLen);
- hostname.c[hostnameLen] = 0;
-
- if (inRR->RecordType == kDNSRecordTypePacketNegative)
- {
- response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
- response.data = NULL;
- }
- else
- {
- response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
- response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
- }
- ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
- }
-
-exit:
- return;
-}
-
//===========================================================================================================================
// MetricsUpdateDNSQuerySize
//===========================================================================================================================
-mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
+mDNSlocal void UpdateMessageSizeCounts(uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
{
UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
}
-mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
+mDNSlocal void UpdateMessageSizeCounts(uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
{
size_t i;
if (inSize == 0) return;
i = (inSize - 1) / inBinWidth;
if (i >= inBinCount) i = inBinCount - 1;
- increment_saturate(inBins[i], UINT16_MAX);
+ IncrementBin32(&inBins[i]);
}
//===========================================================================================================================
// LogMetrics
//===========================================================================================================================
-mDNSexport void LogMetrics(void)
+mDNSexport void LogMetricsToFD(int fd)
{
- QueryStats * stats;
- const ResolveStatsDomain * domain;
- const ResolveStatsHostname * hostname;
- const ResolveStatsDNSServer * server;
- const ResolveStatsIPv4AddrSet * addrV4;
- const ResolveStatsIPv6Addr * addrV6;
- const ResolveStatsNegAAAASet * negV6;
- int hostnameCount;
- int i;
- unsigned int serverID;
- int serverObjCount = 0;
- int hostnameObjCount = 0;
- int addrObjCount = 0;
-
- LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
- LogMsgNoIdent("---- DNS query stats by domain -----");
+ QueryStats * stats;
+
+ LogToFD(fd, "gAWDServerConnection %p", gAWDServerConnection);
+ LogToFD(fd, "---- DNS query stats by domain -----");
for (stats = gQueryStatsList; stats; stats = stats->next)
{
if (!stats->nonCellular && !stats->cellular)
{
- LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
+ LogToFD(fd, "No data for %s", QueryStatsGetDomainString(stats));
continue;
}
- if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
- if (stats->cellular) LogDNSHistSet(stats->cellular, QueryStatsGetDomainString(stats), mDNStrue);
- }
-
- LogMsgNoIdent("---- DNS resolve stats by domain -----");
-
- LogMsgNoIdent("Servers:");
- for (server = gResolveStatsServerList; server; server = server->next)
- {
- serverObjCount++;
- LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
- server->id, server->isForCell ? " C" : "NC", server->addrBytes);
- }
-
- for (domain = gResolveStatsList; domain; domain = domain->next)
- {
- hostnameCount = 0;
- for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
- hostnameObjCount += hostnameCount;
-
- LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
-
- for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
- {
- LogMsgNoIdent(" %##s", hostname->name);
- for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
- {
- for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
- {
- if (serverID == 0) addrObjCount++;
- for (i = 0; i < (int)countof(addrV4->counters); ++i)
- {
- const IPv4AddrCounter * counter;
-
- counter = &addrV4->counters[i];
- if (counter->count == 0) break;
- if (counter->serverID == serverID)
- {
- if (counter->isNegative)
- {
- LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
- }
- else
- {
- LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
- }
- }
- }
- }
- for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
- {
- if (serverID == 0) addrObjCount++;
- if (addrV6->serverID == serverID)
- {
- LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
- }
- }
- for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
- {
- if (serverID == 0) addrObjCount++;
- for (i = 0; i < (int)countof(negV6->counters); ++i)
- {
- const NegAAAACounter * counter;
-
- counter = &negV6->counters[i];
- if (counter->count == 0) break;
- if (counter->serverID == serverID)
- {
- LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
- }
- }
- }
- }
- }
+ if (stats->nonCellular) LogDNSHistSetToFD(fd, stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
+ if (stats->cellular) LogDNSHistSetToFD(fd, stats->cellular, QueryStatsGetDomainString(stats), mDNStrue);
}
- LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
- serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
- LogMsgNoIdent("---- Num of Services Registered -----");
- LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
- curr_num_regservices, max_num_regservices);
+ LogToFD(fd, "---- Num of Services Registered -----");
+ LogToFD(fd, "Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
+ curr_num_regservices, max_num_regservices);
if (gDNSMessageSizeStats)
{
- LogMsgNoIdent("---- DNS query size stats ---");
- LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
+ LogToFD(fd, "---- DNS query size stats ---");
+ LogDNSMessageSizeStatsToFD(fd, gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
- LogMsgNoIdent("-- DNS response size stats --");
- LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
+ LogToFD(fd, "-- DNS response size stats --");
+ LogDNSMessageSizeStatsToFD(fd, gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
}
else
{
- LogMsgNoIdent("No DNS message size stats.");
+ LogToFD(fd, "No DNS message size stats.");
}
}
// QueryStatsUpdate
//===========================================================================================================================
-mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell)
+mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell)
{
mStatus err;
DNSHistSet * set;
i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
- increment_saturate(sendCountBins[i], UINT16_MAX);
+ IncrementBin16(&sendCountBins[i]);
if (inQuerySendCount > 0)
{
for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
- increment_saturate(latencyBins[i], UINT16_MAX);
+ IncrementBin16(&latencyBins[i]);
}
}
else
{
i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
- increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
+ IncrementBin16(&hist->unansweredQuerySendCountBins[i]);
for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
- increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
+ IncrementBin16(&hist->unansweredQueryDurationBins[i]);
}
- increment_saturate(hist->expiredAnswerStateBins[Min(inExpiredAnswerState, (kQueryStatsExpiredAnswerStateCount-1))], UINT16_MAX);
+ IncrementBin32(&hist->expiredAnswerStateBins[Min(inExpiredAnswerState, (kQueryStatsExpiredAnswerStateCount - 1))]);
+ IncrementBin32(&hist->dnsOverTCPStateBins[Min(inDNSOverTCPState, (kQueryStatsDNSOverTCPStateCount - 1))]);
err = mStatus_NoError;
exit:
}
//===========================================================================================================================
-// ResolveStatsDomainCreate
+// DNSMessageSizeStatsCreate
//===========================================================================================================================
-mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
+mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
{
mStatus err;
- ResolveStatsDomain * obj;
-
- obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
- require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
- obj->domainStr = inDomainStr;
- err = StringToDomainName(obj->domainStr, &obj->domain);
- require_noerr_quiet(err, exit);
+ DNSMessageSizeStats * stats;
- obj->labelCount = CountLabels((const domainname *)obj->domain);
+ stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
+ require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
- *outDomain = obj;
- obj = NULL;
+ *outStats = stats;
err = mStatus_NoError;
exit:
- if (obj) ResolveStatsDomainFree(obj);
return (err);
}
//===========================================================================================================================
-// ResolveStatsDomainFree
+// DNSMessageSizeStatsFree
//===========================================================================================================================
-mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
+mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
{
- ResolveStatsHostname * hostname;
-
- ForgetMem(&inDomain->domain);
- while ((hostname = inDomain->hostnameList) != NULL)
- {
- inDomain->hostnameList = hostname->next;
- ResolveStatsHostnameFree(hostname);
- }
- free(inDomain);
+ free(inStats);
}
//===========================================================================================================================
-// ResolveStatsDomainUpdate
+// CreateQueryStatsList
//===========================================================================================================================
-mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
+mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
{
- mStatus err;
- ResolveStatsHostname ** p;
- ResolveStatsHostname * hostname;
- uint8_t serverID;
-
- for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
- {
- if (SameDomainName((domainname *)hostname->name, inHostname)) break;
- }
+ mStatus err;
+ QueryStats ** p;
+ QueryStats * stats;
+ const QueryStatsArgs * args;
+ const QueryStatsArgs * const end = kQueryStatsArgs + countof(kQueryStatsArgs);
+ QueryStats * list = NULL;
- if (!hostname)
+ p = &list;
+ for (args = kQueryStatsArgs; args < end; ++args)
{
- require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
- err = ResolveStatsHostnameCreate(inHostname, &hostname);
+ err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
require_noerr_quiet(err, exit);
- gResolveStatsObjCount++;
- *p = hostname;
- }
- err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
- require_noerr_quiet(err, exit);
+ *p = stats;
+ p = &stats->next;
+ }
- err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
- require_noerr_quiet(err, exit);
+ *outList = list;
+ list = NULL;
+ err = mStatus_NoError;
exit:
+ QueryStatsFreeList(list);
return (err);
}
//===========================================================================================================================
-// ResolveStatsHostnameCreate
+// SubmitAWDMetric
//===========================================================================================================================
-mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
+mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
{
- mStatus err;
- ResolveStatsHostname * obj;
- size_t nameLen;
+ mStatus err;
- nameLen = DomainNameLength(inName);
- require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
+ switch (inMetricID)
+ {
+ case AWDMetricId_MDNSResponder_DNSStatistics:
+ err = SubmitAWDMetricQueryStats();
+ break;
- obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
- require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
+ case AWDMetricId_MDNSResponder_ServicesStats:
+ [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
+ KQueueLock();
+ // reset the no of max services since we want to collect the max no of services registered per AWD submission period
+ max_num_regservices = curr_num_regservices;
+ KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
+ err = mStatus_NoError;
+ break;
- memcpy(obj->name, inName, nameLen);
+ case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
+ err = SubmitAWDMetricDNSMessageSizeStats();
+ break;
- *outHostname = obj;
- err = mStatus_NoError;
+ default:
+ err = mStatus_UnsupportedErr;
+ break;
+ }
-exit:
+ if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
return (err);
}
//===========================================================================================================================
-// ResolveStatsDomainCreateAWDVersion
+// SubmitAWDMetricQueryStats
//===========================================================================================================================
-mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
+mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
+mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
+
+mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
{
- mStatus err;
- AWDMDNSResponderResolveStatsDomain * domain;
- ResolveStatsHostname * hostname;
- AWDMDNSResponderResolveStatsHostname * awdHostname;
- NSString * name;
+ mStatus err;
+ BOOL success;
+ QueryStats * stats;
+ QueryStats * statsList;
+ QueryStats * newStatsList;
+ AWDMetricContainer * container = nil;
+ AWDMDNSResponderDNSStatistics * metric = nil;
- domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
- require_action_quiet(domain, exit, err = mStatus_UnknownErr);
+ newStatsList = NULL;
+ CreateQueryStatsList(&newStatsList);
+
+ KQueueLock();
+ statsList = gQueryStatsList;
+ gQueryStatsList = newStatsList;
+ KQueueUnlock("SubmitAWDMetricQueryStats");
- name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
- require_action_quiet(name, exit, err = mStatus_UnknownErr);
+ container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
+ require_action_quiet(container, exit, err = mStatus_UnknownErr);
- domain.name = name;
- [name release];
- name = nil;
+ metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
+ require_action_quiet(metric, exit, err = mStatus_UnknownErr);
- for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
+ while ((stats = statsList) != NULL)
{
- err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
+ err = AddQueryStats(metric, stats);
require_noerr_quiet(err, exit);
- [domain addHostname:awdHostname];
- [awdHostname release];
- awdHostname = nil;
+ statsList = stats->next;
+ QueryStatsFree(stats);
}
- *outDomain = domain;
- domain = nil;
- err = mStatus_NoError;
+ container.metric = metric;
+ success = [gAWDServerConnection submitMetric:container];
+ LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
+ err = success ? mStatus_NoError : mStatus_UnknownErr;
exit:
- [domain release];
+ QueryStatsFreeList(statsList);
return (err);
}
-//===========================================================================================================================
-// ResolveStatsHostnameFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
+mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
{
- ResolveStatsIPv4AddrSet * addrV4;
- ResolveStatsIPv6Addr * addrV6;
- ResolveStatsNegAAAASet * negV6;
+ mStatus err;
- while ((addrV4 = inHostname->addrV4List) != NULL)
- {
- inHostname->addrV4List = addrV4->next;
- ResolveStatsIPv4AddrSetFree(addrV4);
- }
- while ((addrV6 = inHostname->addrV6List) != NULL)
+ if (inStats->nonCellular)
{
- inHostname->addrV6List = addrV6->next;
- ResolveStatsIPv6AddressFree(addrV6);
+ err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
+ require_noerr_quiet(err, exit);
}
- while ((negV6 = inHostname->negV6List) != NULL)
+ if (inStats->cellular)
{
- inHostname->negV6List = negV6->next;
- ResolveStatsNegAAAASetFree(negV6);
+ err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
+ require_noerr_quiet(err, exit);
}
- free(inHostname);
-}
+ err = mStatus_NoError;
-//===========================================================================================================================
-// ResolveStatsHostnameUpdate
-//===========================================================================================================================
+exit:
+ return (err);
+}
-mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
+mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
{
- mStatus err;
+ mStatus err;
+ AWDDNSDomainStats * awdStats;
- if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
+ if (inSet->histA)
{
- ResolveStatsIPv4AddrSet ** p;
- ResolveStatsIPv4AddrSet * addrV4;
- int i;
- IPv4AddrCounter * counter;
-
- for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
- {
- for (i = 0; i < (int)countof(addrV4->counters); ++i)
- {
- counter = &addrV4->counters[i];
- if (counter->count == 0) break;
- if (counter->serverID != inServerID) continue;
- if (inResp->type == kResponseType_NegA)
- {
- if (counter->isNegative) break;
- }
- else
- {
- if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
- }
- }
- if (i < (int)countof(addrV4->counters)) break;
- }
- if (!addrV4)
- {
- require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
- err = ResolveStatsIPv4AddrSetCreate(&addrV4);
- require_noerr_quiet(err, exit);
- gResolveStatsObjCount++;
-
- *p = addrV4;
- counter = &addrV4->counters[0];
- }
- if (counter->count == 0)
- {
- counter->serverID = inServerID;
- if (inResp->type == kResponseType_NegA)
- {
- counter->isNegative = 1;
- }
- else
- {
- counter->isNegative = 0;
- memcpy(counter->addrBytes, inResp->data, 4);
- }
- }
- increment_saturate(counter->count, UINT16_MAX);
- err = mStatus_NoError;
- }
- else if (inResp->type == kResponseType_IPv6Addr)
- {
- ResolveStatsIPv6Addr ** p;
- ResolveStatsIPv6Addr * addrV6;
-
- for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
- {
- if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
- }
- if (!addrV6)
- {
- require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
- err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
- require_noerr_quiet(err, exit);
- gResolveStatsObjCount++;
-
- *p = addrV6;
- }
- increment_saturate(addrV6->count, UINT16_MAX);
- err = mStatus_NoError;
- }
- else if (inResp->type == kResponseType_NegAAAA)
- {
- ResolveStatsNegAAAASet ** p;
- ResolveStatsNegAAAASet * negV6;
- int i;
- NegAAAACounter * counter;
-
- for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
- {
- for (i = 0; i < (int)countof(negV6->counters); ++i)
- {
- counter = &negV6->counters[i];
- if ((counter->count == 0) || (counter->serverID == inServerID)) break;
- }
- if (i < (int)countof(negV6->counters)) break;
- }
- if (!negV6)
- {
- require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
- err = ResolveStatsNegAAAASetCreate(&negV6);
- require_noerr_quiet(err, exit);
- gResolveStatsObjCount++;
-
- *p = negV6;
- counter = &negV6->counters[0];
- }
- if (counter->count == 0) counter->serverID = inServerID;
- increment_saturate(counter->count, UINT16_MAX);
- err = mStatus_NoError;
- }
- else
- {
- err = mStatus_Invalid;
- }
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsHostnameCreateAWDVersion
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
-{
- mStatus err;
- AWDMDNSResponderResolveStatsHostname * hostname;
- NSString * name;
- char nameBuf[MAX_ESCAPED_DOMAIN_NAME];
- const char * ptr;
- ResolveStatsIPv4AddrSet * addrV4;
- ResolveStatsIPv6Addr * addrV6;
- ResolveStatsNegAAAASet * negV6;
- AWDMDNSResponderResolveStatsResult * result = nil;
- int i;
-
- hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
- require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
-
- ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
- require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
-
- name = [[NSString alloc] initWithUTF8String:nameBuf];
- require_action_quiet(name, exit, err = mStatus_UnknownErr);
-
- hostname.name = name;
- [name release];
- name = nil;
-
- for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
- {
- for (i = 0; i < (int)countof(addrV4->counters); ++i)
- {
- const IPv4AddrCounter * counter;
- NSData * addrBytes;
-
- counter = &addrV4->counters[i];
- if (counter->count == 0) break;
-
- result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
- require_action_quiet(result, exit, err = mStatus_UnknownErr);
-
- if (counter->isNegative)
- {
- result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
- }
- else
- {
- addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
- require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
-
- result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
- result.data = addrBytes;
- [addrBytes release];
- }
- result.count = counter->count;
- result.serverID = counter->serverID;
-
- [hostname addResult:result];
- [result release];
- result = nil;
- }
- }
-
- for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
- {
- NSData * addrBytes;
-
- result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
- require_action_quiet(result, exit, err = mStatus_UnknownErr);
-
- addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
- require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
-
- result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
- result.count = addrV6->count;
- result.serverID = addrV6->serverID;
- result.data = addrBytes;
-
- [addrBytes release];
-
- [hostname addResult:result];
- [result release];
- result = nil;
- }
-
- for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
- {
- for (i = 0; i < (int)countof(negV6->counters); ++i)
- {
- const NegAAAACounter * counter;
-
- counter = &negV6->counters[i];
- if (counter->count == 0) break;
-
- result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
- require_action_quiet(result, exit, err = mStatus_UnknownErr);
-
- result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
- result.count = counter->count;
- result.serverID = counter->serverID;
-
- [hostname addResult:result];
- [result release];
- result = nil;
- }
- }
-
- *outHostname = hostname;
- hostname = nil;
- err = mStatus_NoError;
-
-exit:
- [result release];
- [hostname release];
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsDNSServerCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
-{
- mStatus err;
- ResolveStatsDNSServer * obj;
- size_t addrLen;
-
- require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
-
- addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
- obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
- require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
- obj->isForCell = inForCell;
- if (inAddr->type == mDNSAddrType_IPv4)
- {
- obj->isAddrV6 = mDNSfalse;
- memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
- }
- else
- {
- obj->isAddrV6 = mDNStrue;
- memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
- }
-
- *outServer = obj;
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsDNSServerFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
-{
- free(inServer);
-}
-
-//===========================================================================================================================
-// ResolveStatsDNSServerCreateAWDVersion
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
-{
- mStatus err;
- AWDMDNSResponderResolveStatsDNSServer * server;
- NSData * addrBytes = nil;
-
- server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
- require_action_quiet(server, exit, err = mStatus_UnknownErr);
-
- addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
- require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
-
- server.serverID = inServer->id;
- server.address = addrBytes;
- if (inServer->isForCell)
- {
- server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
- }
- else
- {
- server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
- }
-
- *outServer = server;
- server = nil;
- err = mStatus_NoError;
-
-exit:
- [addrBytes release];
- [server release];
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsIPv4AddrSetCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
-{
- mStatus err;
- ResolveStatsIPv4AddrSet * obj;
-
- obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
- require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
- *outSet = obj;
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsIPv4AddrSetFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
-{
- free(inSet);
-}
-
-//===========================================================================================================================
-// ResolveStatsIPv6AddressCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
-{
- mStatus err;
- ResolveStatsIPv6Addr * obj;
-
- obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
- require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
- obj->serverID = inServerID;
- memcpy(obj->addrBytes, inAddrBytes, 16);
-
- *outAddr = obj;
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsIPv6AddressFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
-{
- free(inAddr);
-}
-
-//===========================================================================================================================
-// ResolveStatsNegAAAASetCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
-{
- mStatus err;
- ResolveStatsNegAAAASet * obj;
-
- obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
- require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
- *outSet = obj;
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// ResolveStatsNegAAAASetFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
-{
- free(inSet);
-}
-
-//===========================================================================================================================
-// ResolveStatsGetServerID
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
-{
- mStatus err;
- ResolveStatsDNSServer ** p;
- ResolveStatsDNSServer * server;
-
- require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
-
- for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
- {
- if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
- {
- if (inServerAddr->type == mDNSAddrType_IPv4)
- {
- if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
- }
- else
- {
- if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
- }
- }
- }
-
- if (!server)
- {
- require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
- require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
- err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
- require_noerr_quiet(err, exit);
- gResolveStatsObjCount++;
-
- server->id = (uint8_t)gResolveStatsNextServerID++;
- server->next = gResolveStatsServerList;
- gResolveStatsServerList = server;
- }
- else if (gResolveStatsServerList != server)
- {
- *p = server->next;
- server->next = gResolveStatsServerList;
- gResolveStatsServerList = server;
- }
-
- *outServerID = server->id;
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// DNSMessageSizeStatsCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
-{
- mStatus err;
- DNSMessageSizeStats * stats;
-
- stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
- require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
-
- *outStats = stats;
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-//===========================================================================================================================
-// DNSMessageSizeStatsFree
-//===========================================================================================================================
-
-mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
-{
- free(inStats);
-}
-
-//===========================================================================================================================
-// CreateQueryStatsList
-//===========================================================================================================================
-
-mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
-{
- mStatus err;
- QueryStats ** p;
- QueryStats * stats;
- const QueryStatsArgs * args;
- const QueryStatsArgs * const end = kQueryStatsArgs + countof(kQueryStatsArgs);
- QueryStats * list = NULL;
-
- p = &list;
- for (args = kQueryStatsArgs; args < end; ++args)
- {
- err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
- require_noerr_quiet(err, exit);
-
- *p = stats;
- p = &stats->next;
- }
-
- *outList = list;
- list = NULL;
- err = mStatus_NoError;
-
-exit:
- QueryStatsFreeList(list);
- return (err);
-}
-
-//===========================================================================================================================
-// CreateResolveStatsList
-//===========================================================================================================================
-
-mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
-{
- mStatus err;
- unsigned int i;
- ResolveStatsDomain * domain;
- ResolveStatsDomain ** p;
- ResolveStatsDomain * list = NULL;
-
- p = &list;
- for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
- {
- err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
- require_noerr_quiet(err, exit);
-
- *p = domain;
- p = &domain->next;
- }
-
- *outList = list;
- list = NULL;
- err = mStatus_NoError;
-
-exit:
- FreeResolveStatsList(list);
- return (err);
-}
-
-//===========================================================================================================================
-// FreeResolveStatsList
-//===========================================================================================================================
-
-mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
-{
- ResolveStatsDomain * domain;
-
- while ((domain = inList) != NULL)
- {
- inList = domain->next;
- ResolveStatsDomainFree(domain);
- }
-}
-
-//===========================================================================================================================
-// FreeResolveStatsServerList
-//===========================================================================================================================
-
-mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
-{
- ResolveStatsDNSServer * server;
-
- while ((server = inList) != NULL)
- {
- inList = server->next;
- ResolveStatsDNSServerFree(server);
- }
-}
-
-//===========================================================================================================================
-// SubmitAWDMetric
-//===========================================================================================================================
-
-mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
-{
- mStatus err;
-
- switch (inMetricID)
- {
- case AWDMetricId_MDNSResponder_DNSStatistics:
- err = SubmitAWDMetricQueryStats();
- break;
-
- case AWDMetricId_MDNSResponder_ResolveStats:
- err = SubmitAWDMetricResolveStats();
- break;
-
- case AWDMetricId_MDNSResponder_ServicesStats:
- [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
- KQueueLock();
- // reset the no of max services since we want to collect the max no of services registered per AWD submission period
- max_num_regservices = curr_num_regservices;
- KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
- err = mStatus_NoError;
- break;
-
- case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
- err = SubmitAWDMetricDNSMessageSizeStats();
- break;
-
- default:
- err = mStatus_UnsupportedErr;
- break;
- }
-
- if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
- return (err);
-}
-
-//===========================================================================================================================
-// SubmitAWDMetricQueryStats
-//===========================================================================================================================
-
-mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
-mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
-
-mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
-{
- mStatus err;
- BOOL success;
- QueryStats * stats;
- QueryStats * statsList;
- QueryStats * newStatsList;
- AWDMetricContainer * container = nil;
- AWDMDNSResponderDNSStatistics * metric = nil;
-
- newStatsList = NULL;
- CreateQueryStatsList(&newStatsList);
-
- KQueueLock();
- statsList = gQueryStatsList;
- gQueryStatsList = newStatsList;
- KQueueUnlock("SubmitAWDMetricQueryStats");
-
- container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
- require_action_quiet(container, exit, err = mStatus_UnknownErr);
-
- metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
- require_action_quiet(metric, exit, err = mStatus_UnknownErr);
-
- while ((stats = statsList) != NULL)
- {
- err = AddQueryStats(metric, stats);
- require_noerr_quiet(err, exit);
-
- statsList = stats->next;
- QueryStatsFree(stats);
- }
-
- container.metric = metric;
- success = [gAWDServerConnection submitMetric:container];
- LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
- err = success ? mStatus_NoError : mStatus_UnknownErr;
-
-exit:
- [metric release];
- [container release];
- QueryStatsFreeList(statsList);
- return (err);
-}
-
-mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
-{
- mStatus err;
-
- if (inStats->nonCellular)
- {
- err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
- require_noerr_quiet(err, exit);
- }
- if (inStats->cellular)
- {
- err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
- require_noerr_quiet(err, exit);
- }
- err = mStatus_NoError;
-
-exit:
- return (err);
-}
-
-mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
-{
- mStatus err;
- AWDDNSDomainStats * awdStats;
-
- if (inSet->histA)
- {
- err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
- require_noerr_quiet(err, exit);
+ err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
+ require_noerr_quiet(err, exit);
[inMetric addStats:awdStats];
- [awdStats release];
}
if (inSet->histAAAA)
{
require_noerr_quiet(err, exit);
[inMetric addStats:awdStats];
- [awdStats release];
}
err = mStatus_NoError;
return (err);
}
-//===========================================================================================================================
-// SubmitAWDMetricResolveStats
-//===========================================================================================================================
-
-mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
-{
- mStatus err;
- ResolveStatsDomain * newResolveStatsList;
- ResolveStatsDomain * domainList = NULL;
- ResolveStatsDNSServer * serverList = NULL;
- AWDMetricContainer * container = nil;
- AWDMDNSResponderResolveStats * metric = nil;
- ResolveStatsDNSServer * server;
- ResolveStatsDomain * domain;
- BOOL success;
-
- err = CreateResolveStatsList(&newResolveStatsList);
- require_noerr_quiet(err, exit);
-
- KQueueLock();
- domainList = gResolveStatsList;
- serverList = gResolveStatsServerList;
- gResolveStatsList = newResolveStatsList;
- gResolveStatsServerList = NULL;
- gResolveStatsNextServerID = 0;
- gResolveStatsObjCount = 0;
- KQueueUnlock("SubmitAWDMetricResolveStats");
-
- container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
- require_action_quiet(container, exit, err = mStatus_UnknownErr);
-
- metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
- require_action_quiet(metric, exit, err = mStatus_UnknownErr);
-
- while ((server = serverList) != NULL)
- {
- AWDMDNSResponderResolveStatsDNSServer * awdServer;
-
- serverList = server->next;
- err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
- ResolveStatsDNSServerFree(server);
- require_noerr_quiet(err, exit);
-
- [metric addServer:awdServer];
- [awdServer release];
- }
-
- while ((domain = domainList) != NULL)
- {
- AWDMDNSResponderResolveStatsDomain * awdDomain;
-
- domainList = domain->next;
- err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
- ResolveStatsDomainFree(domain);
- require_noerr_quiet(err, exit);
-
- [metric addDomain:awdDomain];
- [awdDomain release];
- }
-
- container.metric = metric;
- success = [gAWDServerConnection submitMetric:container];
- LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed");
- err = success ? mStatus_NoError : mStatus_UnknownErr;
-
-exit:
- [metric release];
- [container release];
- FreeResolveStatsList(domainList);
- FreeResolveStatsServerList(serverList);
- return (err);
-}
-
//===========================================================================================================================
// SubmitAWDMetricDNSMessageSizeStats
//===========================================================================================================================
// Set query size counts.
- binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
+ binCount = CopyBins32(bins, stats->querySizeBins, kQuerySizeBinCount);
[metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
// Set response size counts.
- binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
+ binCount = CopyBins32(bins, stats->responseSizeBins, kResponseSizeBinCount);
[metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
}
err = success ? mStatus_NoError : mStatus_UnknownErr;
exit:
- [metric release];
- [container release];
if (stats) DNSMessageSizeStatsFree(stats);
return (err);
}
uint32_t sendCountBins[kQueryStatsSendCountBinCount];
uint32_t latencyBins[kQueryStatsLatencyBinCount];
uint32_t expiredAnswerBins[kQueryStatsExpiredAnswerStateCount];
+ uint32_t dnsOverTCPBins[kQueryStatsDNSOverTCPStateCount];
awdStats = [[AWDDNSDomainStatsSoft alloc] init];
require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
// Positively answered query send counts
- binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
+ binCount = CopyBins16(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
[awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
// binCount > 1 means that at least one of the non-zero send count bins had a non-zero count, i.e., at least one query
if (binCount > 1)
{
- binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
+ binCount = CopyBins16(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
[awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
}
// Negatively answered query send counts
- binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
+ binCount = CopyBins16(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
[awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
if (binCount > 1)
{
- binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
+ binCount = CopyBins16(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
[awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
}
// Unanswered query send counts
- binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
+ binCount = CopyBins16(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
[awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
if (binCount > 1)
{
- binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
+ binCount = CopyBins16(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
[awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
}
// Expired answers states
- binCount = CopyHistogramBins(expiredAnswerBins, inHist->expiredAnswerStateBins, kQueryStatsExpiredAnswerStateCount);
+ binCount = CopyBins32(expiredAnswerBins, inHist->expiredAnswerStateBins, kQueryStatsExpiredAnswerStateCount);
[awdStats setExpiredAnswerStates:expiredAnswerBins count:(NSUInteger)binCount];
- *outStats = awdStats;
- awdStats = nil;
+ // DNS Over TCP states
+
+ binCount = CopyBins32(dnsOverTCPBins, inHist->dnsOverTCPStateBins, kQueryStatsDNSOverTCPStateCount);
+ [awdStats setDnsOverTCPStates:dnsOverTCPBins count:(NSUInteger)binCount];
+
+ *outStats = awdStats;
err = mStatus_NoError;
exit:
- [domain release];
- [awdStats release];
return (err);
}
//===========================================================================================================================
-// LogDNSHistSet
+// LogDNSHistSetToFD
//===========================================================================================================================
-mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
+mDNSlocal void LogDNSHistSetToFD(int fd, const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
{
- if (inSet->histA) LogDNSHist(inSet->histA, inDomain, inForCell, "A");
- if (inSet->histAAAA) LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
+ if (inSet->histA) LogDNSHistToFD(fd, inSet->histA, inDomain, inForCell, "A");
+ if (inSet->histAAAA) LogDNSHistToFD(fd, inSet->histAAAA, inDomain, inForCell, "AAAA");
}
//===========================================================================================================================
-// LogDNSHist
+// LogDNSHistToFD
//===========================================================================================================================
#define Percent(N, D) (((N) * 100) / (D)), ((((N) * 10000) / (D)) % 100)
#define PercentFmt "%3u.%02u"
-#define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
- LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
+#define LogStatToFD(FILE_DESCRIPTOR, LABEL, COUNT, ACCUMULATOR, TOTAL) \
+ LogToFD((FILE_DESCRIPTOR), "%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
-mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
+mDNSlocal void LogDNSHistToFD(int fd, const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
{
unsigned int totalAnswered;
unsigned int totalNegAnswered;
totalUnanswered += inHist->unansweredQuerySendCountBins[i];
}
- LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
- LogMsgNoIdent("Answered questions %4u", totalAnswered);
- LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
- LogMsgNoIdent("Unanswered questions %4u", totalUnanswered);
- LogMsgNoIdent("Expired - no cached answer %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_Allowed]);
- LogMsgNoIdent("Expired - answered from cache %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithExpired]);
- LogMsgNoIdent("Expired - cache changed %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_ExpiredAnswerChanged]);
- LogMsgNoIdent("-- Query send counts ---------");
- LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
- LogMsgNoIdent("-- Query send counts (NAQs) --");
- LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
+ LogToFD(fd, "Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
+ LogToFD(fd, "Answered questions %10u", totalAnswered);
+ LogToFD(fd, "Negatively answered questions %10u", totalNegAnswered);
+ LogToFD(fd, "Unanswered questions %10u", totalUnanswered);
+ LogToFD(fd, "Expired - no cached answer %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_Allowed]);
+ LogToFD(fd, "Expired - answered from cache %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithCache]);
+ LogToFD(fd, "Expired - answered expired %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithExpired]);
+ LogToFD(fd, "Expired - cache changed %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_ExpiredAnswerChanged]);
+ LogToFD(fd, "DNSoTCP - truncated %10u", inHist->dnsOverTCPStateBins[DNSOverTCP_Truncated]);
+ LogToFD(fd, "DNSoTCP - suspicious %10u", inHist->dnsOverTCPStateBins[DNSOverTCP_Suspicious]);
+ LogToFD(fd, "DNSoTCP - suspicious defense %10u", inHist->dnsOverTCPStateBins[DNSOverTCP_SuspiciousDefense]);
+ LogToFD(fd, "-- Query send counts ---------");
+ LogDNSHistSendCountsToFD(fd, inHist->answeredQuerySendCountBins);
+ LogToFD(fd, "-- Query send counts (NAQs) --");
+ LogDNSHistSendCountsToFD(fd, inHist->negAnsweredQuerySendCountBins);
if (totalAnswered > inHist->answeredQuerySendCountBins[0])
{
- LogMsgNoIdent("--- Response times -----------");
- LogDNSHistLatencies(inHist->responseLatencyBins);
+ LogToFD(fd, "--- Response times -----------");
+ LogDNSHistLatenciesToFD(fd, inHist->responseLatencyBins);
}
if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
{
- LogMsgNoIdent("--- Response times (NAQs) ----");
- LogDNSHistLatencies(inHist->negResponseLatencyBins);
+ LogToFD(fd, "--- Response times (NAQs) ----");
+ LogDNSHistLatenciesToFD(fd, inHist->negResponseLatencyBins);
}
if (totalUnanswered > 0)
{
- LogMsgNoIdent("--- Unanswered query times ---");
- LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
+ LogToFD(fd, "--- Unanswered query times ---");
+ LogDNSHistLatenciesToFD(fd, inHist->unansweredQueryDurationBins);
}
}
//===========================================================================================================================
-// LogDNSHistSendCounts
+// LogDNSHistSendCountsToFD
//===========================================================================================================================
-mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
+mDNSlocal void LogDNSHistSendCountsToFD(int fd, const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
{
uint32_t total;
char label[16];
{
snprintf(label, sizeof(label), "%2d+", i);
}
- LogStat(label, inSendCountBins[i], accumulator, total);
+ LogStatToFD(fd, label, inSendCountBins[i], accumulator, total);
if (accumulator == total) break;
}
}
else
{
- LogMsgNoIdent("No data.");
+ LogToFD(fd, "No data.");
}
}
//===========================================================================================================================
-// LogDNSHistLatencies
+// LogDNSHistLatenciesToFD
//===========================================================================================================================
-mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
+mDNSlocal void LogDNSHistLatenciesToFD(int fd,
+ const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
{
uint32_t total;
int i;
{
snprintf(label, sizeof(label), "< ∞ ms");
}
- LogStat(label, inLatencyBins[i], accumulator, total);
+ LogStatToFD(fd, label, inLatencyBins[i], accumulator, total);
if (accumulator == total) break;
}
}
else
{
- LogMsgNoIdent("No data.");
+ LogToFD(fd, "No data.");
}
}
//===========================================================================================================================
-// LogDNSMessageSizeStats
+// LogDNSMessageSizeStatsToFD
//===========================================================================================================================
-mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
+mDNSlocal void LogDNSMessageSizeStatsToFD(int fd, const uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth)
{
size_t i;
uint32_t total;
{
snprintf(label, sizeof(label), "%3u+ ", lower);
}
- LogStat(label, inBins[i], accumulator, total);
+ LogStatToFD(fd, label, inBins[i], accumulator, total);
if (accumulator == total) break;
}
}
else
{
- LogMsgNoIdent("No data.");
+ LogToFD(fd, "No data.");
}
}
-//===========================================================================================================================
-// CopyHistogramBins
-//
-// Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
-// bin and all bins with non-zero values.
-//===========================================================================================================================
-
-mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
-{
- size_t i;
- size_t minCount;
-
- if (inBinCount == 0) return (0);
-
- minCount = 1;
- for (i = 0; i < inBinCount; ++i)
- {
- inDstBins[i] = inSrcBins[i];
- if (inDstBins[i] > 0) minCount = i + 1;
- }
-
- return (minCount);
-}
-#endif // TARGET_OS_IOS
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12118" systemVersion="17A210a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
- <dependencies>
- <deployment identifier="macosx"/>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12118"/>
- <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
- </dependencies>
- <objects>
- <customObject id="-2" userLabel="File's Owner" customClass="DNSServiceDiscoveryPref">
- <connections>
- <outlet property="_initialKeyView" destination="107" id="235"/>
- <outlet property="_lastKeyView" destination="107" id="183"/>
- <outlet property="_window" destination="12" id="142"/>
- <outlet property="addBrowseDomainButton" destination="381" id="384"/>
- <outlet property="addBrowseDomainManualWindow" destination="NFb-eI-atL" id="0AN-Mr-e84"/>
- <outlet property="addBrowseDomainWindow" destination="333" id="363"/>
- <outlet property="applyButton" destination="208" id="238"/>
- <outlet property="bonjourBrowserView" destination="200327" id="200328"/>
- <outlet property="browseCancelButton" destination="341" id="375"/>
- <outlet property="browseDomainList" destination="327" id="349"/>
- <outlet property="browseDomainTextField" destination="W2d-Us-Cpm" id="kOZ-wG-OPp"/>
- <outlet property="browseOKButton" destination="340" id="376"/>
- <outlet property="comboAuthButton" destination="137" id="201"/>
- <outlet property="hostName" destination="107" id="224"/>
- <outlet property="hostNameSharedSecretButton" destination="263" id="270"/>
- <outlet property="regDomainTextField" destination="OEh-fL-Ol6" id="Dv0-aj-gah"/>
- <outlet property="regDomainView" destination="Reu-VC-MNz" id="4I2-zS-sdq"/>
- <outlet property="registrationBrowserView" destination="agb-WV-smo" id="j7U-ZK-LIb"/>
- <outlet property="registrationSelectButton" destination="KqE-pc-8z0" id="CJS-ml-2CA"/>
- <outlet property="registrationSharedSecretButton" destination="267" id="268"/>
- <outlet property="removeBrowseDomainButton" destination="383" id="385"/>
- <outlet property="revertButton" destination="290" id="292"/>
- <outlet property="secretCancelButton" destination="341" id="373"/>
- <outlet property="secretOKButton" destination="260" id="377"/>
- <outlet property="selectRegistrationDomainManualWindow" destination="he2-0K-CWy" id="eXD-7o-XQU"/>
- <outlet property="selectRegistrationDomainWindow" destination="ail-If-2Xp" id="34V-c7-D3b"/>
- <outlet property="sharedSecretName" destination="256" id="275"/>
- <outlet property="sharedSecretValue" destination="257" id="276"/>
- <outlet property="sharedSecretWindow" destination="255" id="274"/>
- <outlet property="statusImageView" destination="320" id="321"/>
- <outlet property="tabView" destination="100" id="380"/>
- <outlet property="wideAreaCheckBox" destination="179" id="240"/>
- </connections>
- </customObject>
- <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
- <customObject id="-3" userLabel="Application" customClass="NSObject"/>
- <window title="Bonjour" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" deferred="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="12" userLabel="PrefPane">
- <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="51" y="335" width="596" height="343"/>
- <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
- <value key="minSize" type="size" width="213.66399999999999" height="10"/>
- <view key="contentView" id="6">
- <rect key="frame" x="0.0" y="0.0" width="596" height="343"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <tabView translatesAutoresizingMaskIntoConstraints="NO" id="100">
- <rect key="frame" x="13" y="52" width="570" height="285"/>
- <font key="font" metaFont="system"/>
- <tabViewItems>
- <tabViewItem label="Hostname" identifier="1" id="102">
- <view key="view" id="101">
- <rect key="frame" x="10" y="33" width="550" height="239"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="107">
- <rect key="frame" x="119" y="155" width="383" height="22"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" placeholderString="steve.example.com" drawsBackground="YES" id="100107">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- <connections>
- <outlet property="delegate" destination="-2" id="227"/>
- </connections>
- </textField>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="108">
- <rect key="frame" x="43" y="158" width="70" height="17"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Hostname:" id="100108">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="117">
- <rect key="frame" x="18" y="185" width="514" height="34"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="510" id="TMz-kS-KCv"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a hostname for this computer. Other computers on the Internet will be able to reach your computer using this hostname." id="100117">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="263">
- <rect key="frame" x="113" y="119" width="109" height="32"/>
- <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100263">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="changeButtonPressed:" target="-2" id="272"/>
- </connections>
- </button>
- <imageView translatesAutoresizingMaskIntoConstraints="NO" id="320">
- <rect key="frame" x="510" y="156" width="20" height="20"/>
- <constraints>
- <constraint firstAttribute="width" constant="20" id="7Qf-g0-5SV"/>
- <constraint firstAttribute="height" constant="20" id="bfL-QJ-KFw"/>
- </constraints>
- <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="left" imageScaling="proportionallyDown" id="100320"/>
- </imageView>
- </subviews>
- <constraints>
- <constraint firstItem="263" firstAttribute="leading" secondItem="107" secondAttribute="leading" id="4Dv-gf-Cjr"/>
- <constraint firstAttribute="trailing" secondItem="117" secondAttribute="trailing" constant="20" symbolic="YES" id="5zc-LQ-OC8"/>
- <constraint firstItem="320" firstAttribute="leading" secondItem="107" secondAttribute="trailing" constant="8" symbolic="YES" id="BIu-YL-Fr2"/>
- <constraint firstItem="263" firstAttribute="top" secondItem="107" secondAttribute="bottom" constant="8" symbolic="YES" id="K1w-WG-3KW"/>
- <constraint firstItem="107" firstAttribute="centerY" secondItem="320" secondAttribute="centerY" id="LlU-Oy-3va"/>
- <constraint firstItem="107" firstAttribute="top" secondItem="117" secondAttribute="bottom" constant="8" symbolic="YES" id="V8c-G1-gsR"/>
- <constraint firstItem="117" firstAttribute="top" secondItem="101" secondAttribute="top" constant="20" symbolic="YES" id="Xnz-bz-ahU"/>
- <constraint firstItem="117" firstAttribute="leading" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="ZIG-S4-cst"/>
- <constraint firstItem="107" firstAttribute="leading" secondItem="108" secondAttribute="trailing" constant="8" symbolic="YES" id="cQG-zv-Ozo"/>
- <constraint firstItem="108" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="foH-DQ-yvJ"/>
- <constraint firstItem="107" firstAttribute="leading" secondItem="101" secondAttribute="leading" priority="499" constant="119" id="qGZ-fm-Wgf"/>
- <constraint firstAttribute="trailing" secondItem="320" secondAttribute="trailing" constant="20" symbolic="YES" id="w2R-Kc-Tj3"/>
- <constraint firstItem="108" firstAttribute="baseline" secondItem="107" secondAttribute="baseline" id="xcr-32-mbs"/>
- </constraints>
- </view>
- </tabViewItem>
- <tabViewItem label="Registration" identifier="2" id="98">
- <view key="view" id="99">
- <rect key="frame" x="10" y="33" width="550" height="239"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <button translatesAutoresizingMaskIntoConstraints="NO" id="179">
- <rect key="frame" x="41" y="157" width="72" height="18"/>
- <buttonCell key="cell" type="check" title="Domain:" bezelStyle="regularSquare" imagePosition="left" alignment="right" inset="2" id="100179">
- <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="wideAreaCheckBoxChanged:" target="-2" id="317"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="267">
- <rect key="frame" x="222" y="119" width="109" height="32"/>
- <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100267">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="changeButtonPressed:" target="-2" id="273"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="348">
- <rect key="frame" x="18" y="185" width="514" height="34"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="510" id="lUQ-CZ-AzC"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Check the box and select a registration domain to enable Bonjour advertising beyond the local subnet." id="100348">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KqE-pc-8z0">
- <rect key="frame" x="113" y="119" width="109" height="32"/>
- <buttonCell key="cell" type="push" title="Select…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="TjV-QO-BW7">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="selectWideAreaDomainButtonPressed:" target="-2" id="d4S-la-iyw"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cxI-8W-6HI">
- <rect key="frame" x="119" y="155" width="411" height="22"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="Oao-6x-0X9">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="Reu-VC-MNz" customClass="CNBonjourDomainView">
- <rect key="frame" x="119" y="155" width="411" height="22"/>
- <constraints>
- <constraint firstAttribute="height" constant="22" id="l7c-m9-GcE"/>
- </constraints>
- </customView>
- </subviews>
- <constraints>
- <constraint firstItem="267" firstAttribute="leading" secondItem="KqE-pc-8z0" secondAttribute="trailing" constant="12" symbolic="YES" id="2kZ-P9-l60"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="centerY" secondItem="cxI-8W-6HI" secondAttribute="centerY" id="984-4H-aIz"/>
- <constraint firstItem="179" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="D3d-wd-QYX"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="top" secondItem="348" secondAttribute="bottom" constant="8" symbolic="YES" id="GcL-zf-7HQ"/>
- <constraint firstItem="348" firstAttribute="top" secondItem="99" secondAttribute="top" constant="20" symbolic="YES" id="HDQ-fd-PwR"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="height" secondItem="cxI-8W-6HI" secondAttribute="height" id="HUo-M5-tyi"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="width" secondItem="cxI-8W-6HI" secondAttribute="width" id="JML-71-xrY"/>
- <constraint firstItem="cxI-8W-6HI" firstAttribute="baseline" secondItem="179" secondAttribute="baseline" id="NX1-5X-UZI"/>
- <constraint firstItem="348" firstAttribute="leading" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="P0u-7u-LJv"/>
- <constraint firstItem="KqE-pc-8z0" firstAttribute="leading" secondItem="cxI-8W-6HI" secondAttribute="leading" id="RDS-Bc-KYd"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="d8L-Kb-W49"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="centerX" secondItem="cxI-8W-6HI" secondAttribute="centerX" id="dfu-qB-Ezj"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="179" secondAttribute="trailing" constant="8" symbolic="YES" id="rUC-3C-r32"/>
- <constraint firstItem="KqE-pc-8z0" firstAttribute="top" secondItem="cxI-8W-6HI" secondAttribute="bottom" constant="8" symbolic="YES" id="skb-cf-d2E"/>
- <constraint firstAttribute="trailing" secondItem="Reu-VC-MNz" secondAttribute="trailing" constant="20" symbolic="YES" id="ta5-1S-y3v"/>
- <constraint firstAttribute="trailing" secondItem="348" secondAttribute="trailing" constant="20" symbolic="YES" id="tr3-Ed-I8w"/>
- <constraint firstItem="267" firstAttribute="baseline" secondItem="KqE-pc-8z0" secondAttribute="baseline" id="vt0-3i-y05"/>
- <constraint firstItem="267" firstAttribute="width" secondItem="KqE-pc-8z0" secondAttribute="width" id="vxX-jt-NDx"/>
- <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="99" secondAttribute="leading" priority="499" constant="119" id="xdT-xB-bam"/>
- </constraints>
- </view>
- </tabViewItem>
- <tabViewItem label="Browsing" identifier="" id="322">
- <view key="view" id="323">
- <rect key="frame" x="10" y="33" width="550" height="239"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <scrollView horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="326">
- <rect key="frame" x="20" y="82" width="510" height="112"/>
- <clipView key="contentView" id="r8V-oO-qTS">
- <rect key="frame" x="1" y="1" width="508" height="110"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="22" id="327">
- <rect key="frame" x="0.0" y="0.0" width="508" height="110"/>
- <autoresizingMask key="autoresizingMask"/>
- <size key="intercellSpacing" width="3" height="2"/>
- <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
- <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
- <tableColumns>
- <tableColumn identifier="Enabled" width="35" minWidth="30" maxWidth="1000" id="328">
- <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
- <font key="font" metaFont="smallSystem"/>
- <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
- </tableHeaderCell>
- <buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="above" alignment="center" inset="2" id="358">
- <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
- <font key="font" metaFont="cellTitle"/>
- <connections>
- <action selector="enableBrowseDomainClicked:" target="-2" id="360"/>
- </connections>
- </buttonCell>
- </tableColumn>
- <tableColumn identifier="Domain" editable="NO" width="451.9541015625" minWidth="49.3466796875" maxWidth="1000" id="329">
- <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Domain">
- <font key="font" metaFont="smallSystem"/>
- <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
- </tableHeaderCell>
- <customCell key="dataCell" alignment="left" id="LhH-Yh-n33" customClass="CNBonjourDomainCell"/>
- </tableColumn>
- </tableColumns>
- <connections>
- <outlet property="dataSource" destination="-2" id="350"/>
- <outlet property="delegate" destination="-2" id="351"/>
- </connections>
- </tableView>
- </subviews>
- </clipView>
- <constraints>
- <constraint firstAttribute="height" constant="112" id="Pf1-34-QXp"/>
- </constraints>
- <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="100326">
- <rect key="frame" x="-100" y="-100" width="493" height="15"/>
- <autoresizingMask key="autoresizingMask"/>
- </scroller>
- <scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="200326">
- <rect key="frame" x="493" y="1" width="16" height="110"/>
- <autoresizingMask key="autoresizingMask"/>
- </scroller>
- </scrollView>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="330">
- <rect key="frame" x="18" y="202" width="514" height="17"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="510" id="xXz-Xx-cVE"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Choose which domains to browse using Wide-Area Bonjour." id="100330">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <button toolTip="Click to define shortcuts within applications." verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="381">
- <rect key="frame" x="20" y="49" width="24" height="26"/>
- <constraints>
- <constraint firstAttribute="width" constant="24" id="llU-4M-pcI"/>
- <constraint firstAttribute="height" constant="24" id="qD8-y4-ZkW"/>
- </constraints>
- <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" id="100381">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="addBrowseDomainClicked:" target="-2" id="386"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="383">
- <rect key="frame" x="43" y="49" width="24" height="26"/>
- <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" controlSize="small" state="on" borderStyle="border" id="100383">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="smallSystem"/>
- <string key="keyEquivalent">\7f</string>
- </buttonCell>
- <connections>
- <action selector="removeBrowseDomainClicked:" target="-2" id="387"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstItem="326" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="BHw-zP-zzH"/>
- <constraint firstItem="381" firstAttribute="centerY" secondItem="383" secondAttribute="centerY" id="Cae-WW-gYH"/>
- <constraint firstItem="326" firstAttribute="leading" secondItem="381" secondAttribute="leading" id="GCR-nb-Kbp"/>
- <constraint firstItem="381" firstAttribute="height" secondItem="383" secondAttribute="height" id="GYW-Vr-6c8"/>
- <constraint firstAttribute="trailing" secondItem="326" secondAttribute="trailing" constant="20" symbolic="YES" id="HGK-Ej-oKA"/>
- <constraint firstItem="383" firstAttribute="leading" secondItem="381" secondAttribute="trailing" constant="-1" id="KYa-XM-Qrh"/>
- <constraint firstAttribute="trailing" secondItem="330" secondAttribute="trailing" constant="20" symbolic="YES" id="Lkk-cy-gcf"/>
- <constraint firstItem="326" firstAttribute="top" secondItem="330" secondAttribute="bottom" constant="8" symbolic="YES" id="Pna-sQ-Iom"/>
- <constraint firstItem="381" firstAttribute="top" secondItem="326" secondAttribute="bottom" constant="8" symbolic="YES" id="YmF-BH-VOk"/>
- <constraint firstItem="381" firstAttribute="width" secondItem="383" secondAttribute="width" id="kJf-PK-P0M"/>
- <constraint firstItem="330" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="luC-Nv-ec5"/>
- <constraint firstItem="330" firstAttribute="top" secondItem="323" secondAttribute="top" constant="20" symbolic="YES" id="yVJ-PT-T31"/>
- </constraints>
- </view>
- </tabViewItem>
- </tabViewItems>
- </tabView>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="137" customClass="SFAuthorizationView">
- <rect key="frame" x="20" y="20" width="356" height="34"/>
- <constraints>
- <constraint firstAttribute="height" constant="34" id="T24-JY-FUW"/>
- <constraint firstAttribute="width" constant="356" id="hHs-jB-Xz8"/>
- </constraints>
- </customView>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="208">
- <rect key="frame" x="502" y="13" width="80" height="32"/>
- <buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100208">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="applyClicked:" target="-2" id="209"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="290">
- <rect key="frame" x="422" y="13" width="80" height="32"/>
- <buttonCell key="cell" type="push" title="Revert" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100290">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- </buttonCell>
- <connections>
- <action selector="revertClicked:" target="-2" id="293"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstAttribute="trailing" secondItem="100" secondAttribute="trailing" constant="20" symbolic="YES" id="DEs-Vk-n3D"/>
- <constraint firstItem="208" firstAttribute="width" secondItem="290" secondAttribute="width" id="GMB-MK-qPS"/>
- <constraint firstAttribute="bottom" secondItem="137" secondAttribute="bottom" constant="20" symbolic="YES" id="M0C-li-Dr1"/>
- <constraint firstItem="100" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="Ozi-Cv-NdV"/>
- <constraint firstAttribute="bottom" secondItem="208" secondAttribute="bottom" constant="20" symbolic="YES" id="PGr-uI-dUi"/>
- <constraint firstItem="290" firstAttribute="baseline" secondItem="208" secondAttribute="baseline" id="Rcf-kj-OQp"/>
- <constraint firstItem="137" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="dWc-kl-h8o"/>
- <constraint firstItem="208" firstAttribute="leading" secondItem="290" secondAttribute="trailing" constant="12" symbolic="YES" id="g3l-gL-wIw"/>
- <constraint firstItem="137" firstAttribute="top" secondItem="100" secondAttribute="bottom" constant="8" symbolic="YES" id="jDb-sm-pFt"/>
- <constraint firstItem="100" firstAttribute="top" secondItem="6" secondAttribute="top" constant="12" symbolic="YES" id="nWn-mH-iEl"/>
- <constraint firstAttribute="trailing" secondItem="208" secondAttribute="trailing" constant="20" symbolic="YES" id="xIc-XH-CzB"/>
- </constraints>
- </view>
- <point key="canvasLocation" x="6" y="454"/>
- </window>
- <window title="Shared Secret" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="255" userLabel="SharedSecret">
- <windowStyleMask key="styleMask" titled="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="591" y="108" width="496" height="148"/>
- <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
- <value key="minSize" type="size" width="213" height="107"/>
- <view key="contentView" id="254">
- <rect key="frame" x="0.0" y="0.0" width="496" height="148"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="256">
- <rect key="frame" x="96" y="81" width="380" height="22"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100256">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- <connections>
- <outlet property="delegate" destination="-2" id="283"/>
- <outlet property="nextKeyView" destination="257" id="288"/>
- </connections>
- </textField>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="257" customClass="NSSecureTextField">
- <rect key="frame" x="96" y="49" width="380" height="22"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100257">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- <connections>
- <outlet property="delegate" destination="-2" id="284"/>
- <outlet property="nextKeyView" destination="256" id="289"/>
- </connections>
- </textField>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="258">
- <rect key="frame" x="46" y="84" width="44" height="17"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name:" id="100258">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="259">
- <rect key="frame" x="24" y="52" width="66" height="17"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Password:" id="100259">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="260">
- <rect key="frame" x="400" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100260">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="279"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="261">
- <rect key="frame" x="318" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100261">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="280"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="262">
- <rect key="frame" x="18" y="111" width="460" height="17"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="456" id="Mua-9c-7eO"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a password if your DNS server requires authentication." id="100262">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- </subviews>
- <constraints>
- <constraint firstAttribute="trailing" secondItem="256" secondAttribute="trailing" constant="20" symbolic="YES" id="3mf-gO-3d5"/>
- <constraint firstAttribute="trailing" secondItem="262" secondAttribute="trailing" constant="20" symbolic="YES" id="7wb-gt-2py"/>
- <constraint firstItem="261" firstAttribute="baseline" secondItem="260" secondAttribute="baseline" id="9Qx-ne-W5G"/>
- <constraint firstItem="258" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="9jU-dY-JqX"/>
- <constraint firstItem="260" firstAttribute="top" secondItem="257" secondAttribute="bottom" constant="8" symbolic="YES" id="Dt1-uv-H2r"/>
- <constraint firstItem="262" firstAttribute="leading" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="El6-is-b6l"/>
- <constraint firstItem="256" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="IAp-Sj-ojh"/>
- <constraint firstItem="262" firstAttribute="top" secondItem="254" secondAttribute="top" constant="20" symbolic="YES" id="IKv-MA-MaG"/>
- <constraint firstItem="260" firstAttribute="leading" secondItem="261" secondAttribute="trailing" constant="12" symbolic="YES" id="Jih-R5-3WX"/>
- <constraint firstAttribute="trailing" secondItem="260" secondAttribute="trailing" constant="20" symbolic="YES" id="L7K-Si-lMS"/>
- <constraint firstItem="256" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="MGe-DK-IsJ"/>
- <constraint firstItem="257" firstAttribute="leading" secondItem="256" secondAttribute="leading" id="XiH-SB-ew9"/>
- <constraint firstItem="261" firstAttribute="width" secondItem="260" secondAttribute="width" id="ZBv-82-oHI"/>
- <constraint firstItem="257" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="ZSQ-Eu-kfv"/>
- <constraint firstItem="257" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="awk-Ih-h6t"/>
- <constraint firstAttribute="trailing" secondItem="257" secondAttribute="trailing" constant="20" symbolic="YES" id="b4B-N1-Kkw"/>
- <constraint firstItem="256" firstAttribute="top" secondItem="262" secondAttribute="bottom" constant="8" symbolic="YES" id="bMU-Gr-KAT"/>
- <constraint firstItem="259" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="djz-PT-u6u"/>
- <constraint firstItem="259" firstAttribute="baseline" secondItem="257" secondAttribute="baseline" id="eqD-gu-QY7"/>
- <constraint firstItem="256" firstAttribute="leading" secondItem="258" secondAttribute="trailing" constant="8" symbolic="YES" id="g6K-nY-Pnf"/>
- <constraint firstAttribute="bottom" secondItem="260" secondAttribute="bottom" constant="20" symbolic="YES" id="qad-Pr-uFC"/>
- <constraint firstItem="257" firstAttribute="top" secondItem="256" secondAttribute="bottom" constant="10" symbolic="YES" id="qyJ-gm-15K"/>
- <constraint firstItem="257" firstAttribute="leading" secondItem="259" secondAttribute="trailing" constant="8" symbolic="YES" id="sAe-2s-bxV"/>
- <constraint firstItem="258" firstAttribute="baseline" secondItem="256" secondAttribute="baseline" id="xZU-Nd-Q5f"/>
- </constraints>
- </view>
- <point key="canvasLocation" x="148" y="69"/>
- </window>
- <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="333" userLabel="AddDomain">
- <windowStyleMask key="styleMask" titled="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="634" y="377" width="496" height="220"/>
- <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
- <value key="minSize" type="size" width="213" height="107"/>
- <view key="contentView" id="334">
- <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="336">
- <rect key="frame" x="18" y="183" width="460" height="17"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="456" id="qTJ-tL-p1s"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to add to your list of Bonjour browse domains." id="100336">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="200327" customClass="CNDomainBrowserView">
- <rect key="frame" x="20" y="61" width="456" height="114"/>
- <constraints>
- <constraint firstAttribute="height" constant="114" id="ey8-36-A8G"/>
- </constraints>
- <userDefinedRuntimeAttributes>
- <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="NO"/>
- <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
- <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
- <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="NO"/>
- </userDefinedRuntimeAttributes>
- </customView>
- <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="340">
- <rect key="frame" x="400" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100340">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="365"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="341">
- <rect key="frame" x="318" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100341">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="364"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstItem="341" firstAttribute="width" secondItem="340" secondAttribute="width" id="1kP-hH-4fg"/>
- <constraint firstItem="336" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="6p2-FN-dgI"/>
- <constraint firstItem="200327" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="BFf-ab-vji"/>
- <constraint firstItem="341" firstAttribute="baseline" secondItem="340" secondAttribute="baseline" id="DdL-N2-sRf"/>
- <constraint firstItem="336" firstAttribute="top" secondItem="334" secondAttribute="top" constant="20" symbolic="YES" id="Iei-fi-sMQ"/>
- <constraint firstItem="340" firstAttribute="top" secondItem="200327" secondAttribute="bottom" constant="20" symbolic="YES" id="Ouj-CX-0R3"/>
- <constraint firstAttribute="trailing" secondItem="200327" secondAttribute="trailing" constant="20" symbolic="YES" id="QWi-nn-fZb"/>
- <constraint firstItem="200327" firstAttribute="top" secondItem="336" secondAttribute="bottom" constant="8" symbolic="YES" id="f1Y-2w-Xl7"/>
- <constraint firstAttribute="trailing" secondItem="336" secondAttribute="trailing" constant="20" symbolic="YES" id="gOk-i6-e6u"/>
- <constraint firstAttribute="trailing" secondItem="340" secondAttribute="trailing" constant="20" symbolic="YES" id="gvy-DL-dCw"/>
- <constraint firstAttribute="bottom" secondItem="340" secondAttribute="bottom" constant="20" symbolic="YES" id="i1j-hc-gtt"/>
- <constraint firstItem="340" firstAttribute="leading" secondItem="341" secondAttribute="trailing" constant="12" symbolic="YES" id="yRJ-0k-a3r"/>
- </constraints>
- </view>
- <point key="canvasLocation" x="-27" y="-234"/>
- </window>
- <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NFb-eI-atL" userLabel="AddDomainManual">
- <windowStyleMask key="styleMask" titled="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="634" y="377" width="496" height="133"/>
- <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
- <value key="minSize" type="size" width="213" height="107"/>
- <view key="contentView" id="gUJ-3k-BQQ">
- <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="aoV-3v-A7q">
- <rect key="frame" x="400" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Jo3-6e-vxc">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="hMi-BR-qQY"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a0y-0s-TTY">
- <rect key="frame" x="318" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="qne-aW-QHl">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="eUl-Y1-c5S"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Sfp-nO-NP2">
- <rect key="frame" x="36" y="52" width="54" height="17"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="b6L-KA-Dqu">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Myg-XJ-ngM">
- <rect key="frame" x="18" y="79" width="460" height="34"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="456" id="nwj-Vn-nBx"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following domain will be added to your list of Bonjour browse domains." id="m5w-3d-gfR">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="W2d-Us-Cpm">
- <rect key="frame" x="96" y="49" width="380" height="22"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="kJz-0i-YUX">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- </subviews>
- <constraints>
- <constraint firstAttribute="trailing" secondItem="W2d-Us-Cpm" secondAttribute="trailing" constant="20" symbolic="YES" id="08z-5S-y1p"/>
- <constraint firstAttribute="trailing" secondItem="Myg-XJ-ngM" secondAttribute="trailing" constant="20" symbolic="YES" id="2qd-6o-hRs"/>
- <constraint firstAttribute="trailing" secondItem="aoV-3v-A7q" secondAttribute="trailing" constant="20" symbolic="YES" id="5WH-eg-Ibw"/>
- <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" priority="499" constant="96" id="KBy-nt-u24"/>
- <constraint firstItem="aoV-3v-A7q" firstAttribute="baseline" secondItem="a0y-0s-TTY" secondAttribute="baseline" id="L8X-K0-cNZ"/>
- <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="Sfp-nO-NP2" secondAttribute="trailing" constant="8" symbolic="YES" id="Pw7-gK-pJO"/>
- <constraint firstItem="Myg-XJ-ngM" firstAttribute="top" secondItem="gUJ-3k-BQQ" secondAttribute="top" constant="20" symbolic="YES" id="Vkn-zN-QmY"/>
- <constraint firstAttribute="bottom" secondItem="aoV-3v-A7q" secondAttribute="bottom" constant="20" symbolic="YES" id="aJb-Dk-Ofa"/>
- <constraint firstItem="aoV-3v-A7q" firstAttribute="top" secondItem="W2d-Us-Cpm" secondAttribute="bottom" constant="8" symbolic="YES" id="bbw-LB-NG3"/>
- <constraint firstItem="Myg-XJ-ngM" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="cab-6m-9M7"/>
- <constraint firstItem="W2d-Us-Cpm" firstAttribute="top" secondItem="Myg-XJ-ngM" secondAttribute="bottom" constant="8" symbolic="YES" id="ewM-hb-zj3"/>
- <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="jsT-pp-iwi"/>
- <constraint firstItem="Sfp-nO-NP2" firstAttribute="baseline" secondItem="W2d-Us-Cpm" secondAttribute="baseline" id="qPo-ba-jjr"/>
- <constraint firstItem="aoV-3v-A7q" firstAttribute="leading" secondItem="a0y-0s-TTY" secondAttribute="trailing" constant="12" symbolic="YES" id="tzd-P2-c6b"/>
- <constraint firstItem="Sfp-nO-NP2" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="vVs-34-dSS"/>
- <constraint firstItem="aoV-3v-A7q" firstAttribute="width" secondItem="a0y-0s-TTY" secondAttribute="width" id="xg1-eb-4Pj"/>
- </constraints>
- </view>
- <point key="canvasLocation" x="-27" y="-524"/>
- </window>
- <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="ail-If-2Xp" userLabel="SelectRegDomain">
- <windowStyleMask key="styleMask" titled="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="634" y="377" width="496" height="220"/>
- <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
- <value key="minSize" type="size" width="213" height="107"/>
- <view key="contentView" id="W37-VK-yC5">
- <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q4Y-tT-1h7">
- <rect key="frame" x="18" y="183" width="460" height="17"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="456" id="zF0-CN-3xD"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to use as your Bonjour registration domain." id="EDB-Ul-M1P">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <customView translatesAutoresizingMaskIntoConstraints="NO" id="agb-WV-smo" customClass="CNDomainBrowserView">
- <rect key="frame" x="20" y="61" width="456" height="114"/>
- <constraints>
- <constraint firstAttribute="height" constant="114" id="3JN-68-aTf"/>
- </constraints>
- <userDefinedRuntimeAttributes>
- <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="YES"/>
- <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
- <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
- <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="YES"/>
- </userDefinedRuntimeAttributes>
- </customView>
- <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="8fZ-4V-xd6">
- <rect key="frame" x="400" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eLF-AD-BgY">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="HFg-iF-1qy"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I6S-g0-R0G">
- <rect key="frame" x="318" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="a1o-he-Kv7">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="SQP-5g-qGG"/>
- </connections>
- </button>
- </subviews>
- <constraints>
- <constraint firstItem="8fZ-4V-xd6" firstAttribute="top" secondItem="agb-WV-smo" secondAttribute="bottom" constant="20" symbolic="YES" id="4cD-Af-ApJ"/>
- <constraint firstItem="q4Y-tT-1h7" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="8fj-II-NeF"/>
- <constraint firstItem="q4Y-tT-1h7" firstAttribute="top" secondItem="W37-VK-yC5" secondAttribute="top" constant="20" symbolic="YES" id="Bq5-8Z-4eY"/>
- <constraint firstItem="agb-WV-smo" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="Kex-pV-3tR"/>
- <constraint firstAttribute="trailing" secondItem="q4Y-tT-1h7" secondAttribute="trailing" constant="20" symbolic="YES" id="Piu-PE-SEc"/>
- <constraint firstItem="agb-WV-smo" firstAttribute="top" secondItem="q4Y-tT-1h7" secondAttribute="bottom" constant="8" symbolic="YES" id="Spl-BU-U7l"/>
- <constraint firstItem="8fZ-4V-xd6" firstAttribute="width" secondItem="I6S-g0-R0G" secondAttribute="width" id="Xx2-3v-4H5"/>
- <constraint firstItem="8fZ-4V-xd6" firstAttribute="leading" secondItem="I6S-g0-R0G" secondAttribute="trailing" constant="12" symbolic="YES" id="aly-0r-bvb"/>
- <constraint firstAttribute="bottom" secondItem="8fZ-4V-xd6" secondAttribute="bottom" constant="20" symbolic="YES" id="eqT-TT-gxE"/>
- <constraint firstItem="8fZ-4V-xd6" firstAttribute="baseline" secondItem="I6S-g0-R0G" secondAttribute="baseline" id="h1B-xs-zFp"/>
- <constraint firstAttribute="trailing" secondItem="agb-WV-smo" secondAttribute="trailing" constant="20" symbolic="YES" id="xLH-br-4Uh"/>
- <constraint firstAttribute="trailing" secondItem="8fZ-4V-xd6" secondAttribute="trailing" constant="20" symbolic="YES" id="xiF-Cr-13M"/>
- </constraints>
- </view>
- <point key="canvasLocation" x="538" y="-234"/>
- </window>
- <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="he2-0K-CWy" userLabel="SelectRegDomainManual">
- <windowStyleMask key="styleMask" titled="YES"/>
- <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
- <rect key="contentRect" x="634" y="377" width="496" height="133"/>
- <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
- <value key="minSize" type="size" width="213" height="107"/>
- <view key="contentView" id="FYv-ly-yOd">
- <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
- <autoresizingMask key="autoresizingMask"/>
- <subviews>
- <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="sau-gD-LVt">
- <rect key="frame" x="400" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="jAh-nT-Qwg">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="ySI-9p-3tZ"/>
- </connections>
- </button>
- <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ypd-8h-xfJ">
- <rect key="frame" x="318" y="13" width="82" height="32"/>
- <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Nd2-rR-DtX">
- <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
- <font key="font" metaFont="system"/>
- <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
- </buttonCell>
- <connections>
- <action selector="closeMyCustomSheet:" target="-2" id="YM3-jW-TNM"/>
- </connections>
- </button>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="die-Uf-Bn9">
- <rect key="frame" x="36" y="52" width="54" height="17"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="ZIy-WQ-OIZ">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="06e-WM-3MP">
- <rect key="frame" x="18" y="79" width="460" height="34"/>
- <constraints>
- <constraint firstAttribute="width" priority="499" constant="456" id="ilh-EM-DG1"/>
- </constraints>
- <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following registration domain will be used by Bonjour to advertise beyond the local subnet." id="SLP-nX-Q2C">
- <font key="font" metaFont="systemBold"/>
- <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OEh-fL-Ol6">
- <rect key="frame" x="96" y="49" width="380" height="22"/>
- <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="aIe-CQ-mQ3">
- <font key="font" metaFont="system"/>
- <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
- <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
- </textFieldCell>
- </textField>
- </subviews>
- <constraints>
- <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" priority="499" constant="96" id="1Nc-CQ-lXd"/>
- <constraint firstItem="06e-WM-3MP" firstAttribute="top" secondItem="FYv-ly-yOd" secondAttribute="top" constant="20" symbolic="YES" id="5wy-Ji-7tZ"/>
- <constraint firstItem="OEh-fL-Ol6" firstAttribute="top" secondItem="06e-WM-3MP" secondAttribute="bottom" constant="8" symbolic="YES" id="7BD-rk-RTl"/>
- <constraint firstItem="sau-gD-LVt" firstAttribute="leading" secondItem="Ypd-8h-xfJ" secondAttribute="trailing" constant="12" symbolic="YES" id="7oo-eg-nGA"/>
- <constraint firstItem="die-Uf-Bn9" firstAttribute="baseline" secondItem="OEh-fL-Ol6" secondAttribute="baseline" id="DbC-UI-YFz"/>
- <constraint firstItem="die-Uf-Bn9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="Ip2-Q3-r3l"/>
- <constraint firstAttribute="trailing" secondItem="sau-gD-LVt" secondAttribute="trailing" constant="20" symbolic="YES" id="Jce-ky-wTf"/>
- <constraint firstItem="sau-gD-LVt" firstAttribute="width" secondItem="Ypd-8h-xfJ" secondAttribute="width" id="NkV-L2-e4p"/>
- <constraint firstItem="sau-gD-LVt" firstAttribute="top" secondItem="OEh-fL-Ol6" secondAttribute="bottom" constant="8" symbolic="YES" id="Omq-c5-SZQ"/>
- <constraint firstAttribute="trailing" secondItem="06e-WM-3MP" secondAttribute="trailing" constant="20" symbolic="YES" id="U0T-5s-Jip"/>
- <constraint firstAttribute="bottom" secondItem="sau-gD-LVt" secondAttribute="bottom" constant="20" symbolic="YES" id="cWG-NL-TzC"/>
- <constraint firstAttribute="trailing" secondItem="OEh-fL-Ol6" secondAttribute="trailing" constant="20" symbolic="YES" id="igv-0W-kuw"/>
- <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="die-Uf-Bn9" secondAttribute="trailing" constant="8" symbolic="YES" id="j71-MK-aiv"/>
- <constraint firstItem="sau-gD-LVt" firstAttribute="baseline" secondItem="Ypd-8h-xfJ" secondAttribute="baseline" id="t9l-JC-Ab2"/>
- <constraint firstItem="06e-WM-3MP" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wIW-Ja-ih6"/>
- <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wia-Av-Bte"/>
- </constraints>
- </view>
- <point key="canvasLocation" x="538" y="-525"/>
- </window>
- </objects>
- <resources>
- <image name="NSAddTemplate" width="11" height="11"/>
- <image name="NSRemoveTemplate" width="11" height="11"/>
- </resources>
-</document>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14724.4" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+ <dependencies>
+ <deployment identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14724.4"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="DNSServiceDiscoveryPref">
+ <connections>
+ <outlet property="_initialKeyView" destination="107" id="235"/>
+ <outlet property="_lastKeyView" destination="107" id="183"/>
+ <outlet property="_window" destination="12" id="142"/>
+ <outlet property="addBrowseDomainButton" destination="381" id="384"/>
+ <outlet property="addBrowseDomainManualWindow" destination="NFb-eI-atL" id="0AN-Mr-e84"/>
+ <outlet property="addBrowseDomainWindow" destination="333" id="363"/>
+ <outlet property="applyButton" destination="208" id="238"/>
+ <outlet property="bonjourBrowserView" destination="200327" id="200328"/>
+ <outlet property="browseCancelButton" destination="341" id="375"/>
+ <outlet property="browseDomainList" destination="327" id="349"/>
+ <outlet property="browseDomainTextField" destination="W2d-Us-Cpm" id="kOZ-wG-OPp"/>
+ <outlet property="browseOKButton" destination="340" id="376"/>
+ <outlet property="comboAuthButton" destination="137" id="201"/>
+ <outlet property="hostName" destination="107" id="224"/>
+ <outlet property="hostNameSharedSecretButton" destination="263" id="270"/>
+ <outlet property="regDomainTextField" destination="OEh-fL-Ol6" id="Dv0-aj-gah"/>
+ <outlet property="regDomainView" destination="Reu-VC-MNz" id="4I2-zS-sdq"/>
+ <outlet property="registrationBrowserView" destination="agb-WV-smo" id="j7U-ZK-LIb"/>
+ <outlet property="registrationSelectButton" destination="KqE-pc-8z0" id="CJS-ml-2CA"/>
+ <outlet property="registrationSharedSecretButton" destination="267" id="268"/>
+ <outlet property="removeBrowseDomainButton" destination="383" id="385"/>
+ <outlet property="revertButton" destination="290" id="292"/>
+ <outlet property="secretCancelButton" destination="341" id="373"/>
+ <outlet property="secretOKButton" destination="260" id="377"/>
+ <outlet property="selectRegistrationDomainManualWindow" destination="he2-0K-CWy" id="eXD-7o-XQU"/>
+ <outlet property="selectRegistrationDomainWindow" destination="ail-If-2Xp" id="34V-c7-D3b"/>
+ <outlet property="sharedSecretName" destination="256" id="275"/>
+ <outlet property="sharedSecretValue" destination="257" id="276"/>
+ <outlet property="sharedSecretWindow" destination="255" id="274"/>
+ <outlet property="statusImageView" destination="320" id="321"/>
+ <outlet property="tabView" destination="100" id="380"/>
+ <outlet property="wideAreaCheckBox" destination="179" id="240"/>
+ </connections>
+ </customObject>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <window title="Bonjour" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" deferred="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="12" userLabel="PrefPane">
+ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="51" y="335" width="596" height="343"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213.66399999999999" height="10"/>
+ <view key="contentView" id="6">
+ <rect key="frame" x="0.0" y="0.0" width="596" height="343"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <tabView translatesAutoresizingMaskIntoConstraints="NO" id="100">
+ <rect key="frame" x="13" y="52" width="570" height="285"/>
+ <font key="font" metaFont="system"/>
+ <tabViewItems>
+ <tabViewItem label="Hostname" identifier="1" id="102">
+ <view key="view" id="101">
+ <rect key="frame" x="10" y="33" width="550" height="239"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="107">
+ <rect key="frame" x="119" y="155" width="383" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" placeholderString="steve.example.com" drawsBackground="YES" id="100107">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <connections>
+ <outlet property="delegate" destination="-2" id="227"/>
+ </connections>
+ </textField>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="108">
+ <rect key="frame" x="43" y="158" width="70" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Hostname:" id="100108">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="117">
+ <rect key="frame" x="18" y="185" width="514" height="34"/>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a hostname for this computer. Other computers on the Internet will be able to reach your computer using this hostname." id="100117">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="263">
+ <rect key="frame" x="113" y="119" width="109" height="32"/>
+ <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100263">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="changeButtonPressed:" target="-2" id="272"/>
+ </connections>
+ </button>
+ <imageView translatesAutoresizingMaskIntoConstraints="NO" id="320">
+ <rect key="frame" x="510" y="156" width="20" height="20"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="20" id="7Qf-g0-5SV"/>
+ <constraint firstAttribute="height" constant="20" id="bfL-QJ-KFw"/>
+ </constraints>
+ <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="left" imageScaling="proportionallyDown" id="100320"/>
+ </imageView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="263" firstAttribute="leading" secondItem="107" secondAttribute="leading" id="4Dv-gf-Cjr"/>
+ <constraint firstAttribute="trailing" secondItem="117" secondAttribute="trailing" constant="20" symbolic="YES" id="5zc-LQ-OC8"/>
+ <constraint firstItem="320" firstAttribute="leading" secondItem="107" secondAttribute="trailing" constant="8" symbolic="YES" id="BIu-YL-Fr2"/>
+ <constraint firstItem="263" firstAttribute="top" secondItem="107" secondAttribute="bottom" constant="8" symbolic="YES" id="K1w-WG-3KW"/>
+ <constraint firstItem="107" firstAttribute="centerY" secondItem="320" secondAttribute="centerY" id="LlU-Oy-3va"/>
+ <constraint firstItem="107" firstAttribute="top" secondItem="117" secondAttribute="bottom" constant="8" symbolic="YES" id="V8c-G1-gsR"/>
+ <constraint firstItem="117" firstAttribute="top" secondItem="101" secondAttribute="top" constant="20" symbolic="YES" id="Xnz-bz-ahU"/>
+ <constraint firstItem="117" firstAttribute="leading" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="ZIG-S4-cst"/>
+ <constraint firstItem="107" firstAttribute="leading" secondItem="108" secondAttribute="trailing" constant="8" symbolic="YES" id="cQG-zv-Ozo"/>
+ <constraint firstItem="108" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="foH-DQ-yvJ"/>
+ <constraint firstItem="107" firstAttribute="leading" secondItem="101" secondAttribute="leading" priority="499" constant="119" id="qGZ-fm-Wgf"/>
+ <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="263" secondAttribute="trailing" constant="20" symbolic="YES" id="vFp-zd-1ea"/>
+ <constraint firstAttribute="trailing" secondItem="320" secondAttribute="trailing" constant="20" symbolic="YES" id="w2R-Kc-Tj3"/>
+ <constraint firstItem="108" firstAttribute="baseline" secondItem="107" secondAttribute="baseline" id="xcr-32-mbs"/>
+ </constraints>
+ </view>
+ </tabViewItem>
+ <tabViewItem label="Registration" identifier="2" id="98">
+ <view key="view" id="99">
+ <rect key="frame" x="10" y="33" width="550" height="239"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <button translatesAutoresizingMaskIntoConstraints="NO" id="179">
+ <rect key="frame" x="41" y="157" width="72" height="18"/>
+ <buttonCell key="cell" type="check" title="Domain:" bezelStyle="regularSquare" imagePosition="left" alignment="right" inset="2" id="100179">
+ <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="wideAreaCheckBoxChanged:" target="-2" id="317"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="267">
+ <rect key="frame" x="222" y="119" width="109" height="32"/>
+ <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100267">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="changeButtonPressed:" target="-2" id="273"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="348">
+ <rect key="frame" x="18" y="185" width="514" height="34"/>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Check the box and select a registration domain to enable Bonjour advertising beyond the local subnet." id="100348">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KqE-pc-8z0">
+ <rect key="frame" x="113" y="119" width="109" height="32"/>
+ <buttonCell key="cell" type="push" title="Select…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="TjV-QO-BW7">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="selectWideAreaDomainButtonPressed:" target="-2" id="d4S-la-iyw"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cxI-8W-6HI">
+ <rect key="frame" x="119" y="155" width="411" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="Oao-6x-0X9">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="Reu-VC-MNz" customClass="CNBonjourDomainView">
+ <rect key="frame" x="119" y="155" width="411" height="22"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="22" id="l7c-m9-GcE"/>
+ </constraints>
+ </customView>
+ </subviews>
+ <constraints>
+ <constraint firstItem="267" firstAttribute="leading" secondItem="KqE-pc-8z0" secondAttribute="trailing" constant="12" symbolic="YES" id="2kZ-P9-l60"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="centerY" secondItem="cxI-8W-6HI" secondAttribute="centerY" id="984-4H-aIz"/>
+ <constraint firstItem="179" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="D3d-wd-QYX"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="top" secondItem="348" secondAttribute="bottom" constant="8" symbolic="YES" id="GcL-zf-7HQ"/>
+ <constraint firstItem="348" firstAttribute="top" secondItem="99" secondAttribute="top" constant="20" symbolic="YES" id="HDQ-fd-PwR"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="height" secondItem="cxI-8W-6HI" secondAttribute="height" id="HUo-M5-tyi"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="width" secondItem="cxI-8W-6HI" secondAttribute="width" id="JML-71-xrY"/>
+ <constraint firstItem="cxI-8W-6HI" firstAttribute="baseline" secondItem="179" secondAttribute="baseline" id="NX1-5X-UZI"/>
+ <constraint firstItem="348" firstAttribute="leading" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="P0u-7u-LJv"/>
+ <constraint firstItem="KqE-pc-8z0" firstAttribute="leading" secondItem="cxI-8W-6HI" secondAttribute="leading" id="RDS-Bc-KYd"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="d8L-Kb-W49"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="centerX" secondItem="cxI-8W-6HI" secondAttribute="centerX" id="dfu-qB-Ezj"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="179" secondAttribute="trailing" constant="8" symbolic="YES" id="rUC-3C-r32"/>
+ <constraint firstItem="KqE-pc-8z0" firstAttribute="top" secondItem="cxI-8W-6HI" secondAttribute="bottom" constant="8" symbolic="YES" id="skb-cf-d2E"/>
+ <constraint firstAttribute="trailing" secondItem="Reu-VC-MNz" secondAttribute="trailing" constant="20" symbolic="YES" id="ta5-1S-y3v"/>
+ <constraint firstAttribute="trailing" secondItem="348" secondAttribute="trailing" constant="20" symbolic="YES" id="tr3-Ed-I8w"/>
+ <constraint firstItem="267" firstAttribute="baseline" secondItem="KqE-pc-8z0" secondAttribute="baseline" id="vt0-3i-y05"/>
+ <constraint firstItem="267" firstAttribute="width" secondItem="KqE-pc-8z0" secondAttribute="width" id="vxX-jt-NDx"/>
+ <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="267" secondAttribute="trailing" constant="20" symbolic="YES" id="w1s-Ah-Gmw"/>
+ <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="99" secondAttribute="leading" priority="499" constant="119" id="xdT-xB-bam"/>
+ </constraints>
+ </view>
+ </tabViewItem>
+ <tabViewItem label="Browsing" identifier="" id="322">
+ <view key="view" id="323">
+ <rect key="frame" x="10" y="33" width="550" height="239"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <scrollView horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="326">
+ <rect key="frame" x="20" y="82" width="510" height="112"/>
+ <clipView key="contentView" id="r8V-oO-qTS">
+ <rect key="frame" x="1" y="1" width="508" height="110"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="22" id="327">
+ <rect key="frame" x="0.0" y="0.0" width="508" height="110"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <size key="intercellSpacing" width="3" height="2"/>
+ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+ <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+ <tableColumns>
+ <tableColumn identifier="Enabled" width="35" minWidth="30" maxWidth="1000" id="328">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
+ </tableHeaderCell>
+ <buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="above" alignment="center" inset="2" id="358">
+ <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+ <font key="font" metaFont="cellTitle"/>
+ <connections>
+ <action selector="enableBrowseDomainClicked:" target="-2" id="360"/>
+ </connections>
+ </buttonCell>
+ </tableColumn>
+ <tableColumn identifier="Domain" editable="NO" width="451.9541015625" minWidth="49.3466796875" maxWidth="1000" id="329">
+ <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Domain">
+ <font key="font" metaFont="smallSystem"/>
+ <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
+ </tableHeaderCell>
+ <customCell key="dataCell" alignment="left" id="LhH-Yh-n33" customClass="CNBonjourDomainCell"/>
+ </tableColumn>
+ </tableColumns>
+ <connections>
+ <outlet property="dataSource" destination="-2" id="350"/>
+ <outlet property="delegate" destination="-2" id="351"/>
+ </connections>
+ </tableView>
+ </subviews>
+ </clipView>
+ <constraints>
+ <constraint firstAttribute="height" constant="112" id="Pf1-34-QXp"/>
+ </constraints>
+ <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="100326">
+ <rect key="frame" x="-100" y="-100" width="493" height="15"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="200326">
+ <rect key="frame" x="493" y="1" width="16" height="110"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </scroller>
+ </scrollView>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="330">
+ <rect key="frame" x="18" y="202" width="514" height="17"/>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Choose which domains to browse using Wide-Area Bonjour." id="100330">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button toolTip="Click to define shortcuts within applications." verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="381">
+ <rect key="frame" x="20" y="49" width="24" height="26"/>
+ <constraints>
+ <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="24" id="llU-4M-pcI"/>
+ <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="24" id="qD8-y4-ZkW"/>
+ </constraints>
+ <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" id="100381">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="addBrowseDomainClicked:" target="-2" id="386"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="383">
+ <rect key="frame" x="43" y="49" width="24" height="26"/>
+ <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" controlSize="small" state="on" borderStyle="border" id="100383">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="smallSystem"/>
+ <string key="keyEquivalent">\7f</string>
+ </buttonCell>
+ <connections>
+ <action selector="removeBrowseDomainClicked:" target="-2" id="387"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="326" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="BHw-zP-zzH"/>
+ <constraint firstItem="381" firstAttribute="centerY" secondItem="383" secondAttribute="centerY" id="Cae-WW-gYH"/>
+ <constraint firstItem="326" firstAttribute="leading" secondItem="381" secondAttribute="leading" id="GCR-nb-Kbp"/>
+ <constraint firstItem="381" firstAttribute="height" secondItem="383" secondAttribute="height" id="GYW-Vr-6c8"/>
+ <constraint firstAttribute="trailing" secondItem="326" secondAttribute="trailing" constant="20" symbolic="YES" id="HGK-Ej-oKA"/>
+ <constraint firstItem="383" firstAttribute="leading" secondItem="381" secondAttribute="trailing" constant="-1" id="KYa-XM-Qrh"/>
+ <constraint firstAttribute="trailing" secondItem="330" secondAttribute="trailing" constant="20" symbolic="YES" id="Lkk-cy-gcf"/>
+ <constraint firstItem="326" firstAttribute="top" secondItem="330" secondAttribute="bottom" constant="8" symbolic="YES" id="Pna-sQ-Iom"/>
+ <constraint firstItem="381" firstAttribute="top" secondItem="326" secondAttribute="bottom" constant="8" symbolic="YES" id="YmF-BH-VOk"/>
+ <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="383" secondAttribute="trailing" constant="20" symbolic="YES" id="aY5-XO-vJN"/>
+ <constraint firstItem="381" firstAttribute="width" secondItem="383" secondAttribute="width" id="kJf-PK-P0M"/>
+ <constraint firstItem="330" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="luC-Nv-ec5"/>
+ <constraint firstItem="330" firstAttribute="top" secondItem="323" secondAttribute="top" constant="20" symbolic="YES" id="yVJ-PT-T31"/>
+ </constraints>
+ </view>
+ </tabViewItem>
+ </tabViewItems>
+ </tabView>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="137" customClass="SFAuthorizationView">
+ <rect key="frame" x="20" y="20" width="356" height="34"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="34" id="T24-JY-FUW"/>
+ <constraint firstAttribute="width" constant="356" id="hHs-jB-Xz8"/>
+ </constraints>
+ </customView>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="208">
+ <rect key="frame" x="502" y="13" width="80" height="32"/>
+ <buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100208">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="applyClicked:" target="-2" id="209"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="290">
+ <rect key="frame" x="422" y="13" width="80" height="32"/>
+ <buttonCell key="cell" type="push" title="Revert" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100290">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ </buttonCell>
+ <connections>
+ <action selector="revertClicked:" target="-2" id="293"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="290" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="0rt-dY-Rii"/>
+ <constraint firstAttribute="trailing" secondItem="100" secondAttribute="trailing" constant="20" symbolic="YES" id="DEs-Vk-n3D"/>
+ <constraint firstItem="208" firstAttribute="width" secondItem="290" secondAttribute="width" id="GMB-MK-qPS"/>
+ <constraint firstAttribute="bottom" secondItem="137" secondAttribute="bottom" constant="20" symbolic="YES" id="M0C-li-Dr1"/>
+ <constraint firstItem="100" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="Ozi-Cv-NdV"/>
+ <constraint firstAttribute="bottom" secondItem="208" secondAttribute="bottom" constant="20" symbolic="YES" id="PGr-uI-dUi"/>
+ <constraint firstItem="290" firstAttribute="baseline" secondItem="208" secondAttribute="baseline" id="Rcf-kj-OQp"/>
+ <constraint firstItem="137" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="dWc-kl-h8o"/>
+ <constraint firstItem="208" firstAttribute="leading" secondItem="290" secondAttribute="trailing" constant="12" symbolic="YES" id="g3l-gL-wIw"/>
+ <constraint firstItem="137" firstAttribute="top" secondItem="100" secondAttribute="bottom" constant="8" symbolic="YES" id="jDb-sm-pFt"/>
+ <constraint firstItem="100" firstAttribute="top" secondItem="6" secondAttribute="top" constant="12" symbolic="YES" id="nWn-mH-iEl"/>
+ <constraint firstAttribute="trailing" secondItem="208" secondAttribute="trailing" constant="20" symbolic="YES" id="xIc-XH-CzB"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="6" y="454"/>
+ </window>
+ <window title="Shared Secret" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="255" userLabel="SharedSecret">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="591" y="108" width="496" height="148"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="254">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="148"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="256">
+ <rect key="frame" x="96" y="81" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100256">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <connections>
+ <outlet property="delegate" destination="-2" id="283"/>
+ <outlet property="nextKeyView" destination="257" id="288"/>
+ </connections>
+ </textField>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="257" customClass="NSSecureTextField">
+ <rect key="frame" x="96" y="49" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100257">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ <connections>
+ <outlet property="delegate" destination="-2" id="284"/>
+ <outlet property="nextKeyView" destination="256" id="289"/>
+ </connections>
+ </textField>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="258">
+ <rect key="frame" x="46" y="84" width="44" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name:" id="100258">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="259">
+ <rect key="frame" x="24" y="52" width="66" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Password:" id="100259">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="260">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100260">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="279"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="261">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100261">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="280"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="262">
+ <rect key="frame" x="18" y="111" width="460" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="Mua-9c-7eO"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a password if your DNS server requires authentication." id="100262">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="256" secondAttribute="trailing" constant="20" symbolic="YES" id="3mf-gO-3d5"/>
+ <constraint firstAttribute="trailing" secondItem="262" secondAttribute="trailing" constant="20" symbolic="YES" id="7wb-gt-2py"/>
+ <constraint firstItem="261" firstAttribute="baseline" secondItem="260" secondAttribute="baseline" id="9Qx-ne-W5G"/>
+ <constraint firstItem="258" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="9jU-dY-JqX"/>
+ <constraint firstItem="260" firstAttribute="top" secondItem="257" secondAttribute="bottom" constant="8" symbolic="YES" id="Dt1-uv-H2r"/>
+ <constraint firstItem="262" firstAttribute="leading" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="El6-is-b6l"/>
+ <constraint firstItem="256" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="IAp-Sj-ojh"/>
+ <constraint firstItem="262" firstAttribute="top" secondItem="254" secondAttribute="top" constant="20" symbolic="YES" id="IKv-MA-MaG"/>
+ <constraint firstItem="260" firstAttribute="leading" secondItem="261" secondAttribute="trailing" constant="12" symbolic="YES" id="Jih-R5-3WX"/>
+ <constraint firstAttribute="trailing" secondItem="260" secondAttribute="trailing" constant="20" symbolic="YES" id="L7K-Si-lMS"/>
+ <constraint firstItem="256" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="MGe-DK-IsJ"/>
+ <constraint firstItem="257" firstAttribute="leading" secondItem="256" secondAttribute="leading" id="XiH-SB-ew9"/>
+ <constraint firstItem="261" firstAttribute="width" secondItem="260" secondAttribute="width" id="ZBv-82-oHI"/>
+ <constraint firstItem="257" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="ZSQ-Eu-kfv"/>
+ <constraint firstItem="257" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="awk-Ih-h6t"/>
+ <constraint firstAttribute="trailing" secondItem="257" secondAttribute="trailing" constant="20" symbolic="YES" id="b4B-N1-Kkw"/>
+ <constraint firstItem="256" firstAttribute="top" secondItem="262" secondAttribute="bottom" constant="8" symbolic="YES" id="bMU-Gr-KAT"/>
+ <constraint firstItem="259" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="djz-PT-u6u"/>
+ <constraint firstItem="259" firstAttribute="baseline" secondItem="257" secondAttribute="baseline" id="eqD-gu-QY7"/>
+ <constraint firstItem="256" firstAttribute="leading" secondItem="258" secondAttribute="trailing" constant="8" symbolic="YES" id="g6K-nY-Pnf"/>
+ <constraint firstAttribute="bottom" secondItem="260" secondAttribute="bottom" constant="20" symbolic="YES" id="qad-Pr-uFC"/>
+ <constraint firstItem="257" firstAttribute="top" secondItem="256" secondAttribute="bottom" constant="10" symbolic="YES" id="qyJ-gm-15K"/>
+ <constraint firstItem="257" firstAttribute="leading" secondItem="259" secondAttribute="trailing" constant="8" symbolic="YES" id="sAe-2s-bxV"/>
+ <constraint firstItem="258" firstAttribute="baseline" secondItem="256" secondAttribute="baseline" id="xZU-Nd-Q5f"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="148" y="69"/>
+ </window>
+ <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="333" userLabel="AddDomain">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="220"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="334">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="336">
+ <rect key="frame" x="18" y="183" width="460" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="qTJ-tL-p1s"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to add to your list of Bonjour browse domains." id="100336">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="200327" customClass="CNDomainBrowserView">
+ <rect key="frame" x="20" y="61" width="456" height="114"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="114" id="ey8-36-A8G"/>
+ </constraints>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="NO"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="NO"/>
+ </userDefinedRuntimeAttributes>
+ </customView>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="340">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100340">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="365"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="341">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100341">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="364"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="341" firstAttribute="width" secondItem="340" secondAttribute="width" id="1kP-hH-4fg"/>
+ <constraint firstItem="336" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="6p2-FN-dgI"/>
+ <constraint firstItem="200327" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="BFf-ab-vji"/>
+ <constraint firstItem="341" firstAttribute="baseline" secondItem="340" secondAttribute="baseline" id="DdL-N2-sRf"/>
+ <constraint firstItem="336" firstAttribute="top" secondItem="334" secondAttribute="top" constant="20" symbolic="YES" id="Iei-fi-sMQ"/>
+ <constraint firstItem="340" firstAttribute="top" secondItem="200327" secondAttribute="bottom" constant="20" symbolic="YES" id="Ouj-CX-0R3"/>
+ <constraint firstAttribute="trailing" secondItem="200327" secondAttribute="trailing" constant="20" symbolic="YES" id="QWi-nn-fZb"/>
+ <constraint firstItem="200327" firstAttribute="top" secondItem="336" secondAttribute="bottom" constant="8" symbolic="YES" id="f1Y-2w-Xl7"/>
+ <constraint firstAttribute="trailing" secondItem="336" secondAttribute="trailing" constant="20" symbolic="YES" id="gOk-i6-e6u"/>
+ <constraint firstAttribute="trailing" secondItem="340" secondAttribute="trailing" constant="20" symbolic="YES" id="gvy-DL-dCw"/>
+ <constraint firstAttribute="bottom" secondItem="340" secondAttribute="bottom" constant="20" symbolic="YES" id="i1j-hc-gtt"/>
+ <constraint firstItem="340" firstAttribute="leading" secondItem="341" secondAttribute="trailing" constant="12" symbolic="YES" id="yRJ-0k-a3r"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="-27" y="-234"/>
+ </window>
+ <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NFb-eI-atL" userLabel="AddDomainManual">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="133"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="gUJ-3k-BQQ">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="aoV-3v-A7q">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Jo3-6e-vxc">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="hMi-BR-qQY"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a0y-0s-TTY">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="qne-aW-QHl">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="eUl-Y1-c5S"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Sfp-nO-NP2">
+ <rect key="frame" x="36" y="52" width="54" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="b6L-KA-Dqu">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Myg-XJ-ngM">
+ <rect key="frame" x="18" y="79" width="460" height="34"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="nwj-Vn-nBx"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following domain will be added to your list of Bonjour browse domains." id="m5w-3d-gfR">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="W2d-Us-Cpm">
+ <rect key="frame" x="96" y="49" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="kJz-0i-YUX">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstAttribute="trailing" secondItem="W2d-Us-Cpm" secondAttribute="trailing" constant="20" symbolic="YES" id="08z-5S-y1p"/>
+ <constraint firstAttribute="trailing" secondItem="Myg-XJ-ngM" secondAttribute="trailing" constant="20" symbolic="YES" id="2qd-6o-hRs"/>
+ <constraint firstAttribute="trailing" secondItem="aoV-3v-A7q" secondAttribute="trailing" constant="20" symbolic="YES" id="5WH-eg-Ibw"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" priority="499" constant="96" id="KBy-nt-u24"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="baseline" secondItem="a0y-0s-TTY" secondAttribute="baseline" id="L8X-K0-cNZ"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="Sfp-nO-NP2" secondAttribute="trailing" constant="8" symbolic="YES" id="Pw7-gK-pJO"/>
+ <constraint firstItem="Myg-XJ-ngM" firstAttribute="top" secondItem="gUJ-3k-BQQ" secondAttribute="top" constant="20" symbolic="YES" id="Vkn-zN-QmY"/>
+ <constraint firstAttribute="bottom" secondItem="aoV-3v-A7q" secondAttribute="bottom" constant="20" symbolic="YES" id="aJb-Dk-Ofa"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="top" secondItem="W2d-Us-Cpm" secondAttribute="bottom" constant="8" symbolic="YES" id="bbw-LB-NG3"/>
+ <constraint firstItem="Myg-XJ-ngM" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="cab-6m-9M7"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="top" secondItem="Myg-XJ-ngM" secondAttribute="bottom" constant="8" symbolic="YES" id="ewM-hb-zj3"/>
+ <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="jsT-pp-iwi"/>
+ <constraint firstItem="Sfp-nO-NP2" firstAttribute="baseline" secondItem="W2d-Us-Cpm" secondAttribute="baseline" id="qPo-ba-jjr"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="leading" secondItem="a0y-0s-TTY" secondAttribute="trailing" constant="12" symbolic="YES" id="tzd-P2-c6b"/>
+ <constraint firstItem="Sfp-nO-NP2" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="vVs-34-dSS"/>
+ <constraint firstItem="aoV-3v-A7q" firstAttribute="width" secondItem="a0y-0s-TTY" secondAttribute="width" id="xg1-eb-4Pj"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="-27" y="-524"/>
+ </window>
+ <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="ail-If-2Xp" userLabel="SelectRegDomain">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="220"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="W37-VK-yC5">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="q4Y-tT-1h7">
+ <rect key="frame" x="18" y="183" width="460" height="17"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="zF0-CN-3xD"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to use as your Bonjour registration domain." id="EDB-Ul-M1P">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <customView translatesAutoresizingMaskIntoConstraints="NO" id="agb-WV-smo" customClass="CNDomainBrowserView">
+ <rect key="frame" x="20" y="61" width="456" height="114"/>
+ <constraints>
+ <constraint firstAttribute="height" constant="114" id="3JN-68-aTf"/>
+ </constraints>
+ <userDefinedRuntimeAttributes>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="YES"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
+ <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="YES"/>
+ </userDefinedRuntimeAttributes>
+ </customView>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="8fZ-4V-xd6">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eLF-AD-BgY">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="HFg-iF-1qy"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I6S-g0-R0G">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="a1o-he-Kv7">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="SQP-5g-qGG"/>
+ </connections>
+ </button>
+ </subviews>
+ <constraints>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="top" secondItem="agb-WV-smo" secondAttribute="bottom" constant="20" symbolic="YES" id="4cD-Af-ApJ"/>
+ <constraint firstItem="q4Y-tT-1h7" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="8fj-II-NeF"/>
+ <constraint firstItem="q4Y-tT-1h7" firstAttribute="top" secondItem="W37-VK-yC5" secondAttribute="top" constant="20" symbolic="YES" id="Bq5-8Z-4eY"/>
+ <constraint firstItem="agb-WV-smo" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="Kex-pV-3tR"/>
+ <constraint firstAttribute="trailing" secondItem="q4Y-tT-1h7" secondAttribute="trailing" constant="20" symbolic="YES" id="Piu-PE-SEc"/>
+ <constraint firstItem="agb-WV-smo" firstAttribute="top" secondItem="q4Y-tT-1h7" secondAttribute="bottom" constant="8" symbolic="YES" id="Spl-BU-U7l"/>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="width" secondItem="I6S-g0-R0G" secondAttribute="width" id="Xx2-3v-4H5"/>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="leading" secondItem="I6S-g0-R0G" secondAttribute="trailing" constant="12" symbolic="YES" id="aly-0r-bvb"/>
+ <constraint firstAttribute="bottom" secondItem="8fZ-4V-xd6" secondAttribute="bottom" constant="20" symbolic="YES" id="eqT-TT-gxE"/>
+ <constraint firstItem="8fZ-4V-xd6" firstAttribute="baseline" secondItem="I6S-g0-R0G" secondAttribute="baseline" id="h1B-xs-zFp"/>
+ <constraint firstAttribute="trailing" secondItem="agb-WV-smo" secondAttribute="trailing" constant="20" symbolic="YES" id="xLH-br-4Uh"/>
+ <constraint firstAttribute="trailing" secondItem="8fZ-4V-xd6" secondAttribute="trailing" constant="20" symbolic="YES" id="xiF-Cr-13M"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="538" y="-234"/>
+ </window>
+ <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="he2-0K-CWy" userLabel="SelectRegDomainManual">
+ <windowStyleMask key="styleMask" titled="YES"/>
+ <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+ <rect key="contentRect" x="634" y="377" width="496" height="133"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+ <value key="minSize" type="size" width="213" height="107"/>
+ <view key="contentView" id="FYv-ly-yOd">
+ <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="sau-gD-LVt">
+ <rect key="frame" x="400" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="jAh-nT-Qwg">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="ySI-9p-3tZ"/>
+ </connections>
+ </button>
+ <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ypd-8h-xfJ">
+ <rect key="frame" x="318" y="13" width="82" height="32"/>
+ <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Nd2-rR-DtX">
+ <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+ <font key="font" metaFont="system"/>
+ <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+ </buttonCell>
+ <connections>
+ <action selector="closeMyCustomSheet:" target="-2" id="YM3-jW-TNM"/>
+ </connections>
+ </button>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="die-Uf-Bn9">
+ <rect key="frame" x="36" y="52" width="54" height="17"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="ZIy-WQ-OIZ">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="06e-WM-3MP">
+ <rect key="frame" x="18" y="79" width="460" height="34"/>
+ <constraints>
+ <constraint firstAttribute="width" priority="499" constant="456" id="ilh-EM-DG1"/>
+ </constraints>
+ <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following registration domain will be used by Bonjour to advertise beyond the local subnet." id="SLP-nX-Q2C">
+ <font key="font" metaFont="systemBold"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OEh-fL-Ol6">
+ <rect key="frame" x="96" y="49" width="380" height="22"/>
+ <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="aIe-CQ-mQ3">
+ <font key="font" metaFont="system"/>
+ <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+ </textFieldCell>
+ </textField>
+ </subviews>
+ <constraints>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" priority="499" constant="96" id="1Nc-CQ-lXd"/>
+ <constraint firstItem="06e-WM-3MP" firstAttribute="top" secondItem="FYv-ly-yOd" secondAttribute="top" constant="20" symbolic="YES" id="5wy-Ji-7tZ"/>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="top" secondItem="06e-WM-3MP" secondAttribute="bottom" constant="8" symbolic="YES" id="7BD-rk-RTl"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="leading" secondItem="Ypd-8h-xfJ" secondAttribute="trailing" constant="12" symbolic="YES" id="7oo-eg-nGA"/>
+ <constraint firstItem="die-Uf-Bn9" firstAttribute="baseline" secondItem="OEh-fL-Ol6" secondAttribute="baseline" id="DbC-UI-YFz"/>
+ <constraint firstItem="die-Uf-Bn9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="Ip2-Q3-r3l"/>
+ <constraint firstAttribute="trailing" secondItem="sau-gD-LVt" secondAttribute="trailing" constant="20" symbolic="YES" id="Jce-ky-wTf"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="width" secondItem="Ypd-8h-xfJ" secondAttribute="width" id="NkV-L2-e4p"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="top" secondItem="OEh-fL-Ol6" secondAttribute="bottom" constant="8" symbolic="YES" id="Omq-c5-SZQ"/>
+ <constraint firstAttribute="trailing" secondItem="06e-WM-3MP" secondAttribute="trailing" constant="20" symbolic="YES" id="U0T-5s-Jip"/>
+ <constraint firstAttribute="bottom" secondItem="sau-gD-LVt" secondAttribute="bottom" constant="20" symbolic="YES" id="cWG-NL-TzC"/>
+ <constraint firstAttribute="trailing" secondItem="OEh-fL-Ol6" secondAttribute="trailing" constant="20" symbolic="YES" id="igv-0W-kuw"/>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="die-Uf-Bn9" secondAttribute="trailing" constant="8" symbolic="YES" id="j71-MK-aiv"/>
+ <constraint firstItem="sau-gD-LVt" firstAttribute="baseline" secondItem="Ypd-8h-xfJ" secondAttribute="baseline" id="t9l-JC-Ab2"/>
+ <constraint firstItem="06e-WM-3MP" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wIW-Ja-ih6"/>
+ <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wia-Av-Bte"/>
+ </constraints>
+ </view>
+ <point key="canvasLocation" x="538" y="-525"/>
+ </window>
+ </objects>
+ <resources>
+ <image name="NSAddTemplate" width="11" height="11"/>
+ <image name="NSRemoveTemplate" width="11" height="11"/>
+ </resources>
+</document>
+++ /dev/null
-/*
- File: ConfigurationRights.h
-
- Abstract: Defines the rights we need, namely, (i) the right to write to
- the system configuration settings for Dynamic DNS and Wide-Area DNS-SD,
- and (ii) the right to write to the system keychain to store Dynamic DNS
- shared secrets used to perform authorized updates to DDNS servers.
- Right now these are both actually the same right: "system.preferences"
-
- Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
-
- Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
- ("Apple") in consideration of your agreement to the following terms, and your
- use, installation, modification or redistribution of this Apple software
- constitutes acceptance of these terms. If you do not agree with these terms,
- please do not use, install, modify or redistribute this Apple software.
-
- In consideration of your agreement to abide by the following terms, and subject
- to these terms, Apple grants you a personal, non-exclusive license, under Apple's
- copyrights in this original Apple software (the "Apple Software"), to use,
- reproduce, modify and redistribute the Apple Software, with or without
- modifications, in source and/or binary forms; provided that if you redistribute
- the Apple Software in its entirety and without modifications, you must retain
- this notice and the following text and disclaimers in all such redistributions of
- the Apple Software. Neither the name, trademarks, service marks or logos of
- Apple Computer, Inc. may be used to endorse or promote products derived from the
- Apple Software without specific prior written permission from Apple. Except as
- expressly stated in this notice, no other rights or licenses, express or implied,
- are granted by Apple herein, including but not limited to any patent rights that
- may be infringed by your derivative works or by other works in which the Apple
- Software may be incorporated.
-
- The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
- WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
- WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
- COMBINATION WITH YOUR PRODUCTS.
-
- IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
- OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
- (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define UPDATE_SC_RIGHT "system.preferences"
-#define EDIT_SYS_KEYCHAIN_RIGHT "system.preferences"
+++ /dev/null
-/* Localized versions of Info.plist keys */
-
-CFBundleName = "Bonjour";
-CFBundleGetInfoString = "Bonjour version 1.0, Copyright (c) 2005-2015 Apple Inc.";
-NSHumanReadableCopyright = "Copyright (c) 2005-2015 Apple Inc.";
--- /dev/null
+/* Localized versions of Info.plist keys */
+
+CFBundleName = "Bonjour";
+CFBundleGetInfoString = "Bonjour version 1.0, Copyright (c) 2005-2019 Apple Inc.";
+NSHumanReadableCopyright = "Copyright (c) 2005-2019 Apple Inc.";
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2012-2019 Apple Inc. All rights reserved.
*
* PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
* Resides in /usr/lib/libdns_services.dylib
*/
#include "dns_services.h"
-#include "dns_xpc.h"
#include <xpc/xpc.h>
#include <Block.h>
#include <os/log.h>
+#include "xpc_clients.h"
//*************************************************************************************************************
// Globals
struct _DNSXConnRef_t
{
- connection_t conn_ref; // xpc_connection between client and daemon
- dispatch_queue_t lib_q; // internal queue created in library itself
- void *AppCallBack; // Callback function ptr for Client
- dispatch_queue_t client_q; // Queue specified by client for scheduling its Callback
+ connection_t conn_ref; // xpc_connection between client and daemon
+ dispatch_queue_t lib_q; // internal queue created in library itself
+ DNSXEnableProxyReply AppCallBack; // Callback function ptr for Client
+ dispatch_queue_t client_q; // Queue specified by client for scheduling its Callback
};
//*************************************************************************************************************
case kDNSMsg_NoError:
dispatch_async((connRef)->client_q, ^{
if (connRef->AppCallBack != NULL)
- ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_NoError);
+ connRef->AppCallBack(connRef, kDNSX_NoError);
});
break;
os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: DNS Proxy already in use");
dispatch_async((connRef)->client_q, ^{
if (connRef->AppCallBack != NULL)
- ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_Busy);
+ connRef->AppCallBack(connRef, kDNSX_Busy);
});
break;
os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: Unknown error");
dispatch_async((connRef)->client_q, ^{
if (connRef->AppCallBack != NULL)
- ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_UnknownErr);
+ connRef->AppCallBack(connRef, kDNSX_UnknownErr);
});
break;
}
}
// Creates a new DNSX Connection Reference(DNSXConnRef)
-static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, void *AppCallBack)
+static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, DNSXEnableProxyReply AppCallBack)
{
if (connRefOut == NULL)
{
xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
dispatch_async(connRef->client_q, ^{
if (connRef->AppCallBack != NULL)
- ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_DaemonNotRunning);
+ connRef->AppCallBack(connRef, kDNSX_DaemonNotRunning);
});
}
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2012-2018 Apple Inc. All rights reserved.
*
*
* @header Interface to DNSX SPI
#include <dispatch/dispatch.h>
+#if (defined(__GNUC__) && (__GNUC__ >= 4))
+#define DNS_SERVICES_EXPORT __attribute__((visibility("default")))
+#else
+#define DNS_SERVICES_EXPORT
+#endif
+
// DNSXConnRef: Opaque internal data type
typedef struct _DNSXConnRef_t *DNSXConnRef;
*
*/
+DNS_SERVICES_EXPORT
DNSXErrorType DNSXEnableProxy
(
DNSXConnRef *connRef,
* connRef: A DNSXConnRef initialized by any of the DNSX*() calls.
*
*/
+DNS_SERVICES_EXPORT
void DNSXRefDeAlloc(DNSXConnRef connRef);
#endif
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- * Defines the common interface between mDNSResponder and the Private ClientLibrary(libdnsprivate.dylib)
- * Uses XPC as the IPC Mechanism
- *
- */
-
-#ifndef DNS_XPC_H
-#define DNS_XPC_H
-
-#define kDNSProxyService "com.apple.mDNSResponder.dnsproxy"
-#define kDNSCTLService "com.apple.mDNSResponder.dnsctl"
-
-#define kDNSProxyParameters "DNSProxyParameters"
-
-#define kDNSInIfindex0 "InputArrayInterfaceIndex[0]"
-#define kDNSInIfindex1 "InputArrayInterfaceIndex[1]"
-#define kDNSInIfindex2 "InputArrayInterfaceIndex[2]"
-#define kDNSInIfindex3 "InputArrayInterfaceIndex[3]"
-#define kDNSInIfindex4 "InputArrayInterfaceIndex[4]"
-
-#define kDNSOutIfindex "OutputInterfaceIndex"
-
-#define kDNSDaemonReply "DaemonReplyStatusToClient"
-
-typedef enum
-{
- kDNSMsg_NoError = 0,
- kDNSMsg_Busy
-} DaemonReplyStatusCodes;
-
-#define kDNSLogLevel "DNSLoggingVerbosity"
-
-typedef enum
-{
- log_level1 = 1, // logging off
- log_level2, // logging USR1
- log_level3, // logging USR2
- log_level4, // logging USR1/2
-} DNSLogLevels;
-
-#define kDNSStateInfo "DNSStateInfoLevels"
-
-typedef enum
-{
- full_state = 1, // full state info of mDNSResponder (INFO)
-} DNSStateInfo;
-
-#define kmDNSResponderTests "mDNSResponderTests"
-
-typedef enum
-{
- test_helper_ipc = 1, // invokes mDNSResponder to send a test msg to mDNSResponderHelper
- test_mDNS_log, // invokes mDNSResponder to log using different internal macros
-} mDNSTestModes;
-
-
-
-#endif // DNS_XPC_H
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 Apple Inc. All rights reserved.
- *
- * dnsctl_server.c
- * mDNSResponder
- *
- * XPC as an IPC mechanism to communicate with dnsctl. Open only to Apple OSX/iOS clients
- */
-
-#include "xpc_services.h"
-#include "dns_xpc.h"
-
-#include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock
-#include "helper.h" // mDNSResponderHelper tests
-#include <xpc/xpc.h>
-
-// ***************************************************************************
-// Globals
-extern mDNS mDNSStorage;
-static dispatch_queue_t dnsctlserver_queue = NULL;
-// ***************************************************************************
-
-mDNSlocal void handle_logging(mDNSu32 log_level)
-{
- KQueueLock();
-
- switch (log_level)
- {
- case log_level1:
- mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 0;
- LogMsg("USR1 Logging:[%s] USR2 Logging:[%s]", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
- break;
-
- case log_level2:
- mDNS_LoggingEnabled = 1;
- LogMsg("USR1 Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
- break;
-
- case log_level3:
- mDNS_PacketLoggingEnabled = 1;
- LogMsg("USR2 Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
- break;
-
- case log_level4:
- mDNS_LoggingEnabled = 1 ;
- mDNS_PacketLoggingEnabled = 1;
- LogMsg("USR1 Logging:%s USR2 Logging:%s", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
- break;
-
- default:
- mDNS_LoggingEnabled = 0 ;
- mDNS_PacketLoggingEnabled = 0;
- break;
- }
- UpdateDebugState();
-
- KQueueUnlock("LogLevel changed");
-}
-
-mDNSlocal void handle_stateinfo(mDNSu32 state_level)
-{
- KQueueLock();
-
- switch (state_level)
- {
- case full_state:
- INFOCallback();
- break;
-
- default:
- INFOCallback();
- break;
- }
-
- KQueueUnlock("StateInfo dumped");
-}
-
-
-mDNSlocal void handle_test_mode(mDNSu32 test_mode)
-{
- KQueueLock();
-
- switch (test_mode)
- {
- case test_helper_ipc:
- mDNSNotify("mDNSResponderHelperTest", "This is just a test message to mDNSResponderHelper. This is NOT an actual alert");
- break;
-
- case test_mDNS_log:
- LogInfo("LogInfo: Should be logged at INFO level");
- LogOperation("LogOperation: Should be logged at INFO level");
- LogMsg("LogMsg: Should be logged at DEFAULT level");
- LogSPS("LogSPS: Should be logged at INFO level");
- break;
-
- default:
- LogMsg("Unidentified Test mode: Please add this test");
- break;
- }
-
- KQueueUnlock("Test Msg to mDNSResponderHelper");
-}
-
-mDNSlocal void handle_terminate()
-{
-
- LogInfo("handle_terminate: Client terminated connection.");
-
-}
-
-mDNSlocal void handle_requests(xpc_object_t req)
-{
- mDNSu32 log_level, state_level, test_mode;
- xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
-
- LogInfo("handle_requests: Handler for dnsctl requests");
-
- xpc_object_t response = xpc_dictionary_create_reply(req);
-
- // Return Success Status to the client (essentially ACKing the request)
- if (response)
- {
- xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
- xpc_connection_send_message(remote_conn, response);
- xpc_release(response);
- }
- else
- {
- LogMsg("handle_requests: Response Dictionary could not be created");
- return;
- }
-
- // switch here based on dictionary
- // to handle various different requests like logging, INFO snapshot, etc..
- if ((xpc_dictionary_get_uint64(req, kDNSLogLevel)))
- {
- log_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSLogLevel));
- handle_logging(log_level);
- }
- else if ((xpc_dictionary_get_uint64(req, kDNSStateInfo)))
- {
- state_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSStateInfo));
- handle_stateinfo(state_level);
- }
- else if ((xpc_dictionary_get_uint64(req, kmDNSResponderTests)))
- {
- test_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kmDNSResponderTests));
- handle_test_mode(test_mode);
- }
-}
-
-mDNSlocal void accept_client(xpc_connection_t conn)
-{
- uid_t c_euid;
- int c_pid;
- c_euid = xpc_connection_get_euid(conn);
- c_pid = xpc_connection_get_pid(conn);
-
- if (c_euid != 0 || !IsEntitled(conn, kDNSCTLService))
- {
- LogMsg("accept_client: Client PID[%d] is missing Entitlement or is NOT running as root!", c_pid);
- xpc_connection_cancel(conn);
- return;
- }
-
- xpc_retain(conn);
- xpc_connection_set_target_queue(conn, dnsctlserver_queue);
- xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
- {
- xpc_type_t type = xpc_get_type(req_msg);
-
- if (type == XPC_TYPE_DICTIONARY)
- {
- handle_requests(req_msg);
- }
- else // We hit this case ONLY if Client Terminated Connection OR Crashed
- {
- LogInfo("accept_client: Client %p teared down the connection", (void *) conn);
- handle_terminate();
- xpc_release(conn);
- }
- });
-
- xpc_connection_resume(conn);
-
-}
-
-mDNSexport void init_dnsctl_service(void)
-{
-
- xpc_connection_t dnsctl_listener = xpc_connection_create_mach_service(kDNSCTLService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
- if (!dnsctl_listener || xpc_get_type(dnsctl_listener) != XPC_TYPE_CONNECTION)
- {
- LogMsg("init_dnsctl_service: Error Creating XPC Listener for DNSCTL Server!");
- return;
- }
-
- dnsctlserver_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsctlserver_queue", NULL);
-
- xpc_connection_set_event_handler(dnsctl_listener, ^(xpc_object_t eventmsg)
- {
- xpc_type_t type = xpc_get_type(eventmsg);
-
- if (type == XPC_TYPE_CONNECTION)
- {
- LogInfo("init_dnsctl_service: New DNSCTL Client %p", eventmsg);
- accept_client(eventmsg);
- }
- else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
- {
- LogMsg("init_dnsctl_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
- }
- else
- {
- LogMsg("init_dnsctl_service: Unknown EventMsg type");
- }
- });
-
- xpc_connection_resume(dnsctl_listener);
-}
-
-
-
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
- *
- * xpc_services.c
- * mDNSResponder
- *
- * XPC as an IPC mechanism to communicate with Clients. Open only to Apple OSX/iOS clients
- */
-
-#include "xpc_services.h"
-#include "dns_xpc.h"
-
-#ifndef UNICAST_DISABLED
-
-#include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
-#include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock
-#include <xpc/private.h> // xpc_connection_copy_entitlement_value
-
-// ***************************************************************************
-// Globals
-extern mDNS mDNSStorage;
-static int dps_client_pid; // To track current active client using DNS Proxy Service
-static dispatch_queue_t dps_queue = NULL;
-// ***************************************************************************
-
-// prints current XPC Server State
-mDNSexport void xpcserver_info(mDNS *const m)
-{
-
- LogMsg("----- Active XPC Clients -----");
- if (dps_client_pid)
- LogMsg("DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]", dps_client_pid, m->dp_ipintf[0],
- m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf);
-}
-
-
-mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off)
-{
-
- LogInfo("ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d] ", IpIfArr[0], IpIfArr[1],
- IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf);
-
- KQueueLock();
- DNSProxyInit(IpIfArr, OpIf);
- if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts
- mDNSPlatformInitDNSProxySkts(ProxyUDPCallback, ProxyTCPCallback);
- KQueueUnlock("DNSProxy Activated");
-}
-
-mDNSlocal void handle_dps_terminate()
-{
-
- LogInfo("handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy", dps_client_pid);
- // Clear the Client's PID, so that we can now accept new DPS requests
- dps_client_pid = 0;
-
- KQueueLock();
- mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
- // TBD: Close TCP Sockets
- DNSProxyTerminate();
- KQueueUnlock("DNSProxy Deactivated");
-}
-
-mDNSlocal void handle_dps_request(xpc_object_t req)
-{
- int dps_tmp_client;
- mDNSBool proxy_off = mDNSfalse;
- xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
- dps_tmp_client = (int) xpc_connection_get_pid(remote_conn);
-
- LogInfo("handle_dps_request: Handler for DNS Proxy Requests");
-
- if (dps_client_pid <= 0)
- {
- LogInfo("handle_dps_request: DNSProxy is not engaged (New Client)");
- // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF)
- dps_client_pid = dps_tmp_client;
- proxy_off = mDNStrue;
- }
- else
- {
- // We already have an active DNS Proxy Client and until that client does not terminate the connection
- // or crashes, a new client cannot change/override the current DNS Proxy settings.
- if (dps_client_pid != dps_tmp_client)
- {
- LogMsg("handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time");
- // Return Engaged Status to the client
- xpc_object_t reply = xpc_dictionary_create_reply(req);
- if (reply)
- {
- xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_Busy);
- xpc_connection_send_message(remote_conn, reply);
- xpc_release(reply);
- }
- else
- {
- LogMsg("handle_dps_request: Reply Dictionary could not be created");
- return;
- }
- // We do not really need to terminate the connection with the client
- // as it may try again later which is fine
- return;
- }
- }
-
-
- xpc_object_t response = xpc_dictionary_create_reply(req);
- // Return Success Status to the client
- if (response)
- {
- xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
- xpc_connection_send_message(remote_conn, response);
- xpc_release(response);
- }
- else
- {
- LogMsg("handle_dps_request: Response Dictionary could not be created");
- return;
- }
-
- // Proceed to get DNS Proxy Settings from the Client
- if (xpc_dictionary_get_uint64(req, kDNSProxyParameters))
- {
- mDNSu32 inIf[MaxIp], outIf;
-
- inIf[0] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0);
- inIf[1] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1);
- inIf[2] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2);
- inIf[3] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3);
- inIf[4] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4);
- outIf = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex);
-
- ActivateDNSProxy(inIf, outIf, proxy_off);
- }
-
-}
-
-// Verify Client's Entitlement
-mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *password)
-{
- mDNSBool entitled = mDNSfalse;
- xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password);
-
- if (ent)
- {
- if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent))
- {
- entitled = mDNStrue;
- }
- xpc_release(ent);
- }
- else
- {
- LogMsg("IsEntitled: Client Entitlement is NULL");
- }
-
- if (!entitled)
- LogMsg("IsEntitled: Client is missing Entitlement!");
-
- return entitled;
-}
-
-mDNSlocal void accept_dps_client(xpc_connection_t conn)
-{
- uid_t c_euid;
- int c_pid;
- c_euid = xpc_connection_get_euid(conn);
- c_pid = xpc_connection_get_pid(conn);
-
- if (c_euid != 0 || !IsEntitled(conn, kDNSProxyService))
- {
- LogMsg("accept_dps_client: DNSProxyService Client PID[%d] is missing Entitlement or is not running as root!", c_pid);
- xpc_connection_cancel(conn);
- return;
- }
-
- xpc_retain(conn);
- xpc_connection_set_target_queue(conn, dps_queue);
- xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
- {
- xpc_type_t type = xpc_get_type(req_msg);
-
- if (type == XPC_TYPE_DICTIONARY)
- {
- handle_dps_request(req_msg);
- }
- else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
- {
- LogInfo("accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn);
- // Only the Client that has activated DPS should be able to terminate it
- if (c_pid == dps_client_pid)
- handle_dps_terminate();
- xpc_release(conn);
- }
- });
-
- xpc_connection_resume(conn);
-
-}
-
-mDNSlocal void init_dnsproxy_service(void)
-{
-
- xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
- if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION)
- {
- LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
- return;
- }
-
- dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL);
-
- xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg)
- {
- xpc_type_t type = xpc_get_type(eventmsg);
-
- if (type == XPC_TYPE_CONNECTION)
- {
- LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg);
- accept_dps_client(eventmsg);
- }
- else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
- {
- LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
- return;
- }
- else
- {
- LogMsg("init_dnsproxy_service: Unknown EventMsg type");
- return;
- }
- });
-
- xpc_connection_resume(dps_listener);
-
-}
-
-mDNSexport void xpc_server_init()
-{
- // Add XPC Services here
- init_dnsproxy_service();
- init_dnsctl_service();
-}
-
-
-#else // !UNICAST_DISABLED
-
-mDNSexport void xpc_server_init()
-{
- return;
-}
-
-mDNSexport void xpcserver_info(mDNS *const m)
-{
- (void) m;
-
- return;
-}
-
-#endif // !UNICAST_DISABLED
-
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- *
- *
- * File: xpc_services.h
- *
- * Contains: Interfaces necessary to talk to xpc_services.c
- *
- */
-
-#ifndef XPC_SERVICES_H
-#define XPC_SERVICES_H
-
-#include "mDNSEmbeddedAPI.h"
-#include <xpc/xpc.h>
-
-extern void xpc_server_init(void);
-extern void xpcserver_info(mDNS *const m);
-
-extern mDNSBool IsEntitled(xpc_connection_t conn, const char *password);
-extern void init_dnsctl_service(void);
-
-extern void INFOCallback(void);
-
-#endif // XPC_SERVICES_H
#! /bin/bash
#
-# Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+# Copyright (c) 2017-2019 Apple Inc. All rights reserved.
#
# This script is currently for Apple Internal use only.
#
-version=1.4
-script=${BASH_SOURCE[0]}
-dnssdutil=${dnssdutil:-dnssdutil}
+declare -r version=1.6
+declare -r script=${BASH_SOURCE[0]}
+declare -r dnssdutil=${dnssdutil:-dnssdutil}
+
+# The serviceTypesOfInterest array is initialized with commonly-debugged service types or service types whose records can
+# provide useful debugging information, e.g., _airport._tcp in case an AirPort base station is a WiFi network's access
+# point. Note: Additional service types can be added with the '-s' option.
+
+serviceTypesOfInterest=(
+ _airplay._tcp # AirPlay
+ _airport._tcp # AirPort Base Station
+ _companion-link._tcp # Companion Link
+ _hap._tcp # HomeKit Accessory Protocol
+ _homekit._tcp # HomeKit
+ _raop._tcp # Remote Audio Output Protocol
+)
#============================================================================================================================
# PrintUsage
echo "Usage: $( basename "${script}" ) [options]"
echo ""
echo "Options:"
+ echo " -s Specifies a service type of interest, e.g., _airplay._tcp, _raop._tcp, etc. Can be used more than once."
echo " -V Display version of this script and exit."
echo ""
}
fi
}
+#============================================================================================================================
+# GetStateDump
+#============================================================================================================================
+
+GetStateDump()
+{
+ local suffix=''
+ if [ -n "${1}" ]; then
+ suffix="-${1//[^A-Za-z0-9._-]/_}"
+ fi
+ LogMsg "Getting mDNSResponder state dump."
+ dns-sd -O -stdout &> "${workPath}/state-dump${suffix}.txt"
+}
+
#============================================================================================================================
# RunNetStat
#============================================================================================================================
LogMsg "Starting tcpdump."
tcpdump -n -w "${workPath}/tcpdump.pcapng" &> "${workPath}/tcpdump.txt" &
tcpdumpPID=$!
+ tcpdump -i lo0 -n -w "${workPath}/tcpdump-loopback.pcapng" &> "${workPath}/tcpdump-loopback.txt" 'udp port 5353' &
+ tcpdumpLoopbackPID=$!
}
#============================================================================================================================
mkdir "${workPath}/pcaps"
for file in /tmp/mdns-tcpdump.pcapng*; do
[ -e "${file}" ] || continue
- baseName=$( sed -E 's/^mdns-tcpdump.pcapng([0-9]+)$/mdns-tcpdump-\1.pcapng/' <<< "$( basename ${file} )" )
- gzip < ${file} > "${workPath}/pcaps/${baseName}.gz"
+ baseName=$( basename "${file}" | sed -E 's/^mdns-tcpdump.pcapng([0-9]+)$/mdns-tcpdump-\1.pcapng/' )
+ gzip < "${file}" > "${workPath}/pcaps/${baseName}.gz"
done
}
StopPacketCapture()
{
LogMsg "Stopping tcpdump."
- kill -TERM ${tcpdumpPID}
+ kill -TERM "${tcpdumpPID}"
+ kill -TERM "${tcpdumpLoopbackPID}"
}
#============================================================================================================================
RunInterfaceMulticastTests()
{
- local ifname="$1"
- local allHostsV4=224.0.0.1
- local allHostsV6=ff02::1
- local mDNSV4=224.0.0.251
- local mDNSV6=ff02::fb
- local serviceList=( $( "${dnssdutil}" queryrecord -i "${ifname}" -A -t ptr -n _services._dns-sd._udp.local -l 6 | sed -E -n 's/.*(_.*_(tcp|udp)\.local\.)$/\1/p' | sort -u ) )
- local log="${workPath}/mcast-test-log-${ifname}.txt"
+ local -r ifname=${1}
+ local -r allHostsV4=224.0.0.1
+ local -r allHostsV6=ff02::1
+ local -r mDNSV4=224.0.0.251
+ local -r mDNSV6=ff02::fb
+ local -r log="${workPath}/mcast-test-log-${ifname}.txt"
+ local serviceList=( $( "${dnssdutil}" queryrecord -i "${ifname}" -A -t ptr -n _services._dns-sd._udp.local -l 6 | sed -E -n 's/.*(_.*_(tcp|udp)\.local\.)$/\1/p' ) )
+ serviceList+=( "${serviceTypesOfInterest[@]/%/.local.}" )
+ serviceList=( $( IFS=$'\n' sort -f -u <<< "${serviceList[*]}" ) )
LogOut "List of services: ${serviceList[*]}" >> "${log}"
+
+ # Ping IPv4 broadcast address.
+
+ local broadcastAddr=$( ifconfig "${ifname}" inet | awk '$5 == "broadcast" {print $6}' )
+ if [ -n "${broadcastAddr}" ]; then
+ LogOut "Pinging ${broadcastAddr} on interface ${ifname}." >> "${log}"
+ ping -t 5 -b "${ifname}" "${broadcastAddr}" &> "${workPath}/ping-broadcast-${ifname}.txt"
+ else
+ LogOut "No IPv4 broadcast address for ${ifname}." >> "${log}"
+ fi
+
# Ping All Hosts IPv4 multicast address.
- local routeOutput=$( route -n get -ifscope ${ifname} "${allHostsV4}" 2> /dev/null )
+ local routeOutput=$( route -n get -ifscope "${ifname}" "${allHostsV4}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
- LogOut "Pinging "${allHostsV4}" on interface ${ifname}." >> "${log}"
- ping -t 5 -b ${ifname} "${allHostsV4}" &> "${workPath}/ping-all-hosts-${ifname}.txt"
+ LogOut "Pinging ${allHostsV4} on interface ${ifname}." >> "${log}"
+ ping -t 5 -b "${ifname}" "${allHostsV4}" &> "${workPath}/ping-all-hosts-${ifname}.txt"
else
- LogOut "No route to "${allHostsV4}" on interface ${ifname}." >> "${log}"
+ LogOut "No route to ${allHostsV4} on interface ${ifname}." >> "${log}"
fi
# Ping mDNS IPv4 multicast address.
- routeOutput=$( route -n get -ifscope ${ifname} "${mDNSV4}" 2> /dev/null )
+ routeOutput=$( route -n get -ifscope "${ifname}" "${mDNSV4}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
- LogOut "Pinging "${mDNSV4}" on interface ${ifname}." >> "${log}"
- ping -t 5 -b ${ifname} "${mDNSV4}" &> "${workPath}/ping-mDNS-${ifname}.txt"
+ LogOut "Pinging ${mDNSV4} on interface ${ifname}." >> "${log}"
+ ping -t 5 -b "${ifname}" "${mDNSV4}" &> "${workPath}/ping-mDNS-${ifname}.txt"
else
- LogOut "No route to "${mDNSV4}" on interface ${ifname}." >> "${log}"
+ LogOut "No route to ${mDNSV4} on interface ${ifname}." >> "${log}"
fi
# Ping All Hosts IPv6 multicast address.
- routeOutput=$( route -n get -ifscope ${ifname} -inet6 "${allHostsV6}" 2> /dev/null )
+ routeOutput=$( route -n get -ifscope "${ifname}" -inet6 "${allHostsV6}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
- LogOut "Pinging "${allHostsV6}" on interface ${ifname}." >> "${log}"
- ping6 -c 6 -I ${ifname} "${allHostsV6}" &> "${workPath}/ping6-all-hosts-${ifname}.txt"
+ LogOut "Pinging ${allHostsV6} on interface ${ifname}." >> "${log}"
+ ping6 -c 6 -I "${ifname}" "${allHostsV6}" &> "${workPath}/ping6-all-hosts-${ifname}.txt"
else
- LogOut "No route to "${allHostsV6}" on interface ${ifname}." >> "${log}"
+ LogOut "No route to ${allHostsV6} on interface ${ifname}." >> "${log}"
fi
# Ping mDNS IPv6 multicast address.
- routeOutput=$( route -n get -ifscope ${ifname} -inet6 "${mDNSV6}" 2> /dev/null )
+ routeOutput=$( route -n get -ifscope "${ifname}" -inet6 "${mDNSV6}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
- LogOut "Pinging "${mDNSV6}" on interface ${ifname}." >> "${log}"
- ping6 -c 6 -I ${ifname} "${mDNSV6}" &> "${workPath}/ping6-mDNS-${ifname}.txt"
+ LogOut "Pinging ${mDNSV6} on interface ${ifname}." >> "${log}"
+ ping6 -c 6 -I "${ifname}" "${mDNSV6}" &> "${workPath}/ping6-mDNS-${ifname}.txt"
else
- LogOut "No route to "${mDNSV6}" on interface ${ifname}." >> "${log}"
+ LogOut "No route to ${mDNSV6} on interface ${ifname}." >> "${log}"
fi
# Send mDNS queries for services.
for service in "${serviceList[@]}"; do
- LogOut "Sending mDNS queries for "${service}" on interface ${ifname}." >> "${log}"
+ LogOut "Sending mDNS queries for ${service} on interface ${ifname}." >> "${log}"
for(( i = 1; i <= 3; ++i )); do
printf "\n"
"${dnssdutil}" mdnsquery -i "${ifname}" -n "${service}" -t ptr -r 2
RunMulticastTests()
{
- local interfaces=( $( ifconfig -l -u ) )
- local skipPrefixes=( ap awdl bridge ipsec lo p2p pdp_ip pktap UDC utun )
- local ifname=""
- local pid=""
- local pids=()
+ local -r interfaces=( $( ifconfig -l -u ) )
+ local -r skipPrefixes=( ap awdl bridge ipsec llw p2p pdp_ip pktap UDC utun )
+ local -a pids
+ local ifname
+ local skip
+ local pid
LogMsg "List of interfaces: ${interfaces[*]}"
for ifname in "${interfaces[@]}"; do
- local skip=false
- for prefix in ${skipPrefixes[@]}; do
+ skip=false
+ for prefix in "${skipPrefixes[@]}"; do
if [[ ${ifname} =~ ^${prefix}[0-9]*$ ]]; then
skip=true
break
fi
done
- if [ "${skip}" != "true" ]; then
- ifconfig ${ifname} | grep -q inet
+ if ! "${skip}"; then
+ ifconfig ${ifname} | egrep -q '\binet6?\b'
if [ $? -ne 0 ]; then
skip=true
fi
fi
- if [ "${skip}" == "true" ]; then
+ if "${skip}"; then
continue
fi
LogMsg "Starting interface multicast tests for ${ifname}."
- RunInterfaceMulticastTests "${ifname}" & pids+=($!)
+ RunInterfaceMulticastTests "${ifname}" & pids+=( $! )
done
LogMsg "Waiting for interface multicast tests to complete..."
RunBrowseTest()
{
- LogMsg "Running dnssdutil browseAll command."
+ local -a typeArgs
+
+ if [ "${#serviceTypesOfInterest[@]}" -gt 0 ]; then
+ for serviceType in "${serviceTypesOfInterest[@]}"; do
+ typeArgs+=( "-t" "${serviceType}" )
+ done
+
+ LogMsg "Running dnssdutil browseAll command for service types of interest."
+ "${dnssdutil}" browseAll -A -d local -b 10 -c 10 "${typeArgs[@]}" &> "${workPath}/browseAll-STOI.txt"
+ fi
+
+ LogMsg "Running general dnssdutil browseAll command."
"${dnssdutil}" browseAll -A -d local -b 10 -c 10 &> "${workPath}/browseAll.txt"
}
ArchiveLogs()
{
- local workdir=$( basename "${workPath}" )
- local archivePath="${dstPath}/${workdir}.tar.gz"
+ local -r workdir=$( basename "${workPath}" )
+ local parentDir
+ if IsMacOS; then
+ parentDir=/var/tmp
+ else
+ parentDir=/var/mobile/Library/Logs/CrashReporter
+ fi
+ local -r archivePath="${parentDir}/${workdir}.tar.gz"
LogMsg "Archiving logs."
echo "---"
echo "*** Please run sysdiagnose NOW. ***"
echo "Attach both the log archive and the sysdiagnose archive to the radar."
if IsMacOS; then
- open "${dstPath}"
+ open "${parentDir}"
fi
else
echo "Failed to create archive at ${archivePath}."
CreateWorkDirName()
{
- local suffix=""
- local productName=$( sw_vers -productName )
+ local suffix=''
+ local -r productName=$( sw_vers -productName )
if [ -n "${productName}" ]; then
suffix+="_${productName}"
fi
- local model=""
+ local model
if IsMacOS; then
model=$( sysctl -n hw.model )
model=${model//,/-}
suffix+="_${model}"
fi
- local buildVersion=$( sw_vers -buildVersion )
+ local -r buildVersion=$( sw_vers -buildVersion )
if [ -n "${buildVersion}" ]; then
suffix+="_${buildVersion}"
fi
main()
{
- while getopts ":hV" option; do
+ while getopts ":s:hV" option; do
case "${option}" in
h)
PrintUsage
exit 0
;;
+ s)
+ serviceType=$( awk '{print tolower($0)}' <<< "${OPTARG}" )
+ if [[ ${serviceType} =~ ^_[-a-z0-9]*\._(tcp|udp)$ ]]; then
+ serviceTypesOfInterest+=( "${serviceType}" )
+ else
+ ErrQuit "Service type '${OPTARG}' is malformed."
+ fi
+ ;;
V)
echo "$( basename "${script}" ) version ${version}"
exit 0
esac
done
- [ "${OPTIND}" -gt "$#" ] || ErrQuit "unexpected argument \""${!OPTIND}"\"."
+ [ "${OPTIND}" -gt "$#" ] || ErrQuit "unexpected argument \"${!OPTIND}\"."
if IsMacOS; then
if [ "${EUID}" -ne 0 ]; then
echo "Re-launching with sudo"
- exec sudo ${script}
+ exec sudo "${script}" "$@"
fi
- dstPath=/var/tmp
else
[ "${EUID}" -eq 0 ] || ErrQuit "$( basename "${script}" ) needs to be run as root."
- dstPath=/var/mobile/Library/Logs/CrashReporter
fi
tempPath=$( mktemp -d -q ) || ErrQuit "Failed to make temp directory."
trap SignalHandler SIGINT SIGTERM
trap ExitHandler EXIT
- LogMsg "About: $( basename "${script}" ) version ${version} ($( md5 -q ${script} ))."
+ LogMsg "About: $( basename "${script}" ) version ${version} ($( md5 -q "${script}" ))."
if [ "${dnssdutil}" != "dnssdutil" ]; then
if [ -x "$( which "${dnssdutil}" )" ]; then
LogMsg "Using $( "${dnssdutil}" -V ) at $( which "${dnssdutil}" )."
fi
fi
+ serviceTypesOfInterest=( $( IFS=$'\n' sort -u <<< "${serviceTypesOfInterest[*]}" ) )
+
+ GetStateDump 'before'
RunNetStat
StartPacketCapture
SaveExistingPacketCaptures
RunBrowseTest
RunMulticastTests
+ GetStateDump 'after'
StopPacketCapture
ArchiveLogs
}
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2015-2019 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.
* limitations under the License.
*/
-#include "mDNSEmbeddedAPI.h"
+#include "SymptomReporter.h"
#include <arpa/inet.h>
#include <dlfcn.h>
#include <stdint.h>
#include <sys/socket.h>
#include <AvailabilityMacros.h>
-#include <TargetConditionals.h>
-
-#define TARGET_OS_MACOSX (TARGET_OS_MAC && !TARGET_OS_IPHONE)
-
-#if (!TARGET_OS_MACOSX || (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
#include <SymptomReporter/SymptomReporter.h>
-#else
-#include <Symptoms/SymptomReporter.h>
-#endif
#define SYMPTOM_REPORTER_mDNSResponder_NUMERIC_ID 101
#define SYMPTOM_REPORTER_mDNSResponder_TEXT_ID "com.apple.mDNSResponder"
#define SYMPTOM_DNS_NO_REPLIES 0x00065001
#define SYMPTOM_DNS_RESUMED_RESPONDING 0x00065002
+mDNSu32 NumUnreachableDNSServers;
+
static symptom_framework_t symptomReporter = mDNSNULL;
static symptom_framework_t (*symptom_framework_init_f)(symptom_ident_t id, const char *originator_string) = mDNSNULL;
static symptom_t (*symptom_new_f)(symptom_framework_t framework, symptom_ident_t id) = mDNSNULL;
mStatus err;
static mDNSBool triedInit = mDNSfalse;
static void *symptomReporterLib = mDNSNULL;
-#if (!TARGET_OS_MACOSX || (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
static const char path[] = "/System/Library/PrivateFrameworks/SymptomReporter.framework/SymptomReporter";
-#else
- static const char path[] = "/System/Library/PrivateFrameworks/Symptoms.framework/Frameworks/SymptomReporter.framework/SymptomReporter";
-#endif
if (!triedInit)
{
struct sockaddr_storage sockAddr;
size_t sockAddrSize;
- LogInfo("SymptomReporterReportDNSReachability: DNS server %#a is %sreachable", addr, isReachable ? "" : "un");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "SymptomReporterReportDNSReachability: DNS server " PRI_IP_ADDR " is " PUB_S "reachable", addr, isReachable ? "" : "un");
if (addr->type == mDNSAddrType_IPv4)
{
}
else
{
- LogMsg("SymptomReporterReportDNSReachability: addr is not an IPv4 or IPv6 address!");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "SymptomReporterReportDNSReachability: addr is not an IPv4 or IPv6 address!");
err = mStatus_BadParamErr;
goto exit;
}
for (s = m->DNSServers; s; s = s->next)
{
- if (s->flags & DNSServer_FlagDelete)
+ if (s->flags & DNSServerFlag_Delete)
continue;
- if ((s->flags & DNSServer_FlagUnreachable) && mDNSSameAddress(addr, &s->addr))
+ if ((s->flags & DNSServerFlag_Unreachable) && mDNSSameAddress(addr, &s->addr))
{
- s->flags &= ~DNSServer_FlagUnreachable;
+ s->flags &= ~DNSServerFlag_Unreachable;
NumUnreachableDNSServers--;
found = mDNStrue;
}
if (err != mStatus_NoError)
goto exit;
- if ((s->flags & DNSServer_FlagDelete) || (s->flags & DNSServer_FlagUnreachable))
+ if ((s->flags & DNSServerFlag_Delete) || (s->flags & DNSServerFlag_Unreachable))
goto exit;
- s->flags |= DNSServer_FlagUnreachable;
+ s->flags |= DNSServerFlag_Unreachable;
NumUnreachableDNSServers++;
err = SymptomReporterReportDNSReachability(&s->addr, mDNSfalse);
--- /dev/null
+/*
+ * Copyright (c) 2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SymptomReporter_h
+#define __SymptomReporter_h
+
+#include "mDNSEmbeddedAPI.h"
+
+extern mDNSu32 NumUnreachableDNSServers;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAddr *addr);
+extern mStatus SymptomReporterDNSServerUnreachable(DNSServer *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SymptomReporter_h
--- /dev/null
+#!/bin/sh
+#
+# bats_test_proxy.sh
+# mDNSResponder Tests
+#
+# Copyright (c) 2019 Apple Inc. All rights reserved.
+
+# tests whether the state dump will create at most MAX_NUM_DUMP_FILES, to avoid wasting too much space.
+base_test="dnssdutil dnsquery -s 127.0.0.1 -n apple.com -t a"
+
+# Enable the proxy and test over TCP
+function test_proxy_tcp {
+ test_proxy_on $base_test --tcp
+ return $?
+}
+
+# Enable the proxy and test over UDP
+function test_proxy_udp {
+ test_proxy_on $base_test
+ return $?
+}
+
+# Test the proxy over TCP without enabling it (should fail)
+function test_noproxy_tcp {
+ test_proxy $base_test --tcp
+ if [ $? == 0 ]; then
+ return 1;
+ fi
+ return 0
+}
+
+# Test the proxy over UDP without enabling it (should fail)
+function test_noproxy_udp {
+ test_proxy $base_test
+ if [ $? == 0 ]; then
+ return 1;
+ fi
+ return 0
+}
+
+function test_proxy_on {
+ local command_line="$*"
+ local ret=1
+
+ # Enable the proxy
+ dnssdutil dnsproxy -i lo0 &
+ local dnssdutil_pid=$!
+
+ # See if that worked
+ sleep 1
+ local dnssdutil_pid_now=$(ps xa |sed -n -e 's/^ *\([0-9][0-9]*\).*$/\1/' -e "/$dnssdutil_pid/p")
+ if [ $dnssdutil_pid != "$dnssdutil_pid_now" ]; then
+ echo "Failed to enable DNS proxy $dnssdutil_pid $dnssdutil_pid_now."
+ return 1
+ fi
+
+ test_proxy $command_line
+ ret=$?
+
+ # Disable the proxy and wait for that to finish
+ kill -HUP $dnssdutil_pid
+ wait $dnssdutil_pid
+ return $ret
+}
+
+function test_proxy {
+ local command_line="$*"
+ local ret=1
+ # Try to do the DNS lookup
+ local output=$($command_line |egrep "^End reason:")
+ if [ "$output" = "End reason: received response" ]; then
+ echo "Proxy is working: $output"
+ ret=0
+ else
+ echo "Proxy is not working: $output"
+ fi
+ return $ret
+}
+
+ret=0
+# Functions are put inside an array, use ($test) to evaluate it
+declare -a tests=("test_proxy_tcp"
+ "test_proxy_udp"
+ "test_noproxy_tcp"
+ "test_noproxy_udp")
+echo ""
+echo "----Proxy Test Start, $(date)----"
+for test in "${tests[@]}"; do
+ echo "running $test:"
+ ($test)
+ if [[ $? -eq 0 ]]; then
+ echo "passed"$'\n' # use $'\n' to print one more newline character
+ else
+ ret=1
+ echo "failed"$'\n'
+ fi
+done
+echo "----Proxy Test End, $(date)----"
+exit $ret
+
+# Local Variables:
+# tab-width: 4
+# fill-column: 108
+# indent-tabs-mode: nil
+# End:
--- /dev/null
+#!/bin/sh
+#
+# bats_test_state_dump.sh
+# mDNSResponder Tests
+#
+# Copyright (c) 2019 Apple Inc. All rights reserved.
+
+
+# trigger state dump
+function triger_state_dump {
+ local command_line="$1"
+ output="$($command_line)"
+ if [[ $? -ne 0 ]]; then
+ printf "dns-sd -O exit with non-zero return value, the returned error message is:\n"
+ echo $output
+ return 1
+ fi
+ return 0
+}
+
+# trigger state dump and check if the file is created successfully
+function triger_state_dump_and_check_file {
+ # $1 is the command line used to trigger state dump
+ triger_state_dump "$1"
+ if [[ $? -ne 0 ]]; then
+ return 1
+ fi
+ # the returned result is like the following:
+ # State Dump Is Saved to: /private/var/log/mDNSResponder/mDNSResponder_state_dump_2019-03-01_17-07-10-260-08-00.txt
+ # Time Used: 33 ms
+ # splited the result with '\n'
+ IFS=$'\n' read -r -d '' -a line_being_read <<< "$output"
+ # ${line_being_read[0]} contains "State Dump Is Saved to: /private/var/log/mDNSResponder/mDNSResponder_state_dump_2019-03-01_17-07-10-260-08-00.txt"
+ IFS=":" read -r -d '' -a line_being_splitted <<< "${line_being_read[0]}"
+ # get the path "/private/var/log/mDNSResponder/mDNSResponder_state_dump_2019-03-01_17-07-10-260-08-00.txt"
+ file_name=$(echo "${line_being_splitted[1]}" | xargs)
+ # check if the file exists in the disk
+ if [ ! -f $file_name ]; then
+ printf "State dump is not created under %s\n" $file_name
+ return 1
+ fi
+ return 0
+}
+
+# verify that the state dump contains the full content
+function verify_state_dump_content {
+ # the passed parameter is the file content to be checked
+ local file="$1"
+ # the first line of file should start with "---- BEGIN STATE LOG ----"
+ local file_start_string="---- BEGIN STATE LOG ----"
+ if [[ ! "$file" == "$file_start_string"* ]]; then
+ printf "State dump file does not start with %s\n" "$file_start_string"
+ return 1
+ fi
+
+ # the last line of file should start with "---- END STATE LOG ----"
+ local last_line=$(echo "$file" | tail -n1)
+ local file_end_string="---- END STATE LOG ----"
+ if [[ ! "$last_line" == "$file_end_string"* ]]; then
+ printf "State dump file does not end with %s\n" "$file_end_string"
+ return 1
+ fi
+
+ return 0
+}
+
+function test_check_dump_directory {
+ local dump_path="/private/var/log/mDNSResponder"
+ if [ ! -d "$dump_path" ]; then
+ printf "Directory \"%s\" does not exist\n" $dump_path
+ return 1
+ fi
+ local permission=$(stat -f "%OLp" $dump_path)
+ if [ ! $permission == "755" ]; then
+ printf "Directory \"%s\" has incorrect permission. expected=755; actual=%s\n" $dump_path $permission
+ return 1
+ fi
+ local owner=$(ls -ld $dump_path | awk '{print $3}')
+ if [ ! $owner == "_mdnsresponder" ]; then
+ printf "Directory \"%s\" has incorrect owner. expected=_mdnsresponder; actual=%s\n" $dump_path "$owner"
+ return 1
+ fi
+ return 0
+}
+
+function test_output_to_plain_txt_file {
+ triger_state_dump_and_check_file "dns-sd -O"
+ if [[ $? -ne 0 ]]; then
+ return 1
+ fi
+ # get the file content
+ local file_content=$(cat $file_name)
+ verify_state_dump_content "$file_content" && rm "$file_name"
+ return $?
+}
+
+# tests if "dns-sd -O -compress" works as expected
+function test_output_to_archive {
+ triger_state_dump_and_check_file "dns-sd -O -compress"
+ if [[ $? -ne 0 ]]; then
+ return 1
+ fi
+ # get the uncompressed file name
+ local file_name_uncompressed=$(tar -tf "$file_name")
+ # unzip the file
+ tar -xf "$file_name" --directory /tmp/
+ # get the file content
+ local file_content=$(cat "/tmp/$file_name_uncompressed")
+ verify_state_dump_content "$file_content" && rm "$file_name" && rm "/tmp/$file_name_uncompressed"
+ return $?
+}
+
+# tests if "dns-sd -O -stdout" works as expected
+function test_output_to_stdout {
+ triger_state_dump "dns-sd -O -stdout"
+ if [[ $? -ne 0 ]]; then
+ return 1
+ fi
+ # delete the last line of output, which is " Time Used: <time> ms"
+ output=$(echo "$output" | sed '$d')
+ verify_state_dump_content "$output"
+ return $?
+}
+
+# tests whether the state dump will create at most MAX_NUM_DUMP_FILES, to avoid wasting too much space.
+function test_dump_limit {
+ # calls "dns-sd -O -compress" for 10 times
+ local counter=1
+ while [ $counter -le 10 ]
+ do
+ triger_state_dump_and_check_file "dns-sd -O -compress"
+ if [[ $? -ne 0 ]];then
+ return 1;
+ fi
+ ((counter++))
+ done
+
+ # $file_name is already initialized when we call "dns-sd -O -compress" above
+ local directory=$(dirname "$file_name")
+ # get the number of files under $directory
+ local file_count=$(ls -Uba1 "$directory" | grep ^mDNSResponder_state_dump_ | wc -l | xargs)
+ # clean up the directory
+ rm -rf ${directory}/*
+ # the number of files should be MAX_NUM_DUMP_FILES, which is defined as 5 in mDNSResponder
+ if [[ $file_count -eq 5 ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+ret=0
+# Functions are put inside an array, use ($test) to evaluate it
+declare -a tests=("test_check_dump_directory"
+ "test_output_to_plain_txt_file"
+ "test_output_to_archive"
+ "test_output_to_stdout"
+ "test_dump_limit")
+echo ""
+echo "----State Dump Test Start, $(date)----"
+for test in "${tests[@]}"; do
+ echo "running $test:"
+ ($test)
+ if [[ $? -eq 0 ]]; then
+ echo "passed"$'\n' # use $'\n' to print one more newline character
+ else
+ ret=1
+ echo "failed"$'\n'
+ fi
+done
+echo "----State Dump Test End, $(date)----"
+exit $ret
--- /dev/null
+/*
+ * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unittest_common.h"
+#import <XCTest/XCTest.h>
+
+struct UDPSocket_struct
+{
+ mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+};
+typedef struct UDPSocket_struct UDPSocket;
+
+// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
+uint8_t query_client_msgbuf[35] = {
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
+ 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
+ 0x01, 0x00, 0x01
+};
+
+// This uDNS message is a canned response that was originally captured by wireshark.
+uint8_t query_response_msgbuf[108] = {
+ 0x69, 0x41, // transaction id
+ 0x85, 0x80, // flags
+ 0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
+ 0x00, 0x02, // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
+ 0x00, 0x01, // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
+ 0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
+ 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
+ 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
+ 0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
+ 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
+ 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
+ 0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
+};
+
+// Variables associated with contents of the above uDNS message
+#define uDNS_TargetQID 16745
+char udns_original_domainname_cstr[] = "123server.dotbennu.com.";
+char udns_cname_domainname_cstr[] = "test212.dotbennu.com.";
+//static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }};
+
+@interface CNameRecordTest : XCTestCase
+{
+ UDPSocket* local_socket;
+ request_state* client_request_message;}
+@end
+
+@implementation CNameRecordTest
+
+// The InitThisUnitTest() initializes the mDNSResponder environment as well as
+// a DNSServer. It also allocates memory for a local_socket and client request.
+// Note: This unit test does not send packets on the wire and it does not open sockets.
+- (void)setUp
+{
+ // Init unit test environment and verify no error occurred.
+ mStatus result = init_mdns_environment(mDNStrue);
+ XCTAssertEqual(result, mStatus_NoError);
+
+ // Add one DNS server and verify it was added.
+ AddDNSServer_ut();
+ XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1);
+
+ // Create memory for a socket that is never used or opened.
+ local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket));
+
+ // Create memory for a request that is used to make this unit test's client request.
+ client_request_message = calloc(1, sizeof(request_state));
+}
+
+- (void)tearDown
+{
+ mDNS *m = &mDNSStorage;
+ request_state* req = client_request_message;
+ DNSServer *ptr, **p = &m->DNSServers;
+
+ while (req->replies)
+ {
+ reply_state *reply = req->replies;
+ req->replies = req->replies->next;
+ mDNSPlatformMemFree(reply);
+ }
+ mDNSPlatformMemFree(req);
+
+ mDNSPlatformMemFree(local_socket);
+
+ while (*p)
+ {
+ ptr = *p;
+ *p = (*p)->next;
+ LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
+ mDNSPlatformMemFree(ptr);
+ }
+}
+
+// This test simulates a uds client request by setting up a client request and then
+// calling mDNSResponder's handle_client_request. The handle_client_request function
+// processes the request and starts a query. This unit test verifies
+// the client request and query were setup as expected. This unit test also calls
+// mDNS_execute which determines the cache does not contain the new question's
+// answer.
+- (void)testStartClientQueryRequest
+{
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ char *msgptr = (char *)query_client_msgbuf;
+ size_t msgsz = sizeof(query_client_msgbuf);
+ mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+ DNSQuestion *q;
+ mStatus err = mStatus_NoError;
+ char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ // Process the unit test's client request
+ start_client_request(req, msgptr, msgsz, query_request, local_socket);
+ XCTAssertEqual(err, mStatus_NoError);
+
+ // Verify the request fields were set as expected
+ XCTAssertNil((__bridge id)req->next);
+ XCTAssertNil((__bridge id)req->primary);
+ XCTAssertEqual(req->sd, client_req_sd);
+ XCTAssertEqual(req->process_id, client_req_process_id);
+ XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name));
+ XCTAssertEqual(req->validUUID, mDNSfalse);
+ XCTAssertEqual(req->errsd, 0);
+ XCTAssertEqual(req->uid, client_req_uid);
+ XCTAssertEqual(req->ts, t_complete);
+ XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
+ XCTAssertEqual(req->msgend, msgptr+msgsz);
+ XCTAssertNil((__bridge id)(void*)req->msgbuf);
+ XCTAssertEqual(req->hdr.version, VERSION);
+ XCTAssertNil((__bridge id)req->replies);
+ XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
+ XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates);
+ XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny);
+
+ // Verify the query fields were set as expected
+ q = &req->u.queryrecord.op.q;
+ XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL);
+ XCTAssertEqual(q, m->Questions);
+ XCTAssertEqual(q, m->NewQuestions);
+ XCTAssertEqual(q->SuppressUnusable, mDNSfalse);
+ XCTAssertEqual(q->ReturnIntermed, mDNStrue);
+ XCTAssertEqual(q->Suppressed, mDNSfalse);
+
+ ConvertDomainNameToCString(&q->qname, qname_cstr);
+ XCTAssertFalse(strcmp(qname_cstr, udns_original_domainname_cstr));
+ XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+
+ XCTAssertEqual(q->InterfaceID, mDNSInterface_Any);
+ XCTAssertEqual(q->flags, req->flags);
+ XCTAssertEqual(q->qtype, 1);
+ XCTAssertEqual(q->qclass, 1);
+ XCTAssertEqual(q->LongLived, 0);
+ XCTAssertEqual(q->ExpectUnique, mDNSfalse);
+ XCTAssertEqual(q->ForceMCast, 0);
+ XCTAssertEqual(q->TimeoutQuestion, 0);
+ XCTAssertEqual(q->WakeOnResolve, 0);
+ XCTAssertEqual(q->UseBackgroundTraffic, 0);
+ XCTAssertEqual(q->ValidationRequired, 0);
+ XCTAssertEqual(q->ValidatingResponse, 0);
+ XCTAssertEqual(q->ProxyQuestion, 0);
+ XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
+ XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
+ XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
+ XCTAssertEqual(q->AppendSearchDomains, 0);
+ XCTAssertNil((__bridge id)q->DuplicateOf);
+
+ // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
+ // It won't be yet because the cache is empty.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ // Verify mDNS_Execute processed the new question.
+ XCTAssertNil((__bridge id)m->NewQuestions);
+
+ // Verify the cache is empty and the request got no reply.
+ XCTAssertEqual(m->rrcache_totalused, 0);
+ XCTAssertNil((__bridge id)req->replies);
+}
+#if 0
+// This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function.
+// It then verifies cache entries were added for the CNAME and A records that were contained in the
+// answers of the canned response, query_response_msgbuf. This unit test also verifies that
+// 2 add events were generated for the client.
+- (void)testPopulateCacheWithClientResponseRecords
+{
+ mDNS *const m = &mDNSStorage;
+ DNSMessage *msgptr = (DNSMessage *)query_response_msgbuf;
+ size_t msgsz = sizeof(query_response_msgbuf);
+ struct reply_state *reply;
+ request_state* req = client_request_message;
+ DNSQuestion *q = &req->u.queryrecord.q;
+ const char *data;
+ const char *end;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+ size_t len;
+ char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ // Receive and populate the cache with canned response
+ receive_response(req, msgptr, msgsz);
+
+ // Verify 2 cache entries for CName and A record are present
+ mDNSu32 CacheUsed =0, notUsed =0;
+ LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used);
+ XCTAssertEqual(CacheUsed, m->rrcache_totalused);
+ XCTAssertEqual(CacheUsed, 4); // 2 for the CacheGroup object plus 2 for the A and CNAME records
+ XCTAssertEqual(m->PktNum, 1); // one packet was received
+
+ // Verify question's qname is now set with the A record's domainname
+ ConvertDomainNameToCString(&q->qname, domainname_cstr);
+ XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+ XCTAssertFalse(strcmp(domainname_cstr, udns_cname_domainname_cstr));
+
+ // Verify client's add event for CNAME is properly formed
+ reply = req->replies;
+ XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+ XCTAssertNil((__bridge id)reply->next);
+
+ data = (char *)&reply->rhdr[1];
+ end = data+reply->totallen;
+ get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ len = get_reply_len(name, rdlen);
+
+ XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+
+ XCTAssertEqual(reply->rhdr->flags, htonl(kDNSServiceFlagsAdd));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexAny);
+ XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+
+ XCTAssertEqual(rrtype, kDNSType_CNAME);
+ XCTAssertEqual(rrclass, kDNSClass_IN);
+ ConvertDomainNameToCString((const domainname *const)rdata, domainname_cstr);
+ XCTAssertFalse(strcmp(domainname_cstr, "test212.dotbennu.com."));
+
+ // The mDNS_Execute call generates an add event for the A record
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ // Verify the client's reply contains a properly formed add event for the A record.
+ reply = req->replies;
+ XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+ XCTAssertNotEqual(reply->next, (reply_state*)mDNSNULL);
+ reply = reply->next;
+
+ data = (char *)&reply->rhdr[1];
+ end = data+reply->totallen;
+ get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ len = get_reply_len(name, rdlen);
+
+ XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+
+ XCTAssertEqual(reply->rhdr->flags, htonl(kDNSServiceFlagsAdd));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexAny);
+ XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+
+ XCTAssertEqual(rrtype, kDNSType_A);
+ XCTAssertEqual(rrclass, kDNSClass_IN);
+ XCTAssertEqual(rdata[0], dns_response_ipv4.b[0]);
+ XCTAssertEqual(rdata[1], dns_response_ipv4.b[1]);
+ XCTAssertEqual(rdata[2], dns_response_ipv4.b[2]);
+ XCTAssertEqual(rdata[3], dns_response_ipv4.b[3]);
+}
+
+// This function verifies the cache and event handling occurred as expected when a network change happened.
+// The uDNS_SetupDNSConfig is called to simulate a network change and two outcomes occur. First the A record
+// query is restarted and sent to a new DNS server. Second the cache records are purged. Then mDNS_Execute
+// is called and it removes the purged cache records and generates a remove event for the A record.
+// The following are verified:
+// 1.) The restart of query for A record.
+// 2.) The cache is empty after mDNS_Execute removes the cache entres.
+// 3.) The remove event is verified by examining the request's reply data.
+- (void)testSimulateNetworkChangeAndVerify
+{
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ DNSQuestion* q = &req->u.queryrecord.q;
+ mDNSu32 CacheUsed =0, notUsed =0;
+ const char *data; const char *end;
+ char name[kDNSServiceMaxDomainName];
+ uint16_t rrtype, rrclass, rdlen;
+ const char *rdata;
+ size_t len;
+
+ // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and
+ // both the CNAME and A record are purged.
+ uDNS_SetupDNSConfig(m);
+
+ // Verify the A record query was restarted. This is done indirectly by noticing the transaction id and interval have changed.
+ XCTAssertEqual(q->ThisQInterval, InitialQuestionInterval);
+ XCTAssertNotEqual(q->TargetQID.NotAnInteger, uDNS_TargetQID);
+
+ // Then mDNS_Execute removes both records from the cache and calls the client back with a remove event for A record.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ // Verify the cache entries are removed
+ LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used);
+ XCTAssertEqual(CacheUsed, m->rrcache_totalused);
+ XCTAssertEqual(CacheUsed, 0);
+
+ // Verify the A record's remove event is setup as expected in the reply data
+ struct reply_state *reply;
+ reply = req->replies;
+ XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+ XCTAssertNotEqual(reply->next, (reply_state*)mDNSNULL);
+ XCTAssertNotEqual(reply->next->next, (reply_state*)mDNSNULL);
+
+ reply = reply->next->next; // Get to last event to verify remove event
+ data = (char *)&reply->rhdr[1];
+ end = data+reply->totallen;
+ get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+ rrtype = get_uint16(&data, end);
+ rrclass = get_uint16(&data, end);
+ rdlen = get_uint16(&data, end);
+ rdata = get_rdata(&data, end, rdlen);
+ len = get_reply_len(name, rdlen);
+
+ XCTAssertEqual(reply->totallen, reply->mhdr->datalen + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+
+ XCTAssertNotEqual(reply->rhdr->flags, htonl(kDNSServiceFlagsAdd));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexAny);
+ XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+
+ XCTAssertEqual(rrtype, kDNSType_A);
+ XCTAssertEqual(rrclass, kDNSClass_IN);
+ XCTAssertEqual(rdata[0], dns_response_ipv4.b[0]);
+ XCTAssertEqual(rdata[1], dns_response_ipv4.b[1]);
+ XCTAssertEqual(rdata[2], dns_response_ipv4.b[2]);
+ XCTAssertEqual(rdata[3], dns_response_ipv4.b[3]);
+}
+#endif
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
+#import <XCTest/XCTest.h>
+
+@interface DNSMessageTest : XCTestCase
+{
+ DNSMessage *msg;
+}
+@end
+
+@implementation DNSMessageTest
+
+- (void)setUp
+{
+ msg = (DNSMessage *)malloc (sizeof(DNSMessage));
+ XCTAssert(msg != NULL);
+
+ // message header should be 12 bytes
+ XCTAssertEqual(sizeof(msg->h), 12);
+}
+
+- (void)tearDown
+{
+ XCTAssert(msg != NULL);
+ free(msg);
+}
+
+- (void)testMessageInitialization
+{
+ // Initialize the message
+ InitializeDNSMessage(&msg->h, onesID, QueryFlags);
+
+ // Check that the message is initialized properly
+ XCTAssertEqual(msg->h.numAdditionals, 0);
+ XCTAssertEqual(msg->h.numAnswers, 0);
+ XCTAssertEqual(msg->h.numQuestions, 0);
+ XCTAssertEqual(msg->h.numAuthorities, 0);
+}
+
+#if 0
+- (void)testPerformanceExample {
+ // This is an example of a performance test case.
+ [self measureBlock:^{
+ // Put the code you want to measure the time of here.
+ }];
+}
+#endif
+
+@end
--- /dev/null
+//
+// HelperFunctionTest.m
+// Tests
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#import <XCTest/XCTest.h>
+#include "unittest_common.h"
+
+@interface HelperFunctionTest : XCTestCase
+
+@end
+
+@implementation HelperFunctionTest
+
+- (void)setUp {
+ // It is empty for now.
+}
+
+- (void)tearDown {
+ // It is empty for now.
+}
+
+- (void)testCFStringToDomainLabel {
+ // test_cstring[i][0] is the input
+ // test_cstring[i][1] is the expected correct output
+ static const char * const test_cstring[][2] = {
+ {"short", "short"},
+ {"this-is-a-normal-computer-name", "this-is-a-normal-computer-name"},
+ {"", ""},
+ {"This is an ascii string whose length is more than 63 bytes, where it takes one byte to store every character", "This is an ascii string whose length is more than 63 bytes, whe"},
+ {"यह एक एस्सी स्ट्रिंग है जिसकी लंबाई साठ तीन बाइट्स से अधिक है, जहां यह हर चरित्र को संग्रहीत करने के लिए एक बाइट लेता है", "यह एक एस्सी स्ट्रिंग है "}, // "यह एक एस्सी स्ट्रिंग है " is 62 byte, and "यह एक एस्सी स्ट्रिंग है जि" is more than 63, so the result is expected to truncated to 62 bytes instead of 63 bytes
+ {"वितीय टेस्ट ट्राई टी॰वी॰", "वितीय टेस्ट ट्राई टी॰वी"},
+ {"这是一个超过六十三比特的其中每个中文字符占三比特的中文字符串", "这是一个超过六十三比特的其中每个中文字符占"},
+ {"🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝", "🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝"} // "🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝" is 60 bytes, and "🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝" is more than 63 bytes so the result is expected to be truncated to 60 bytes instead of 64 bytes
+ };
+
+ for (int i = 0, n = sizeof(test_cstring) / sizeof(test_cstring[0]); i < n; i++) {
+ // construct CFString from input
+ CFStringRef name_ref = CFStringCreateWithCString(kCFAllocatorDefault, test_cstring[i][0], kCFStringEncodingUTF8);
+ XCTAssertTrue(name_ref != NULL, @"unit test internal error. {descrption=\"name_ref should be non-NULL.\"}");
+
+ // call the function being tested
+ domainlabel label;
+ mDNSDomainLabelFromCFString_ut(name_ref, &label);
+
+ // Check if the result is correct
+ XCTAssertEqual(label.c[0], strlen(test_cstring[i][1]),
+ @"name length is not equal. {expect=%d,actual=%d}", strlen(test_cstring[i][1]), label.c[0]);
+ XCTAssertTrue(memcmp(label.c + 1, test_cstring[i][1], label.c[0]) == 0,
+ @"name is not correctly decoded. {expect='%s',actual='%s'}", test_cstring[i][1], label.c + 1);
+
+ CFRelease(name_ref);
+ }
+}
+
+@end
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
+ <key>CFBundleExecutable</key>
+ <string>$(EXECUTABLE_NAME)</string>
+ <key>CFBundleIdentifier</key>
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>$(PRODUCT_NAME)</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
--- /dev/null
+/*
+ * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unittest_common.h"
+#include "mDNSMacOSX.h"
+#import <XCTest/XCTest.h>
+
+// This query request message was generated from the following command: "dns-sd -lo -timeout -Q cardinal2.apple.com. A"
+char query_req_msgbuf[33]= {
+ 0x00, 0x01, 0x90, 0x00,
+ // DNSServiceFlags.L = (kDNSServiceFlagsReturnIntermediates |kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout)
+ 0xff, 0xff, 0xff, 0xff,
+ // interfaceIndex = mDNSInterface_LocalOnly
+ 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,
+ 0x32, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x00, 0x00, 0x01, 0x00,
+ 0x01
+};
+
+mDNSlocal mStatus InitEtcHostsRecords(void)
+{
+ mDNS *m = &mDNSStorage;
+ struct sockaddr_storage hostaddr;
+
+ AuthHash newhosts;
+ mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("127.0.0.1", &hostaddr);
+
+ domainname domain;
+ MakeDomainNameFromDNSNameString(&domain, "localhost");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr);
+
+ MakeDomainNameFromDNSNameString(&domain, "localhost");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("255.255.255.255", &hostaddr);
+
+ MakeDomainNameFromDNSNameString(&domain, "broadcasthost");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+
+ memset(&hostaddr, 0, sizeof(hostaddr));
+ get_ip("17.226.40.200", &hostaddr);
+
+ MakeDomainNameFromDNSNameString(&domain, "cardinal2.apple.com");
+
+ mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+ UpdateEtcHosts_ut(&newhosts);
+
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ return mStatus_NoError;
+}
+
+@interface LocalOnlyATimeoutTest : XCTestCase
+{
+ request_state* client_request_message;
+ UDPSocket* local_socket;
+ char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+}
+@end
+
+@implementation LocalOnlyATimeoutTest
+
+// The InitUnitTest() initializes a minimal mDNSResponder environment as
+// well as allocates memory for a local_socket and client request.
+// It also sets the domainname_cstr specified in the client's query request.
+// Note: This unit test does not send packets on the wire and it does not open sockets.
+- (void)setUp
+{
+ // Init mDNSStorage
+ mStatus result = init_mdns_storage();
+ XCTAssertEqual(result, mStatus_NoError);
+
+ // Allocate a client request
+ local_socket = (UDPSocket *)calloc(1, sizeof(*local_socket));
+
+ // Allocate memory for a request that is used to make client requests.
+ client_request_message = calloc(1, sizeof(request_state));
+
+ // Init domainname that is used by unit tests
+ strlcpy(domainname_cstr, "cardinal2.apple.com.", sizeof(domainname_cstr));
+}
+
+// This function does memory cleanup and no verification.
+- (void)tearDown
+{
+ mDNSPlatformMemFree(local_socket);
+}
+
+// This unit test starts a local only request for "cardinal2.apple.com.". It first
+// calls start_client_request to start a query, it then verifies the
+// req and query data structures are set as expected. Next, the cache is verified to
+// be empty by AnswerNewLocalOnlyQuestion() and so results in GenerateNegativeResponse()
+// getting called which sets up a reply with a negative answer in it for the client.
+// On return from mDNS_Execute, the client's reply structure is verified to be set as
+// expected. Lastly the timeout is simulated and mDNS_Execute is called. This results
+// in a call to TimeoutQuestions(). And again, the GenerateNegativeResponse() is called
+// which returns a negative response to the client. This time the client reply is verified
+// to be setup with a timeout result.
+- (void)testStartLocalOnlyClientQueryRequest
+{
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ char *msgptr = (char *)query_req_msgbuf;
+ size_t msgsz = sizeof(query_req_msgbuf);
+ DNSQuestion *q;
+ mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+ mStatus err = mStatus_NoError;
+ char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+ struct reply_state *reply;
+ size_t len;
+
+ // Process the unit test's client request
+ start_client_request(req, msgptr, msgsz, query_request, local_socket);
+ XCTAssertEqual(err, mStatus_NoError);
+
+ // Verify the query initialized and request fields were set as expected
+ XCTAssertEqual(req->hdr.version, VERSION);
+ XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
+ XCTAssertEqual(req->flags, (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
+ XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexLocalOnly);
+ XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
+
+ q = &req->u.queryrecord.op.q;
+ XCTAssertEqual(q, m->NewLocalOnlyQuestions);
+ XCTAssertNil((__bridge id)m->Questions);
+ XCTAssertNil((__bridge id)m->NewQuestions);
+ XCTAssertEqual(q->SuppressUnusable, 1);
+ XCTAssertEqual(q->ReturnIntermed, 1);
+ XCTAssertEqual(q->Suppressed, mDNSfalse); // Regress <rdar://problem/27571734>
+
+ ConvertDomainNameToCString(&q->qname, qname_cstr);
+ XCTAssertFalse(strcmp(qname_cstr, domainname_cstr));
+ XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+
+ XCTAssertEqual(q->InterfaceID, mDNSInterface_LocalOnly);
+ XCTAssertEqual(q->flags, req->flags);
+ XCTAssertEqual(q->qtype, 1);
+ XCTAssertEqual(q->qclass, 1);
+ XCTAssertEqual(q->LongLived, 0);
+ XCTAssertEqual(q->ExpectUnique, mDNSfalse);
+ XCTAssertEqual(q->ForceMCast, 0);
+ XCTAssertEqual(q->TimeoutQuestion, 1);
+ XCTAssertEqual(q->WakeOnResolve, 0);
+ XCTAssertEqual(q->UseBackgroundTraffic, 0);
+ XCTAssertEqual(q->ValidationRequired, 0);
+ XCTAssertEqual(q->ValidatingResponse, 0);
+ XCTAssertEqual(q->ProxyQuestion, 0);
+ XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
+ XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
+ XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
+ XCTAssertNotEqual(q->StopTime, 0);
+ XCTAssertEqual(q->AppendSearchDomains, 0);
+ XCTAssertNil((__bridge id)q->DuplicateOf);
+
+ // At this point the the cache is empty. Calling mDNS_Execute will answer the local-only
+ // question with a negative response.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m); // Regress <rdar://problem/28721294>
+
+ // Verify reply is a negative response and error code is set to kDNSServiceErr_NoSuchRecord error.
+ reply = req->replies;
+ XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+
+ XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+ XCTAssertEqual(q->LOAddressAnswers, 0);
+
+ len = get_reply_len(qname_cstr, 0);
+
+ XCTAssertNil((__bridge id)reply->next);
+ XCTAssertEqual(reply->totallen, reply->mhdr->datalen + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+
+ XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ XCTAssertEqual(reply->rhdr->error,
+ (DNSServiceErrorType)htonl(kDNSServiceErr_NoSuchRecord)); // Regress <rdar://problem/24827555>
+
+ // Simulate what udsserver_idle normally does for clean up
+ freeL("StartLocalOnlyClientQueryRequest:reply", reply);
+ req->replies = NULL;
+
+ // Simulate the query time out of the local-only question.
+ // The expected behavior is a negative answer with time out error
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ q->StopTime = mDNS_TimeNow_NoLock(m);
+ m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
+ mDNS_Execute(m);
+
+ // Verify the reply is a negative response with timeout error.
+ reply = req->replies;
+ XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+ XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+ XCTAssertEqual(q->LOAddressAnswers, 0);
+
+ len = get_reply_len(qname_cstr, 0);
+
+ XCTAssertNil((__bridge id)reply->next);
+ XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+ XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ XCTAssertEqual(reply->rhdr->error,
+ (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
+
+ // Free request and reallocate to use when query is restarted
+ free_req(req);
+ client_request_message = calloc(1, sizeof(request_state));
+}
+
+// This unit test populates the cache with four /etc/hosts records and then
+// verifies there are four entries in the cache.
+- (void)testPopulateCacheWithClientLOResponseRecords
+{
+ mDNS *const m = &mDNSStorage;
+
+ // Verify cache is empty
+ int count = LogEtcHosts_ut(m);
+ XCTAssertEqual(count, 0);
+
+ // Populate /etc/hosts
+ mStatus result = InitEtcHostsRecords();
+ XCTAssertEqual(result, mStatus_NoError);
+
+ // mDNS_Execute is called to populate the /etc/hosts cache.
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m);
+
+ count = LogEtcHosts_ut(m);
+ XCTAssertEqual(count, 4);
+
+ [self _testRestartLocalOnlyClientQueryRequest]; // Continuation of this test
+}
+
+// This unit test starts a local only request for "cardinal2.apple.com.". It first
+// calls start_client_request to start a query, it then verifies the
+// req and query data structures are set as expected. Next, the cache is verified to
+// contain the answer by AnswerNewLocalOnlyQuestion() and so results in setting up an
+// answer reply to the client. On return from mDNS_Execute, the client's reply structure
+// is verified to be set as expected. Lastly the timeout is simulated and mDNS_Execute is
+// called. This results in a call to TimeoutQuestions(). And this time, the
+// GenerateNegativeResponse() is called which returns a negative response to the client
+// which specifies the timeout occurred. Again, the answer reply is verified to
+// to specify a timeout.
+- (void)_testRestartLocalOnlyClientQueryRequest
+{
+ mDNS *const m = &mDNSStorage;
+ request_state* req = client_request_message;
+ char *msgptr = (char *)query_req_msgbuf;
+ size_t msgsz = sizeof(query_req_msgbuf); DNSQuestion *q;
+ mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+ mStatus err = mStatus_NoError;
+ char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+ struct reply_state *reply;
+ size_t len;
+
+ // Process the unit test's client request
+ start_client_request(req, msgptr, msgsz, query_request, local_socket);
+ XCTAssertEqual(err, mStatus_NoError);
+
+ XCTAssertEqual(req->hdr.version, VERSION);
+ XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
+ XCTAssertEqual(req->flags, (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
+ XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexLocalOnly);
+ XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
+ XCTAssertNil((__bridge id)m->Questions);
+
+ q = &req->u.queryrecord.op.q;
+ XCTAssertEqual(q, m->NewLocalOnlyQuestions);
+ XCTAssertEqual(q->SuppressUnusable, 1);
+ XCTAssertEqual(q->ReturnIntermed, 1);
+ XCTAssertEqual(q->Suppressed, mDNSfalse); // Regress <rdar://problem/27571734>
+ XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+ XCTAssertEqual(q->InterfaceID, mDNSInterface_LocalOnly);
+ XCTAssertEqual(q->flags, req->flags);
+ XCTAssertEqual(q->qtype, 1);
+ XCTAssertEqual(q->qclass, 1);
+ XCTAssertEqual(q->LongLived, 0);
+ XCTAssertEqual(q->ExpectUnique, mDNSfalse);
+ XCTAssertEqual(q->ForceMCast, 0);
+ XCTAssertEqual(q->TimeoutQuestion, 1);
+ XCTAssertEqual(q->WakeOnResolve, 0);
+ XCTAssertEqual(q->UseBackgroundTraffic, 0);
+ XCTAssertEqual(q->ValidationRequired, 0);
+ XCTAssertEqual(q->ValidatingResponse, 0);
+ XCTAssertEqual(q->ProxyQuestion, 0);
+ XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
+ XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
+ XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
+ XCTAssertNotEqual(q->StopTime, 0);
+ XCTAssertEqual(q->AppendSearchDomains, 0);
+ XCTAssertNil((__bridge id)q->DuplicateOf);
+ ConvertDomainNameToCString(&q->qname, qname_cstr);
+ XCTAssertFalse(strcmp(qname_cstr, domainname_cstr));
+
+ // Answer local-only question with found cache entry
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ mDNS_Execute(m); // Regress <rdar://problem/28721294>
+ XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+ XCTAssertEqual(req->u.queryrecord.op.answered, 1);
+ XCTAssertEqual(q->LOAddressAnswers, 1);
+ XCTAssertEqual(q, m->LocalOnlyQuestions);
+
+ reply = req->replies;
+ len = get_reply_len(qname_cstr, 4);
+
+ XCTAssertNil((__bridge id)reply->next);
+ XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+ XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+
+ // Simulate the query time out of the local-only question.
+ // The expected behavior is a negative answer with time out error
+ m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+ q->StopTime = mDNS_TimeNow_NoLock(m);
+ m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
+ mDNS_Execute(m);
+
+ reply = req->replies->next;
+ XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+ XCTAssertNil((__bridge id)reply->next);
+ XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+ XCTAssertEqual(q->LOAddressAnswers, 0);
+ len = get_reply_len(qname_cstr, 0);
+
+ XCTAssertNil((__bridge id)reply->next);
+ XCTAssertEqual(reply->totallen, len + + sizeof(ipc_msg_hdr));
+ XCTAssertEqual(reply->mhdr->version, VERSION);
+ XCTAssertEqual(reply->mhdr->datalen, len);
+ XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+ XCTAssertEqual(reply->mhdr->op, query_reply_op);
+ XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+ XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
+ XCTAssertEqual(reply->rhdr->error,
+ (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
+
+ free_req(req);
+}
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
+#import <XCTest/XCTest.h>
+
+@interface ResourceRecordTest : XCTestCase
+{
+}
+@end
+
+@implementation ResourceRecordTest
+
+- (void)setUp
+{
+}
+
+- (void)tearDown
+{
+}
+
+- (void)testTXTSetup
+{
+ AuthRecord authRec;
+ mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeShared, AuthRecordAny,mDNSNULL, mDNSNULL);
+ XCTAssertEqual(authRec.resrec.rrtype, kDNSType_TXT);
+ XCTAssertEqual(authRec.resrec.RecordType, kDNSRecordTypeShared);
+ XCTAssertEqual(authRec.resrec.rdata->MaxRDLength, sizeof(RDataBody));
+}
+
+- (void)testASetup
+{
+ AuthRecord authRec;
+ mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+
+ XCTAssertEqual(authRec.resrec.rrtype, kDNSType_A);
+ XCTAssertEqual(authRec.resrec.RecordType, kDNSRecordTypeUnique);
+ // Add more verifications
+}
+
+- (void)testOPTSetup
+{
+ AuthRecord opt;
+ mDNSu32 updatelease = 7200;
+
+ // Setup the OPT Record
+ mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+
+ // Verify the basic initialization is all ok
+
+ 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;
+
+ // Put the resource record in and verify everything is fine
+#if 0
+ mDNSu8 data[AbsoluteMaxDNSMessageData];
+ mDNSu8 *p = data;
+ mDNSu16 numAdditionals;
+
+ p = PutResourceRecordTTLWithLimit((DNSMessage*)&data, p, &numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, data + AbsoluteMaxDNSMessageData);
+#endif
+}
+
+// Repeat with bad data to make sure it bails out cleanly
+
+#if 0
+- (void)testPerformanceExample {
+ // This is an example of a performance test case.
+ [self measureBlock:^{
+ // Put the code you want to measure the time of here.
+ }];
+}
+#endif
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "unittest_common.h"
+#import <XCTest/XCTest.h>
+
+// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
+uint8_t udns_query_request_message[28] = { // contains 1 question for www.f5.com
+ 0x31, 0xca, // transaction id
+ 0x01, 0x00, // flags
+ 0x00, 0x01, // 1 question
+ 0x00, 0x00, // no anwsers
+ 0x00, 0x00, // no authoritative answers
+ 0x00, 0x00, // no additionals
+ 0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
+// Then the header id (more specifically, the msg->h.id) was deliberately cleared to force code
+// path to traverse regression case, <rdar://problem/28556513>.
+uint8_t udns_query_request_message_with_invalid_id[28] = { // contains 1 question for www.f5.com, msg->h.id = 0
+ 0x00, 0x00, // transaction id
+ 0x01, 0x00, // flags
+ 0x00, 0x01, // 1 question
+ 0x00, 0x00, // no anwsers
+ 0x00, 0x00, // no authoritative answers
+ 0x00, 0x00, // no additionals
+ 0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+uint8_t arp_request_packet[28] = { // contains 1 question for www.f5.com, msg->h.id = 0
+ 0x00, 0x01, // hardware type: enet
+ 0x08, 0x00, // protocol type: IP
+ 0x06, // hardware size
+ 0x04, // Protcol size
+ 0x00, 0x01, // opcode request
+ 0x24, 0x01, 0xc7, 0x24, 0x35, 0x00, // Sender mac addr
+ 0x11, 0xe2, 0x14, 0x01, // Sender ip addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // target mac addr
+ 0x11, 0xe2, 0x17, 0xbe // target ip addr
+};
+
+mDNSlocal void InitmDNSStorage(mDNS *const m)
+{
+ memset(m, 0, sizeof(mDNS));
+}
+
+@interface mDNSCoreReceiveTest : XCTestCase
+{
+}
+@end
+
+@implementation mDNSCoreReceiveTest
+
+- (void)setUp
+{
+ mDNSPlatformTimeInit();
+ mDNS_LoggingEnabled = 0;
+ mDNS_PacketLoggingEnabled = 0;
+}
+
+- (void)tearDown {
+}
+
+- (void)testValidQueryReq
+{
+ mDNS *const m = &mDNSStorage;
+ mDNSAddr srcaddr, dstaddr;
+ mDNSIPPort srcport, dstport;
+ DNSMessage * msg;
+ const mDNSu8 * end;
+
+ // Init unit test environment and verify no error occurred.
+ mStatus result = init_mdns_environment(mDNStrue);
+ XCTAssertEqual(result, mStatus_NoError);
+
+ // Used random values for srcaddr and srcport
+ srcaddr.type = mDNSAddrType_IPv4;
+ srcaddr.ip.v4.b[0] = 192;
+ srcaddr.ip.v4.b[1] = 168;
+ srcaddr.ip.v4.b[2] = 1;
+ srcaddr.ip.v4.b[3] = 10;
+ srcport.NotAnInteger = swap16((mDNSu16)53);
+
+ // Used random values for dstaddr and dstport
+ dstaddr.type = mDNSAddrType_IPv4;
+ dstaddr.ip.v4.b[0] = 192;
+ dstaddr.ip.v4.b[1] = 168;
+ dstaddr.ip.v4.b[2] = 1;
+ dstaddr.ip.v4.b[3] = 20;
+ dstport.NotAnInteger = swap16((mDNSu16)49339);
+
+ // Set message to a DNS message (copied from a WireShark packet)
+ msg = (DNSMessage *)udns_query_request_message;
+ end = udns_query_request_message + sizeof(udns_query_request_message);
+
+ // Execute mDNSCoreReceive using a valid DNS message
+ mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &dstaddr, dstport, if_nametoindex("en0"));
+
+ // Verify that mDNSCoreReceiveQuery traversed the normal code path
+ XCTAssertEqual(m->mDNSStats.NormalQueries, 1);
+}
+
+- (void)testNullDstQueryReqTest
+{
+ mDNS *const m = &mDNSStorage;
+ mDNSAddr srcaddr;
+ mDNSIPPort srcport, dstport;
+ DNSMessage * msg;
+ const mDNSu8 * end;
+
+ // This test case does not require setup of interfaces, the record's cache, or pending questions
+ // so m is initialized to all zeros.
+ InitmDNSStorage(m);
+
+ // Used random values for srcaddr and srcport
+ srcaddr.type = mDNSAddrType_IPv4;
+ srcaddr.ip.v4.b[0] = 192;
+ srcaddr.ip.v4.b[1] = 168;
+ srcaddr.ip.v4.b[2] = 1;
+ srcaddr.ip.v4.b[3] = 10;
+ srcport.NotAnInteger = swap16((mDNSu16)53);
+
+ // Used random value for dstport
+ dstport.NotAnInteger = swap16((mDNSu16)49339);
+
+ // Set message to a DNS message (copied from a WireShark packet)
+ msg = (DNSMessage *)udns_query_request_message_with_invalid_id;
+ end = udns_query_request_message_with_invalid_id + sizeof(udns_query_request_message_with_invalid_id);
+
+ // Execute mDNSCoreReceive to regress <rdar://problem/28556513>
+ mDNSCoreReceive(m, msg, end, &srcaddr, srcport, NULL, dstport, if_nametoindex("en0"));
+
+ // Verify that mDNSCoreReceiveQuery was NOT traversed through the normal code path
+ XCTAssertEqual(m->mDNSStats.NormalQueries, 0);
+
+ // Verify code path that previously crashed, in <rdar://problem/28556513>, now traverses successfully
+ // by checking a counter that was incremented on code path that crashed.
+ XCTAssertEqual(m->MPktNum, 1);
+}
+
+
+#if 0
+- (void)testPerformanceExample {
+ // This is an example of a performance test case.
+ [self measureBlock:^{
+ // Put the code you want to measure the time of here.
+ }];
+}
+#endif
+
+@end
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Project</key>
+ <string>mDNSResponder</string>
+ <key>RadarComponents</key>
+ <dict>
+ <key>Name</key>
+ <string>mDNSResponder</string>
+ <key>Version</key>
+ <string>all</string>
+ </dict>
+ <key>Tests</key>
+ <array>
+ <dict>
+ <key>TestName</key>
+ <string>GAIPerf Advanced</string>
+ <key>Description</key>
+ <string>Tests correctness of resolving hostnames via DNS using the GAIPerf Advanced test suite.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>900</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>gaiperf</string>
+ <string>--suite</string>
+ <string>advanced</string>
+ <string>--timeLimit</string>
+ <string>250</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--skipPathEval</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 1-1-1</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>1</string>
+ <string>--txtSize</string>
+ <string>1</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>1</string>
+ <string>--countAAAA</string>
+ <string>1</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 1-1-1 (No Additionals)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record. Responses from mdnsreplier contain no additional answers.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>1</string>
+ <string>--txtSize</string>
+ <string>1</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>1</string>
+ <string>--countAAAA</string>
+ <string>1</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--noAdditionals</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 10-100-2</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>10</string>
+ <string>--txtSize</string>
+ <string>100</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 10-100-2 (No Additionals)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. Responses from mdnsreplier contain no additional answers.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>10</string>
+ <string>--txtSize</string>
+ <string>100</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--noAdditionals</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 100-500-2</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>100</string>
+ <string>--txtSize</string>
+ <string>500</string>
+ <string>--browseTime</string>
+ <string>5</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 100-500-2 (No Additionals)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records. Responses from mdnsreplier contain no additional answers.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>100</string>
+ <string>--txtSize</string>
+ <string>500</string>
+ <string>--browseTime</string>
+ <string>5</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--noAdditionals</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 1-1-1 (No Cache Flush)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record. Cache is not flushed beforehand.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>1</string>
+ <string>--txtSize</string>
+ <string>1</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>1</string>
+ <string>--countAAAA</string>
+ <string>1</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 1-1-1 (No Cache Flush, No Additionals)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>1</string>
+ <string>--txtSize</string>
+ <string>1</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>1</string>
+ <string>--countAAAA</string>
+ <string>1</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--noAdditionals</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 10-100-2 (No Cache Flush)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>10</string>
+ <string>--txtSize</string>
+ <string>100</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 10-100-2 (No Cache Flush, No Additionals)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>10</string>
+ <string>--txtSize</string>
+ <string>100</string>
+ <string>--browseTime</string>
+ <string>3</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--noAdditionals</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 100-500-2 (No Cache Flush)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>100</string>
+ <string>--txtSize</string>
+ <string>500</string>
+ <string>--browseTime</string>
+ <string>5</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--format</string>
+ <string>json</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery 100-500-2 (No Cache Flush, No Additionals)</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>100</string>
+ <string>--txtSize</string>
+ <string>500</string>
+ <string>--browseTime</string>
+ <string>5</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv4</string>
+ <string>--ipv6</string>
+ <string>--noAdditionals</string>
+ <string>--format</string>
+ <string>json</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery w/Packet Drops 10</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>30</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>10</string>
+ <string>--txtSize</string>
+ <string>100</string>
+ <string>--browseTime</string>
+ <string>16</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv6</string>
+ <string>--udrop</string>
+ <string>0.5</string>
+ <string>--mdrop</string>
+ <string>0.5</string>
+ <string>--maxDropCount</string>
+ <string>3</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNS Discovery w/Packet Drops 100</string>
+ <key>Description</key>
+ <string>Tests mDNS discovery and resolution of 100 service instances with one 100-byte TXT record, two A records, and two AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>30</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>mdnsdiscovery</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--instanceCount</string>
+ <string>100</string>
+ <string>--txtSize</string>
+ <string>100</string>
+ <string>--browseTime</string>
+ <string>18</string>
+ <string>--countA</string>
+ <string>2</string>
+ <string>--countAAAA</string>
+ <string>2</string>
+ <string>--ipv6</string>
+ <string>--udrop</string>
+ <string>0.5</string>
+ <string>--mdrop</string>
+ <string>0.5</string>
+ <string>--maxDropCount</string>
+ <string>3</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--flushCache</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>DotLocal Queries</string>
+ <key>Description</key>
+ <string>Tests DNS and mDNS queries for domain names in the local domain.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>40</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>dotlocal</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--format</string>
+ <string>json</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>Service Registration</string>
+ <key>Description</key>
+ <string>Tests Bonjour service registration.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <true/>
+ <key>Timeout</key>
+ <integer>120</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>registration</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--bats</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>Probe Conflicts</string>
+ <key>Description</key>
+ <string>Tests various probe conflict scenarios, some of which are expected to result in service instance and record renames.</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>300</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>probeconflicts</string>
+ <string>--interface</string>
+ <string>lo0</string>
+ <string>--format</string>
+ <string>json</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>TCP Fallback</string>
+ <key>Description</key>
+ <string>Tests mDNSResponder's TCP fallback mechanism, which is triggered by UDP responses with invalid message IDs that would otherwise be acceptable.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>90</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>gaiperf</string>
+ <string>--suite</string>
+ <string>basic</string>
+ <string>--timeLimit</string>
+ <string>250</string>
+ <string>--format</string>
+ <string>json</string>
+ <string>--skipPathEval</string>
+ <string>--badUDPMode</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>State Dump</string>
+ <key>Description</key>
+ <string>1. Tests whether the state dump can be triggered correctly, and whether the file (or stdout's output) contains the full state information. 2. Checks whether the number of state dump files has an upper limit to avoid wasting disk space.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <true/>
+ <key>Timeout</key>
+ <integer>60</integer>
+ <key>IgnoreOutput</key>
+ <false/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>browseAll</string>
+ <string>&&</string>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/mDNSResponder/bats_test_state_dump.sh</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>DNS Proxy</string>
+ <key>Description</key>
+ <string>1. Tests the DNS Proxy by doing a DNS UDP query. 2. Tests the DNS proxy by doing a DNS TCP query.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <true/>
+ <key>Timeout</key>
+ <integer>60</integer>
+ <key>IgnoreOutput</key>
+ <false/>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/mDNSResponder/bats_test_proxy.sh</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>Expensive/Constrained Interface</string>
+ <key>Description</key>
+ <string>Test the following situation:
+1. The interface is set to expensive and inexpensive, and the query is set to DenyExpensive, a continuous ADD/REMOVE sequence is expected.
+2. The interface is set to expensive and inexpensive, and the query does not DenyExpensive, no update is expected.
+3. The interface is set to constrained and unconstrained, and the query is set to DenyConstrained, a continuous ADD/REMOVE sequence is expected.
+4. The interface is set to constrained and unconstrained, and the query does not DenyConstrained, no update is expected.
+5. The interface is set to expensive and constrained, and the query is set to DenyExpensive and DenyConstrained.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>1200</integer>
+ <key>IgnoreOutput</key>
+ <false/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/dnssdutil</string>
+ <string>test</string>
+ <string>expensive_constrained_updates</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>mDNSResponder Leaks</string>
+ <key>Description</key>
+ <string>Checks mDNSResponder for memory leaks.</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>RequiresWiFi</key>
+ <false/>
+ <key>Timeout</key>
+ <integer>10</integer>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/bin/leaks</string>
+ <string>mDNSResponder</string>
+ </array>
+ </dict>
+ <dict>
+ <key>TestName</key>
+ <string>XCTests</string>
+ <key>Description</key>
+ <string>mDNSResponder XCTests</string>
+ <key>WorkingDirectory</key>
+ <string>/AppleInternal/XCTests/com.apple.mDNSResponder/</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>RequiresWiFi</key>
+ <true/>
+ <key>Timeout</key>
+ <integer>20</integer>
+ <key>ShowSubtestResults</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>BATS_XCTEST_CMD</string>
+ <string>-NSTreatUnknownArgumentsAsOpen</string>
+ <string>NO</string>
+ <string>-ApplePersistenceIgnoreState</string>
+ <string>YES</string>
+ <string>-XCTest</string>
+ <string>Self</string>
+ <string>Tests.xctest</string>
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
</array>
<key>MachServices</key>
<dict>
- <key>com.apple.mDNSResponder.dnsproxy</key>
+ <key>com.apple.dnssd.service</key>
+ <true/>
+ <key>com.apple.mDNSResponder.log_utility</key>
<true/>
- <key>com.apple.mDNSResponder.dnsctl</key>
+ <key>com.apple.mDNSResponder.dnsproxy</key>
<true/>
</dict>
<key>Sockets</key>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.mDNSResponder.log_utility</key>
+ <true/>
+</dict>
+</plist>
+
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil -*-
*
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
#include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
#include <err.h>
#include <sysexits.h>
-
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
+#include <TargetConditionals.h>
#include "uDNS.h"
#include "DNSCommon.h"
#include "mDNSMacOSX.h" // Defines the specific types needed to run mDNS on this platform
#include "uds_daemon.h" // Interface to the server side implementation of dns_sd.h
-#include "xpc_services.h" // Interface to XPC services
+#include "xpc_services.h"
+#include "xpc_service_dns_proxy.h"
+#include "xpc_service_log_utility.h"
#include "helper.h"
+#include "posix_utilities.h" // for getLocalTimestamp()
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
#include "Metrics.h"
#endif
-#if APPLE_OSX_mDNSResponder
-static os_log_t log_general = NULL;
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+#include "dnssd_server.h"
#endif
-
// Used on OSX(10.11.x onwards) for manipulating mDNSResponder program arguments
#if APPLE_OSX_mDNSResponder
// plist file to read the user's preferences
#define kPreferencesKey_DefaultToBLETriggered CFSTR("DefaultToBLETriggered")
#endif // ENABLE_BLE_TRIGGERED_BONJOUR
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
#define kPreferencesKey_PreallocateCacheMemory CFSTR("PreallocateCacheMemory")
#endif
#endif
extern mDNSBool StrictUnicastOrdering;
extern mDNSBool AlwaysAppendSearchDomains;
extern mDNSBool EnableAllowExpired;
+mDNSexport void INFOCallback(void);
+mDNSexport void dump_state_to_fd(int fd);
#if ENABLE_BLE_TRIGGERED_BONJOUR
extern mDNSBool EnableBLEBasedDiscovery;
extern mDNSBool DefaultToBLETriggered;
#endif // ENABLE_BLE_TRIGGERED_BONJOUR
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
static mDNSBool PreallocateCacheMemory = mDNSfalse;
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_MEM_LIMIT)
#define kRRCacheMemoryLimit 1000000 // For now, we limit the cache to at most 1MB on iOS devices.
#endif
#pragma mark - General Utility Functions
#endif
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-
-char _malloc_options[] = "AXZ";
-
-mDNSlocal void validatelists(mDNS *const m)
+#if MDNS_MALLOC_DEBUGGING
+void mDNSPlatformValidateLists()
{
-#if BONJOUR_ON_DEMAND
- mDNSu32 NumAllInterfaceRecords = 0;
- mDNSu32 NumAllInterfaceQuestions = 0;
-#endif // BONJOUR_ON_DEMAND
+ mDNS *const m = &mDNSStorage;
- // Check local lists
KQSocketEventSource *k;
for (k = gEventSources; k; k=k->next)
if (k->next == (KQSocketEventSource *)~0 || k->fd < 0)
LogMemCorruption("gEventSources: %p is garbage (%d)", k, k->fd);
- // Check Unix Domain Socket client lists (uds_daemon.c)
- uds_validatelists();
-
- // Check core mDNS lists
- AuthRecord *rr;
- for (rr = m->ResourceRecords; rr; rr=rr->next)
- {
- if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
- LogMemCorruption("ResourceRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
- if (rr->resrec.name != &rr->namestorage)
- LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
- rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
-#if BONJOUR_ON_DEMAND
- if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
-#endif // BONJOUR_ON_DEMAND
- }
-
- for (rr = m->DuplicateRecords; rr; rr=rr->next)
- {
- if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
- LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
-#if BONJOUR_ON_DEMAND
- if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
-#endif // BONJOUR_ON_DEMAND
- }
-
- rr = m->NewLocalRecords;
- if (rr)
- if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
- LogMemCorruption("NewLocalRecords: %p is garbage (%X)", rr, rr->resrec.RecordType);
-
- rr = m->CurrentRecord;
- if (rr)
- if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
- LogMemCorruption("CurrentRecord: %p is garbage (%X)", rr, rr->resrec.RecordType);
-
- DNSQuestion *q;
- for (q = m->Questions; q; q=q->next)
- {
- if (q->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
- LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
- if (q->DuplicateOf && q->LocalSocket)
- LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
-#if BONJOUR_ON_DEMAND
- if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID))
- NumAllInterfaceQuestions++;
-#endif // BONJOUR_ON_DEMAND
- }
-
- CacheGroup *cg;
- CacheRecord *cr;
- mDNSu32 slot;
- FORALL_CACHERECORDS(slot, cg, cr)
- {
- if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
- LogMemCorruption("Cache slot %lu: %p is garbage (%X)", slot, cr, cr->resrec.RecordType);
- if (cr->CRActiveQuestion)
- {
- for (q = m->Questions; q; q=q->next) if (q == cr->CRActiveQuestion) break;
- if (!q) LogMemCorruption("Cache slot %lu: CRActiveQuestion %p not in m->Questions list %s", slot, cr->CRActiveQuestion, CRDisplayString(m, cr));
- }
- }
-
- // Check core uDNS lists
- udns_validatelists(m);
-
// Check platform-layer lists
NetworkInterfaceInfoOSX *i;
for (i = m->p->InterfaceList; i; i = i->next)
for (t = m->TunnelClients; t; t=t->next)
if (t->next == (ClientTunnel *)~0 || t->dstname.c[0] > 63)
LogMemCorruption("m->TunnelClients: %p is garbage (%d)", t, t->dstname.c[0]);
-
-#if BONJOUR_ON_DEMAND
- if (m->NumAllInterfaceRecords != NumAllInterfaceRecords)
- LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords);
-
- if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions)
- LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions);
-#endif // BONJOUR_ON_DEMAND
}
-
-mDNSexport void *mallocL(char *msg, unsigned int size)
-{
- // Allocate space for two words of sanity checking data before the requested block
- mDNSu32 *mem = malloc(sizeof(mDNSu32) * 2 + size);
- if (!mem)
- { LogMsg("malloc( %s : %d ) failed", msg, size); return(NULL); }
- else
- {
- if (size > 32768) LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
- else if (MACOSX_MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) @ %p", msg, size, &mem[2]);
- mem[0] = 0xDEAD1234;
- mem[1] = size;
- //mDNSPlatformMemZero(&mem[2], size);
- memset(&mem[2], 0xFF, size);
- validatelists(&mDNSStorage);
- return(&mem[2]);
- }
-}
-
-mDNSexport void freeL(char *msg, void *x)
-{
- if (!x)
- LogMsg("free( %s @ NULL )!", msg);
- else
- {
- mDNSu32 *mem = ((mDNSu32 *)x) - 2;
- if (mem[0] == 0xDEADDEAD) { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; }
- if (mem[0] != 0xDEAD1234) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!", msg, mem[1], &mem[2]); return; }
- if (mem[1] > 32768) LogMsg("free( %s : %lu @ %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]);
- mem[0] = 0xDEADDEAD;
- memset(mem+2, 0xFF, mem[1]);
- validatelists(&mDNSStorage);
- free(mem);
- }
-}
-
-#endif
+#endif // MDNS_MALLOC_DEBUGGING
//*************************************************************************************************************
// Registration
{
// Allocate another chunk of cache storage
static unsigned int allocated = 0;
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_MEM_LIMIT)
if (allocated >= kRRCacheMemoryLimit) return; // For now we limit the cache to at most 1MB on iOS devices
#endif
allocated += kRRCacheGrowSize;
#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-mDNSexport void INFOCallback(void)
+mDNSexport void dump_state_to_fd(int fd)
{
+ mDNS *const m = &mDNSStorage;
+ char buffer[1024];
+ buffer[0] = '\0';
+
mDNSs32 utc = mDNSPlatformUTC();
const mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
NetworkInterfaceInfoOSX *i;
DNSServer *s;
McastResolver *mr;
+ char timestamp[64]; // 64 is enough to store the UTC timestmp
- LogMsg("---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+ LogToFD(fd, "---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+ getLocalTimestamp(timestamp, sizeof(timestamp));
+ LogToFD(fd, "Date: %s", timestamp);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- BEGIN STATE LOG ---- (" PUB_S ")", timestamp);
- udsserver_info();
+ udsserver_info_dump_to_fd(fd);
- LogMsgNoIdent("----- Platform Timers -----");
- LogTimer("m->NextCacheCheck ", mDNSStorage.NextCacheCheck);
- LogTimer("m->NetworkChanged ", mDNSStorage.NetworkChanged);
- LogTimer("m->p->NotifyUser ", mDNSStorage.p->NotifyUser);
- LogTimer("m->p->HostNameConflict ", mDNSStorage.p->HostNameConflict);
- LogTimer("m->p->KeyChainTimer ", mDNSStorage.p->KeyChainTimer);
+ LogToFD(fd, "----- Platform Timers -----");
+ LogTimerToFD(fd, "m->NextCacheCheck ", mDNSStorage.NextCacheCheck);
+ LogTimerToFD(fd, "m->NetworkChanged ", mDNSStorage.NetworkChanged);
+ LogTimerToFD(fd, "m->p->NotifyUser ", mDNSStorage.p->NotifyUser);
+ LogTimerToFD(fd, "m->p->HostNameConflict ", mDNSStorage.p->HostNameConflict);
+ LogTimerToFD(fd, "m->p->KeyChainTimer ", mDNSStorage.p->KeyChainTimer);
- xpcserver_info(&mDNSStorage);
+ log_dnsproxy_info_to_fd(fd, &mDNSStorage);
- LogMsgNoIdent("----- KQSocketEventSources -----");
- if (!gEventSources) LogMsgNoIdent("<None>");
+ LogToFD(fd, "----- KQSocketEventSources -----");
+ if (!gEventSources) LogToFD(fd, "<None>");
else
{
KQSocketEventSource *k;
for (k = gEventSources; k; k=k->next)
- LogMsgNoIdent("%3d %s %s", k->fd, k->kqs.KQtask, k->fd == mDNSStorage.uds_listener_skt ? "Listener for incoming UDS clients" : " ");
+ LogToFD(fd, "%3d %s %s", k->fd, k->kqs.KQtask, k->fd == mDNSStorage.uds_listener_skt ? "Listener for incoming UDS clients" : " ");
}
- LogMsgNoIdent("------ Network Interfaces ------");
- if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
+ LogToFD(fd, "------ Network Interfaces ------");
+ if (!mDNSStorage.p->InterfaceList) LogToFD(fd, "<None>");
else
{
- LogMsgNoIdent(" Struct addr Registered MAC BSSID Interface Address");
+ LogToFD(fd, " Struct addr Registered MAC BSSID Interface Address");
for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
{
// Allow six characters for interface name, for names like "vmnet8"
if (!i->Exists)
- LogMsgNoIdent("%p %2ld, %p, %s %-6s %.6a %.6a %#-14a dormant for %d seconds",
- i, i->ifinfo.InterfaceID, i->Registered,
- i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
- &i->ifinfo.ip, utc - i->LastSeen);
+ LogToFD(fd, "%p %2ld, %p, %s %-6s %.6a %.6a %#-14a dormant for %d seconds",
+ i, i->ifinfo.InterfaceID, i->Registered,
+ i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
+ &i->ifinfo.ip, utc - i->LastSeen);
else
{
const CacheRecord *sps[3];
FindSPSInCache(&mDNSStorage, &i->ifinfo.NetWakeBrowse, sps);
- LogMsgNoIdent("%p %2ld, %p, %s %-6s %.6a %.6a %s %s %s %s %s %s %#a",
- i, i->ifinfo.InterfaceID, i->Registered,
- i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
- i->ifinfo.InterfaceActive ? "Active" : " ",
- i->ifinfo.IPv4Available ? "v4" : " ",
- i->ifinfo.IPv6Available ? "v6" : " ",
- i->ifinfo.Advertise ? "A" : " ",
- i->ifinfo.McastTxRx ? "M" : " ",
- !(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "p" : "P",
- &i->ifinfo.ip);
+ LogToFD(fd, "%p %2ld, %p, %s %-6s %.6a %.6a %s %s %s %s %s %s %#a",
+ i, i->ifinfo.InterfaceID, i->Registered,
+ i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
+ i->ifinfo.InterfaceActive ? "Active" : " ",
+ i->ifinfo.IPv4Available ? "v4" : " ",
+ i->ifinfo.IPv6Available ? "v6" : " ",
+ i->ifinfo.Advertise ? "A" : " ",
+ i->ifinfo.McastTxRx ? "M" : " ",
+ !(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "p" : "P",
+ &i->ifinfo.ip);
// Only print the discovered sleep proxies once for the lead/active interface of an interface set.
if (i == i->Registered && (sps[0] || sps[1] || sps[2]))
{
- LogMsgNoIdent(" Sleep Proxy Metric Name");
- if (sps[0]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c);
- if (sps[1]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c);
- if (sps[2]) LogMsgNoIdent(" %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c);
+ LogToFD(fd, " Sleep Proxy Metric Name");
+ if (sps[0]) LogToFD(fd, " %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c);
+ if (sps[1]) LogToFD(fd, " %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c);
+ if (sps[2]) LogToFD(fd, " %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c);
}
}
}
}
- LogMsgNoIdent("--------- DNS Servers(%d) ----------", NumUnicastDNSServers);
- if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
+ LogToFD(fd, "--------- DNS Servers(%d) ----------", CountOfUnicastDNSServers(&mDNSStorage));
+ if (!mDNSStorage.DNSServers) LogToFD(fd, "<None>");
else
{
for (s = mDNSStorage.DNSServers; s; s = s->next)
{
NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(s->interface);
- LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %u %s %s %s %s %s %s",
- s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
- s->penaltyTime ? (s->penaltyTime - mDNS_TimeNow(&mDNSStorage)) : 0, DNSScopeToString(s->scopeType),
- s->timeout, s->resGroupID,
- s->req_A ? "v4" : "!v4",
- s->req_AAAA ? "v6" : "!v6",
- s->isCell ? "cell" : "!cell",
- s->isExpensive ? "exp" : "!exp",
- s->isCLAT46 ? "clat46" : "!clat46",
- s->DNSSECAware ? "DNSSECAware" : "!DNSSECAware");
+ LogToFD(fd, "DNS Server %##s %s%s%#a:%d %d %s %d %d %sv4 %sv6 %scell %sexp %sconstrained %sCLAT46 %sDNSSECAware",
+ s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
+ s->penaltyTime ? (s->penaltyTime - mDNS_TimeNow(&mDNSStorage)) : 0, DNSScopeToString(s->scopeType),
+ s->timeout, s->resGroupID,
+ s->usableA ? "" : "!",
+ s->usableAAAA ? "" : "!",
+ s->isCell ? "" : "!",
+ s->isExpensive ? "" : "!",
+ s->isConstrained ? "" : "!",
+ s->isCLAT46 ? "" : "!",
+ s->DNSSECAware ? "" : "!");
}
}
- LogMsgNoIdent("v4answers %d", mDNSStorage.p->v4answers);
- LogMsgNoIdent("v6answers %d", mDNSStorage.p->v6answers);
- LogMsgNoIdent("Last DNS Trigger: %d ms ago", (now - mDNSStorage.p->DNSTrigger));
+ LogToFD(fd, "v4answers %d", mDNSStorage.p->v4answers);
+ LogToFD(fd, "v6answers %d", mDNSStorage.p->v6answers);
+ LogToFD(fd, "Last DNS Trigger: %d ms ago", (now - mDNSStorage.p->DNSTrigger));
+
+ LogToFD(fd, "-------- Interface Monitors --------");
+ const CFIndex n = m->p->InterfaceMonitors ? CFArrayGetCount(m->p->InterfaceMonitors) : 0;
+ if (n > 0)
+ {
+ for (CFIndex j = 0; j < n; j++)
+ {
+ mdns_interface_monitor_t monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, j);
+ char *description = mdns_copy_description(monitor);
+ if (description)
+ {
+ LogToFD(fd, "%s", description);
+ free(description);
+ }
+ else
+ {
+ LogToFD(fd, "monitor %p (no description)", monitor);
+ }
+ }
+ }
+ else
+ {
+ LogToFD(fd, "No interface monitors");
+ }
- LogMsgNoIdent("--------- Mcast Resolvers ----------");
- if (!mDNSStorage.McastResolvers) LogMsgNoIdent("<None>");
+ LogToFD(fd, "--------- Mcast Resolvers ----------");
+ if (!mDNSStorage.McastResolvers) LogToFD(fd, "<None>");
else
{
for (mr = mDNSStorage.McastResolvers; mr; mr = mr->next)
- LogMsgNoIdent("Mcast Resolver %##s timeout %u", mr->domain.c, mr->timeout);
+ LogToFD(fd, "Mcast Resolver %##s timeout %u", mr->domain.c, mr->timeout);
}
- LogMsgNoIdent("------------ Hostnames -------------");
- if (!mDNSStorage.Hostnames) LogMsgNoIdent("<None>");
+ LogToFD(fd, "------------ Hostnames -------------");
+ if (!mDNSStorage.Hostnames) LogToFD(fd, "<None>");
else
{
HostnameInfo *hi;
for (hi = mDNSStorage.Hostnames; hi; hi = hi->next)
{
- LogMsgNoIdent("%##s v4 %d %s", hi->fqdn.c, hi->arv4.state, ARDisplayString(&mDNSStorage, &hi->arv4));
- LogMsgNoIdent("%##s v6 %d %s", hi->fqdn.c, hi->arv6.state, ARDisplayString(&mDNSStorage, &hi->arv6));
+ LogToFD(fd, "%##s v4 %d %s", hi->fqdn.c, hi->arv4.state, ARDisplayString(&mDNSStorage, &hi->arv4));
+ LogToFD(fd, "%##s v6 %d %s", hi->fqdn.c, hi->arv6.state, ARDisplayString(&mDNSStorage, &hi->arv6));
}
}
- LogMsgNoIdent("--------------- FQDN ---------------");
- if (!mDNSStorage.FQDN.c[0]) LogMsgNoIdent("<None>");
+ LogToFD(fd, "--------------- FQDN ---------------");
+ if (!mDNSStorage.FQDN.c[0]) LogToFD(fd, "<None>");
else
{
- LogMsgNoIdent("%##s", mDNSStorage.FQDN.c);
+ LogToFD(fd, "%##s", mDNSStorage.FQDN.c);
}
-#if AWD_METRICS
- LogMetrics();
-#endif
- LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
- LogMsg("---- END STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
-}
+ #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+ LogMetricsToFD(fd);
+ #endif
+// getLocalTimestamp(timestamp, sizeof(timestamp));
+ LogToFD(fd, "Date: %s", timestamp);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- END STATE LOG ---- (" PUB_S ")", timestamp);
+ LogToFD(fd, "---- END STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+}
-mDNSexport void mDNSPlatformLogToFile(int log_level, const char *buffer)
+mDNSexport void INFOCallback(void)
{
- if (!log_general)
- os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in init_logging()");
- else
- os_log_with_type(log_general, log_level, "%{private}s", buffer);
-
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+ "Sending SIGINFO to mDNSResponder daemon is deprecated. To trigger state dump, please use 'dns-sd -O', enter 'dns-sd -h' for more information");
}
// Writes the state out to the dynamic store and also affects the ASL filter level
}
CFNumberRef numOne = CFNumberCreate(NULL, kCFNumberSInt32Type, &one);
- if (!numOne)
+ if (numOne == NULL)
{
LogMsg("UpdateDebugState: Could not create CFNumber one");
return;
}
CFNumberRef numZero = CFNumberCreate(NULL, kCFNumberSInt32Type, &zero);
- if (!numZero)
+ if (numZero == NULL)
{
LogMsg("UpdateDebugState: Could not create CFNumber zero");
CFRelease(numOne);
return(err);
}
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
if (PreallocateCacheMemory)
{
const int growCount = (kRRCacheMemoryLimit + kRRCacheGrowSize - 1) / kRRCacheGrowSize;
//interval = 48; // For testing
-#if !TARGET_OS_EMBEDDED
-#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
if (m->p->IOPMConnection) // If lightweight-wake capability is available, use that
{
const CFDateRef WakeDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
{
const mDNSs32 reqs = kIOPMSystemPowerStateCapabilityNetwork;
const CFNumberRef Requirements = CFNumberCreate(NULL, kCFNumberSInt32Type, &reqs);
- if (!Requirements) LogMsg("ScheduleNextWake: CFNumberCreate failed");
+ if (Requirements == NULL) LogMsg("ScheduleNextWake: CFNumberCreate failed");
else
{
const void *OptionKeys[2] = { kIOPMAckDHCPRenewWakeDate, kIOPMAckSystemCapabilityRequirements };
LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval);
}
else // else schedule the wakeup using the old API instead to
-#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
-#endif // TARGET_OS_EMBEDDED
+#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
}
LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
-#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
+#if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
(m->p->IOPMConnection) ? "IOPMConnectionAcknowledgeEventWithOptions" :
#endif
(result == kIOReturnSuccess) ? "IOAllowPowerChange" : "IOCancelPowerChange",
m->SleepLimit = 0; // Don't clear m->SleepLimit until after we've logged it above
m->TimeSlept = mDNSPlatformUTC();
-#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
+#if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
if (m->p->IOPMConnection) IOPMConnectionAcknowledgeEventWithOptions(m->p->IOPMConnection, m->p->SleepCookie, opts);
else
#endif
// Run mDNS_Execute to find out the time we next need to wake up
mDNSs32 start = mDNSPlatformRawTime();
mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ if (m->DNSPushServers != mDNSNULL)
+ {
+ nextTimerEvent = dso_idle(m, nextTimerEvent);
+ }
+#endif
mDNSs32 end = mDNSPlatformRawTime();
if (end - start >= WatchDogReportingThreshold)
- LogInfo("CustomSourceHandler:WARNING: Idle task took %dms to complete", end - start);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+ "CustomSourceHandler: WARNING: Idle task took %d ms to complete", end - start);
+ }
mDNSs32 now = mDNS_TimeNow(m);
// Run mDNS_Execute to find out the time we next need to wake up
mDNSs32 start = mDNSPlatformRawTime();
mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+ dnssd_server_idle();
+#endif
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ if (m->DNSPushServers != mDNSNULL)
+ {
+ mDNS_Lock(m);
+ nextTimerEvent = dso_idle(m, m->timenow, nextTimerEvent);
+ mDNS_Unlock(m);
+ }
+#endif
mDNSs32 end = mDNSPlatformRawTime();
if (end - start >= WatchDogReportingThreshold)
- LogInfo("WARNING: Idle task took %dms to complete", end - start);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "WARNING: Idle task took %d ms to complete", end - start);
+ }
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
- validatelists(m);
+#if MDNS_MALLOC_DEBUGGING >= 1
+ mDNSPlatformValidateLists();
#endif
mDNSs32 now = mDNS_TimeNow(m);
kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext, (new_events[i].flags & EV_EOF) != 0);
mDNSs32 etime = mDNSPlatformRawTime();
if (etime - stime >= WatchDogReportingThreshold)
- LogInfo("WARNING: %s took %dms to complete", KQtask, etime - stime);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+ "WARNING: " PUB_S " took %d ms to complete", KQtask, etime - stime);
+ }
}
}
}
mDNSBool result = defaultValue;
boolean = CFPreferencesCopyAppValue(key, kProgramArguments);
- if (boolean)
+ if (boolean != NULL)
{
if (CFGetTypeID(boolean) == CFBooleanGetTypeID())
result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse;
int result = defaultValue;
number = CFPreferencesCopyAppValue(key, kProgramArguments);
- if (number)
+ if (number != NULL)
{
if ((CFGetTypeID(number) == CFNumberGetTypeID()) && CFNumberGetValue(number, kCFNumberIntType, &numberValue))
result = numberValue;
#endif // MDNS_NO_SANDBOX
}
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+#define MDNS_OS_LOG_CATEGORY_INIT(NAME) \
+ do\
+ { \
+ mDNSLogCategory_ ## NAME = os_log_create("com.apple.mDNSResponder", # NAME ); \
+ if (!mDNSLogCategory_ ## NAME ) \
+ { \
+ os_log_error(OS_LOG_DEFAULT, "Could NOT create the " # NAME " log handle in mDNSResponder"); \
+ mDNSLogCategory_ ## NAME = OS_LOG_DEFAULT; \
+ } \
+ } \
+ while (0)
+
+os_log_t mDNSLogCategory_Default = NULL;
+os_log_t mDNSLogCategory_mDNS = NULL;
+os_log_t mDNSLogCategory_uDNS = NULL;
+os_log_t mDNSLogCategory_SPS = NULL;
+os_log_t mDNSLogCategory_XPC = NULL;
+
mDNSlocal void init_logging(void)
{
- log_general = os_log_create("com.apple.mDNSResponder", "AllINFO");
-
- if (!log_general)
- {
- // OS_LOG_DEFAULT is the default logging object, if you are not creating a custom subsystem/category
- os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in mDNSResponder");
- }
+ MDNS_OS_LOG_CATEGORY_INIT(Default);
+ MDNS_OS_LOG_CATEGORY_INIT(mDNS);
+ MDNS_OS_LOG_CATEGORY_INIT(uDNS);
+ MDNS_OS_LOG_CATEGORY_INIT(SPS);
+ MDNS_OS_LOG_CATEGORY_INIT(XPC);
}
#endif
-#ifdef UNIT_TEST
-// Run the unit test main
-UNITTEST_MAIN
-#else
mDNSexport int main(int argc, char **argv)
{
int i;
bool useSandbox = mDNStrue;
#endif
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
init_logging();
#endif
-
+
mDNSMacOSXSystemBuildNumber(NULL);
LogMsg("%s starting %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
EnableBLEBasedDiscovery = PreferencesGetValueBool(kPreferencesKey_EnableBLEBasedDiscovery, EnableBLEBasedDiscovery);
DefaultToBLETriggered = PreferencesGetValueBool(kPreferencesKey_DefaultToBLETriggered, DefaultToBLETriggered);
#endif // ENABLE_BLE_TRIGGERED_BONJOUR
+#endif
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
PreallocateCacheMemory = PreferencesGetValueBool(kPreferencesKey_PreallocateCacheMemory, PreallocateCacheMemory);
-#endif
#endif
// Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
#endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
mDNSStorage.p = &PlatformStorage; // Make sure mDNSStorage.p is set up, because validatelists uses it
- // Need to Start XPC Server Before LaunchdCheckin() (Reason: rdar11023750)
- xpc_server_init();
-#if DEBUG
- if (!useDebugSocket) {
- if (LaunchdCheckin() == 0)
- useDebugSocket = mDNStrue;
- }
- if (useDebugSocket)
- SetDebugBoundPath();
-#else
- LaunchdCheckin();
-#endif
#ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
#endif
SandboxProcess();
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
status = MetricsInit();
if (status) { LogMsg("Daemon start: MetricsInit failed (%d)", status); }
#endif
status = mDNSDaemonInitialize();
if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
+ // Need to Start XPC Server Before LaunchdCheckin() (Reason: radar:11023750)
+ xpc_server_init();
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+ dnssd_server_init();
+#endif
+#if DEBUG
+ if (!useDebugSocket) {
+ if (LaunchdCheckin() == 0)
+ useDebugSocket = mDNStrue;
+ }
+ if (useDebugSocket)
+ SetDebugBoundPath();
+#else
+ LaunchdCheckin();
+#endif
+
status = udsserver_init(launchd_fds, launchd_fds_count);
if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
exit:
return(status);
}
-#endif // UNIT_TEST
// uds_daemon.c support routines /////////////////////////////////////////////
-mDNSlocal void kqUDSEventCallback(int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
+mDNSlocal void kqUDSEventCallback(int fd, short filter, void *context, mDNSBool encounteredEOF)
{
const KQSocketEventSource *const source = context;
- source->callback(fd, filter, source->context);
+ (void)filter; // unused
+ (void)encounteredEOF; // unused
+
+ source->callback(fd, source->context);
}
// Arrange things so that when data appears on fd, callback is called with context
while (*p && (*p)->fd != fd) p = &(*p)->next;
if (*p) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd); return mStatus_AlreadyRegistered; }
- KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
+ KQSocketEventSource *newSource = (KQSocketEventSource*) callocL("KQSocketEventSource", sizeof(*newSource));
if (!newSource) return mStatus_NoMemoryErr;
newSource->next = mDNSNULL;
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>com.apple.mDNSResponder.dnsproxy</key>
- <true/>
- <key>com.apple.mDNSResponder.dnsctl</key>
- <true/>
-</dict>
-</plist>
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dnssd_private.h"
+
+#include "dnssd_object.h"
+#include "dnssd_xpc.h"
+
+#include <CoreUtils/CoreUtils.h>
+#include <os/object_private.h>
+#include <xpc/private.h>
+
+#if 0
+//======================================================================================================================
+#pragma mark - Kind Declarations
+#endif
+
+#define DNSSD_STRUCT(NAME) struct dnssd_ ## NAME ## _s
+#define DNSSD_TYPE(NAME) dnssd_ ## NAME ## _t
+
+#define DNSSD_KIND_DECLARE(NAME) \
+ static DNSSD_TYPE(NAME) \
+ _dnssd_ ## NAME ## _alloc(void); \
+ \
+ static char * \
+ _dnssd_ ## NAME ## _copy_description(DNSSD_TYPE(NAME) object, bool debug, bool privacy); \
+ \
+ static void \
+ _dnssd_ ## NAME ## _finalize(DNSSD_TYPE(NAME) object)
+
+// Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
+// comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
+// the warning hasn't been disabled.
+
+#define DNSSD_BASE_CHECK(NAME, SUPER) \
+ check_compile_time(offsetof(DNSSD_STRUCT(NAME), base) == 0); \
+ check_compile_time(sizeof_field(DNSSD_STRUCT(NAME), base) == sizeof(DNSSD_STRUCT(SUPER))); \
+ extern int _dnssd_base_type_check[sizeof(&(((DNSSD_TYPE(NAME))0)->base) == ((DNSSD_TYPE(SUPER))0))]
+
+#define DNSSD_KIND_DEFINE(NAME, SUPER) \
+ static const struct dnssd_kind_s _dnssd_ ## NAME ## _kind = { \
+ &_dnssd_ ## SUPER ## _kind, \
+ # NAME, \
+ _dnssd_ ## NAME ## _copy_description, \
+ _dnssd_ ## NAME ## _finalize, \
+ }; \
+ \
+ static DNSSD_TYPE(NAME) \
+ _dnssd_ ## NAME ## _alloc(void) \
+ { \
+ DNSSD_TYPE(NAME) obj = dnssd_object_ ## NAME ## _alloc(sizeof(*obj)); \
+ require_quiet(obj, exit); \
+ \
+ const dnssd_object_t base = (dnssd_object_t)obj; \
+ base->kind = &_dnssd_ ## NAME ## _kind; \
+ \
+ exit: \
+ return obj; \
+ } \
+ DNSSD_BASE_CHECK(NAME, SUPER)
+
+DNSSD_KIND_DECLARE(getaddrinfo);
+DNSSD_KIND_DECLARE(getaddrinfo_result);
+
+typedef char * (*dnssd_copy_description_f)(dnssd_any_t object, bool debug, bool privacy);
+typedef void (*dnssd_finalize_f)(dnssd_any_t object);
+
+typedef const struct dnssd_kind_s * dnssd_kind_t;
+struct dnssd_kind_s {
+ dnssd_kind_t superkind; // This kind's superkind.
+ const char * name; // Name of this kind.
+ dnssd_copy_description_f copy_description; // Creates a textual description of object.
+ dnssd_finalize_f finalize; // Releases object's resources right before the object is freed.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_object Kind Definition
+#endif
+
+struct dnssd_object_s {
+ _OS_OBJECT_HEADER(const void *_os_obj_isa, _os_obj_refcnt, _os_obj_xref_cnt);
+ dnssd_kind_t kind; // Pointer to an object's kind.
+};
+
+static const struct dnssd_kind_s _dnssd_object_kind = {
+ NULL, // No superkind.
+ "object",
+ NULL, // No copy_description method.
+ NULL, // No finalize method.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo Kind Definition
+#endif
+
+typedef enum {
+ dnssd_getaddrinfo_state_nascent = 0,
+ dnssd_getaddrinfo_state_starting = 1,
+ dnssd_getaddrinfo_state_started = 2,
+ dnssd_getaddrinfo_state_failed = 3,
+ dnssd_getaddrinfo_state_invalidated = 4,
+} dnssd_getaddrinfo_state_t;
+
+struct dnssd_getaddrinfo_s {
+ struct dnssd_object_s base; // Object base.
+ dnssd_getaddrinfo_t next; // Next getaddrinfo object in list.
+ uint64_t command_id; // Command ID.
+ dispatch_queue_t user_queue; // User's dispatch queue for invoking result and event handlers.
+ dispatch_queue_t mutex_queue; // Mutex for accessing result_list from different queues.
+ xpc_object_t params; // Parameters dictionary for getaddrinfo command.
+ xpc_object_t hostname; // Reference to hostname from parameters dictionary.
+ dispatch_source_t event_source; // Data source for triggering result and event handlers.
+ dnssd_getaddrinfo_result_t result_list; // List of getaddrinfo results.
+ dnssd_getaddrinfo_result_handler_t result_handler; // User's result handler.
+ dnssd_event_handler_t event_handler; // User's event handler.
+ dnssd_getaddrinfo_state_t state; // Internal state.
+ OSStatus error; // Pending error.
+ bool user_activated; // True if the object has been activated by user.
+};
+
+DNSSD_KIND_DEFINE(getaddrinfo, object);
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo_result Kind Definition
+#endif
+
+struct dnssd_getaddrinfo_result_s {
+ struct dnssd_object_s base; // Object base.
+ sockaddr_ip addr; // IPv4 or IPv6 address of hostname.
+ xpc_object_t hostname; // Requested hostname to resolve.
+ xpc_object_t actual_hostname; // The actual/canonical hostname of the requested hostname.
+ xpc_object_t auth_tag; // Authentication tag.
+ uint32_t interface_index; // Interface index to which the result pertains.
+ dnssd_getaddrinfo_result_type_t type; // Type of getaddrinfo result.
+ dnssd_getaddrinfo_result_t next; // Next getaddrinfo result in list.
+};
+
+DNSSD_KIND_DEFINE(getaddrinfo_result, object);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Constants
+#endif
+
+#define DNSSD_EVENT_HAVE_RESULTS (1U << 0) // Results are available.
+#define DNSSD_EVENT_REMOVE_ALL (1U << 1) // Previously delivered results are no longer valid.
+#define DNSSD_EVENT_ERROR (1U << 2) // An error was encountered.
+
+// Strings for redacted description items.
+
+#define DNSSD_REDACTED_HOSTNAME_STR "<redacted hostname>"
+#define DNSSD_REDACTED_ACTUAL_HOSTNAME_STR "<redacted actual hostname>"
+#define DNSSD_REDACTED_IPv4_ADDRESS_STR "<redacted IPv4 address>"
+#define DNSSD_REDACTED_IPv6_ADDRESS_STR "<redacted IPv6 address>"
+
+#if 0
+//======================================================================================================================
+#pragma mark - Local Prototypes
+#endif
+
+static dispatch_queue_t
+_dnssd_client_queue(void);
+
+static xpc_connection_t
+_dnssd_client_connection(void);
+
+static uint64_t
+_dnssd_client_get_new_id(void);
+
+static void
+_dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static OSStatus
+_dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error);
+
+static void
+_dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t gai, dnssd_getaddrinfo_result_t result_list);
+
+static void
+_dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t gai);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t gai, OSStatus error);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname, xpc_object_t result_dict, OSStatus *out_error);
+
+static DNSServiceErrorType
+_dnssd_osstatus_to_dns_service_error(OSStatus status);
+
+#if !defined(dnssd_release_null_safe)
+ #define dnssd_release_null_safe(X) \
+ do { \
+ if (X) { \
+ dnssd_release(X); \
+ } \
+ } while(0)
+#endif
+
+#if !defined(dnssd_forget)
+ #define dnssd_forget(X) ForgetCustom(X, dnssd_release)
+#endif
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_object Public Methods
+#endif
+
+void
+dnssd_retain(dnssd_any_t object)
+{
+ os_retain(object.base);
+}
+
+//======================================================================================================================
+
+void
+dnssd_release(dnssd_any_t object)
+{
+ os_release(object.base);
+}
+
+//======================================================================================================================
+
+char *
+dnssd_copy_description(dnssd_any_t object)
+{
+ return dnssd_object_copy_description(object, false, false);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_object Private Methods
+#endif
+
+char *
+dnssd_object_copy_description(dnssd_any_t object, bool debug, bool privacy)
+{
+ for (dnssd_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+ if (kind->copy_description) {
+ char *desc = kind->copy_description(object, debug, privacy);
+ return desc;
+ }
+ }
+ return NULL;
+}
+
+//======================================================================================================================
+
+void
+dnssd_object_finalize(dnssd_any_t object)
+{
+ for (dnssd_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+ if (kind->finalize) {
+ kind->finalize(object);
+ }
+ }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo Public Methods
+#endif
+
+dnssd_getaddrinfo_t
+dnssd_getaddrinfo_create(void)
+{
+ dnssd_getaddrinfo_t gai = NULL;
+ dnssd_getaddrinfo_t obj = _dnssd_getaddrinfo_alloc();
+ require_quiet(obj, exit);
+
+ obj->params = xpc_dictionary_create(NULL, NULL, 0);
+ require_quiet(obj->params, exit);
+
+ obj->mutex_queue = dispatch_queue_create("com.apple.dnssd.getaddrinfo.mutex", DISPATCH_QUEUE_SERIAL);
+ require_quiet(obj->mutex_queue, exit);
+
+ gai = obj;
+ obj = NULL;
+
+exit:
+ dnssd_release_null_safe(obj);
+ return gai;
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me, dispatch_queue_t queue)
+{
+ if (!me->user_activated) {
+ dispatch_retain(queue);
+ dispatch_release_null_safe(me->user_queue);
+ me->user_queue = queue;
+ } else if (!me->user_queue) {
+ me->user_queue = queue;
+ dispatch_retain(me->user_queue);
+ _dnssd_client_activate_getaddrinfo_async(me);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me, DNSServiceFlags flags)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_flags(me->params, flags);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me, const char *hostname)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_hostname(me->params, hostname);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me, uint32_t interface_index)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_interface_index(me->params, interface_index);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me, DNSServiceProtocol protocols)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_protocols(me->params, protocols);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me, pid_t pid)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_delegate_pid(me->params, pid);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me, uuid_t uuid)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_delegate_uuid(me->params, uuid);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_handler_t handler)
+{
+ dnssd_getaddrinfo_result_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+ if (me->result_handler) {
+ Block_release(me->result_handler);
+ }
+ me->result_handler = new_handler;
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me, dnssd_event_handler_t handler)
+{
+ dnssd_event_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+ if (me->event_handler) {
+ Block_release(me->event_handler);
+ }
+ me->event_handler = new_handler;
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me, bool need)
+{
+ if (!me->user_activated) {
+ dnssd_xpc_parameters_set_need_authentication_tags(me->params, need);
+ }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
+{
+ if (!me->user_activated) {
+ if (me->user_queue) {
+ _dnssd_client_activate_getaddrinfo_async(me);
+ }
+ me->user_activated = true;
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me);
+
+void
+dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
+{
+ dnssd_retain(me);
+ dispatch_async(_dnssd_client_queue(),
+ ^{
+ _dnssd_client_invalidate_getaddrinfo(me);
+ dnssd_release(me);
+ });
+}
+
+static void
+_dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+ require_quiet(gai->state != dnssd_getaddrinfo_state_invalidated, exit);
+
+ _dnssd_client_deregister_getaddrinfo(gai);
+ if ((gai->state == dnssd_getaddrinfo_state_starting) || (gai->state == dnssd_getaddrinfo_state_started)) {
+ xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
+ if (msg) {
+ dnssd_xpc_message_set_id(msg, gai->command_id);
+ dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_STOP);
+ xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
+ ^(xpc_object_t reply)
+ {
+ (void)reply;
+ });
+ xpc_release(msg);
+ }
+ }
+ _dnssd_getaddrinfo_invalidate(gai);
+ gai->state = dnssd_getaddrinfo_state_invalidated;
+
+exit:
+ return;
+}
+
+static void
+_dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
+{
+ dispatch_source_forget(&me->event_source);
+ _dnssd_getaddrinfo_remove_all_results(me);
+
+ if (me->user_queue) {
+ dnssd_retain(me);
+ dispatch_async(me->user_queue,
+ ^{
+ if (me->event_handler) {
+ me->event_handler(dnssd_event_invalidated, kDNSServiceErr_NoError);
+ }
+ dnssd_release(me);
+ });
+ }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo Private Methods
+#endif
+
+static char *
+_dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me, const bool debug, const bool privacy)
+{
+ const char *hostname;
+ if (me->hostname) {
+ hostname = xpc_string_get_string_ptr(me->hostname);
+ if (privacy && hostname) {
+ hostname = DNSSD_REDACTED_HOSTNAME_STR;
+ }
+ } else {
+ hostname = NULL;
+ }
+
+ char * desc = NULL;
+ char * buf_ptr = NULL;
+ size_t buf_len = 0;
+ for (;;)
+ {
+ size_t need = 0;
+ char * dst = buf_ptr;
+ char * const end = &buf_ptr[buf_len];
+ int n;
+
+ if (debug) {
+ const size_t len = (size_t)(end - dst);
+ n = snprintf(dst, len, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
+ require_quiet(n >= 0, exit);
+
+ if (buf_ptr) {
+ dst = (((size_t)n) < len) ? &dst[n] : end;
+ } else {
+ need += (size_t)n;
+ }
+ }
+ n = snprintf(dst, (size_t)(end - dst), "hostname = %s", hostname ? hostname : "<NO HOSTNAME>");
+ require_quiet(n >= 0, exit);
+
+ if (!buf_ptr) {
+ need += (size_t)n;
+ buf_len = need + 1;
+ buf_ptr = malloc(buf_len);
+ require_quiet(buf_ptr, exit);
+ } else {
+ break;
+ }
+ }
+ desc = buf_ptr;
+ buf_ptr = NULL;
+
+exit:
+ FreeNullSafe(buf_ptr);
+ return desc;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me)
+{
+ dispatch_forget(&me->user_queue);
+ dispatch_forget(&me->mutex_queue);
+ xpc_forget(&me->params);
+ xpc_forget(&me->hostname);
+ BlockForget(&me->result_handler);
+ BlockForget(&me->event_handler);
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_t result_list)
+{
+ dispatch_sync(me->mutex_queue,
+ ^{
+ dnssd_getaddrinfo_result_t *ptr = &me->result_list;
+ while (*ptr) {
+ ptr = &(*ptr)->next;
+ }
+ *ptr = result_list;
+ });
+ dispatch_source_merge_data(me->event_source, DNSSD_EVENT_HAVE_RESULTS);
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me)
+{
+ dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
+ if (me->event_source) {
+ dispatch_source_merge_data(me->event_source, DNSSD_EVENT_REMOVE_ALL);
+ }
+
+ dnssd_getaddrinfo_result_t result;
+ while ((result = result_list) != NULL) {
+ result_list = result->next;
+ dnssd_release(result);
+ }
+}
+
+//======================================================================================================================
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me)
+{
+ __block dnssd_getaddrinfo_result_t list;
+ dispatch_sync(me->mutex_queue,
+ ^{
+ list = me->result_list;
+ me->result_list = NULL;
+ });
+ return list;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me, OSStatus error)
+{
+ dispatch_sync(me->mutex_queue,
+ ^{
+ me->error = error;
+ });
+ dispatch_source_merge_data(me->event_source, DNSSD_EVENT_ERROR);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo_result Public Methods
+#endif
+
+dnssd_getaddrinfo_result_type_t
+dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me)
+{
+ return me->type;
+}
+
+//======================================================================================================================
+
+const char *
+dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me)
+{
+ return xpc_string_get_string_ptr(me->actual_hostname);
+}
+
+//======================================================================================================================
+
+const struct sockaddr *
+dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me)
+{
+ return &me->addr.sa;
+}
+
+//======================================================================================================================
+
+const char *
+dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me)
+{
+ return xpc_string_get_string_ptr(me->hostname);
+}
+
+//======================================================================================================================
+
+uint32_t
+dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me)
+{
+ return me->interface_index;
+}
+
+//======================================================================================================================
+
+const void *
+dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me, size_t *out_length)
+{
+ const void * auth_tag_ptr;
+ size_t auth_tag_len;
+
+ if (me->auth_tag) {
+ auth_tag_ptr = xpc_data_get_bytes_ptr(me->auth_tag);
+ auth_tag_len = xpc_data_get_length(me->auth_tag);
+ } else {
+ auth_tag_ptr = NULL;
+ auth_tag_len = 0;
+ }
+ if (out_length) {
+ *out_length = auth_tag_len;
+ }
+ return auth_tag_ptr;
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo_result Private Methods
+#endif
+
+static char *
+_dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me, const bool debug, const bool privacy)
+{
+ const char *hostname;
+ if (me->hostname) {
+ hostname = xpc_string_get_string_ptr(me->hostname);
+ if (privacy && hostname) {
+ hostname = DNSSD_REDACTED_HOSTNAME_STR;
+ }
+ } else {
+ hostname = NULL;
+ }
+
+ const char *actual_hostname;
+ if (me->actual_hostname) {
+ actual_hostname = xpc_string_get_string_ptr(me->actual_hostname);
+ if (privacy && actual_hostname) {
+ actual_hostname = DNSSD_REDACTED_ACTUAL_HOSTNAME_STR;
+ }
+ } else {
+ actual_hostname = NULL;
+ }
+ char addr_buf[INET6_ADDRSTRLEN];
+ check_compile_time_code(sizeof(addr_buf) >= INET_ADDRSTRLEN);
+ check_compile_time_code(sizeof(addr_buf) >= INET6_ADDRSTRLEN);
+
+ const char *addr;
+ if (me->addr.sa.sa_family == AF_INET) {
+ if (privacy) {
+ addr = DNSSD_REDACTED_IPv4_ADDRESS_STR;
+ } else {
+ addr = inet_ntop(AF_INET, &me->addr.v4.sin_addr.s_addr, addr_buf, (socklen_t)sizeof(addr_buf));
+ }
+ } else if (me->addr.sa.sa_family == AF_INET6) {
+ if (privacy) {
+ addr = DNSSD_REDACTED_IPv6_ADDRESS_STR;
+ } else {
+ addr = inet_ntop(AF_INET6, me->addr.v6.sin6_addr.s6_addr, addr_buf, (socklen_t)sizeof(addr_buf));
+ }
+ } else {
+ addr = NULL;
+ }
+
+ char * desc = NULL;
+ char * buf_ptr = NULL;
+ size_t buf_len = 0;
+ for (;;)
+ {
+ char * dst = buf_ptr;
+ char * const end = &buf_ptr[buf_len];
+ size_t need = 0;
+ int n;
+
+ if (debug) {
+ const size_t len = (size_t)(end - dst);
+ n = snprintf(dst, len, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
+ require_quiet(n >= 0, exit);
+
+ if (buf_ptr) {
+ dst = (((size_t)n) < len) ? &dst[n] : end;
+ } else {
+ need += (size_t)n;
+ }
+ }
+ n = snprintf(dst, (size_t)(end - dst), "[%s] %s (%s) -> %s (interface index %lu)",
+ dnssd_getaddrinfo_result_type_to_string(me->type), hostname ? hostname : "<NO HOSTNAME>",
+ actual_hostname ? actual_hostname : "<NO ACTUAL HOSTNAME>", addr ? addr : "<NO IP ADDRESS>",
+ (unsigned long)me->interface_index);
+ require_quiet(n >= 0, exit);
+
+ if (!buf_ptr) {
+ need += (size_t)n;
+ buf_len = need + 1;
+ buf_ptr = malloc(buf_len);
+ require_quiet(buf_ptr, exit);
+ } else {
+ break;
+ }
+ }
+ desc = buf_ptr;
+ buf_ptr = NULL;
+
+exit:
+ FreeNullSafe(buf_ptr);
+ return desc;
+}
+
+//======================================================================================================================
+
+void
+_dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me)
+{
+ xpc_forget(&me->hostname);
+ xpc_forget(&me->actual_hostname);
+ xpc_forget(&me->auth_tag);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd Client
+#endif
+
+static dnssd_getaddrinfo_t g_gai_list = NULL;
+
+static dispatch_queue_t
+_dnssd_client_queue(void)
+{
+ static dispatch_once_t once = 0;
+ static dispatch_queue_t queue = NULL;
+
+ dispatch_once(&once,
+ ^{
+ dispatch_queue_attr_t const attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
+ QOS_CLASS_UTILITY, 0);
+ queue = dispatch_queue_create("com.apple.dnssd.client", attr);
+ });
+ return queue;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_handle_message(xpc_object_t msg);
+static void
+_dnssd_client_handle_interruption(void);
+
+static xpc_connection_t
+_dnssd_client_connection(void)
+{
+ static dispatch_once_t once = 0;
+ static xpc_connection_t connection = NULL;
+
+ dispatch_once(&once,
+ ^{
+ connection = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dnssd_client_queue(),
+ XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+ xpc_connection_set_event_handler(connection,
+ ^(xpc_object_t event)
+ {
+ if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
+ _dnssd_client_handle_message(event);
+ } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
+ _dnssd_client_handle_interruption();
+ }
+ });
+ xpc_connection_activate(connection);
+ });
+ return connection;
+}
+
+static void
+_dnssd_client_handle_message(xpc_object_t msg)
+{
+ const uint64_t command_id = dnssd_xpc_message_get_id(msg, NULL);
+ dnssd_getaddrinfo_t gai;
+ for (gai = g_gai_list; gai; gai = gai->next) {
+ if (gai->command_id == command_id) {
+ break;
+ }
+ }
+ require_quiet(gai, exit);
+
+ const OSStatus error = dnssd_xpc_message_get_error(msg, NULL);
+ if (!error) {
+ xpc_object_t const result_array = dnssd_xpc_message_get_results(msg);
+ require_quiet(result_array, exit);
+
+ dnssd_getaddrinfo_result_t result_list = NULL;
+ __block dnssd_getaddrinfo_result_t * result_ptr = &result_list;
+ xpc_array_apply(result_array,
+ ^bool(__unused size_t index, xpc_object_t result_dict)
+ {
+ dnssd_getaddrinfo_result_t result = _dnssd_getaddrinfo_result_create_from_dictionary(gai->hostname,
+ result_dict, NULL);
+ if (result) {
+ *result_ptr = result;
+ result_ptr = &result->next;
+ }
+ return true;
+ });
+ require_quiet(result_list, exit);
+
+ _dnssd_getaddrinfo_append_results(gai, result_list);
+ result_list = NULL;
+ } else {
+ _dnssd_client_fail_getaddrinfo(gai, error);
+ }
+
+exit:
+ return;
+}
+
+static void
+_dnssd_client_handle_interruption(void)
+{
+ dnssd_getaddrinfo_t next_gai;
+ for (dnssd_getaddrinfo_t gai = g_gai_list; gai; gai = next_gai) {
+ next_gai = gai->next;
+ gai->state = dnssd_getaddrinfo_state_starting;
+ const OSStatus err = _dnssd_client_send_getaddrinfo_command(gai);
+ if (!err) {
+ _dnssd_getaddrinfo_remove_all_results(gai);
+ } else {
+ _dnssd_client_fail_getaddrinfo(gai, err);
+ }
+ }
+}
+
+//======================================================================================================================
+
+static uint64_t
+_dnssd_client_get_new_id(void)
+{
+ static uint64_t last_id = 0;
+ return ++last_id;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static OSStatus
+_dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai)
+{
+ dnssd_retain(gai);
+ dispatch_async(_dnssd_client_queue(),
+ ^{
+ _dnssd_client_activate_getaddrinfo(gai);
+ dnssd_release(gai);
+ });
+}
+
+static void
+_dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+ OSStatus err;
+ require_action_quiet(gai->state == dnssd_getaddrinfo_state_nascent, exit, err = kNoErr);
+
+ err = _dnssd_getaddrinfo_activate(gai);
+ if (err) {
+ gai->state = dnssd_getaddrinfo_state_failed;
+ goto exit;
+ }
+
+ gai->command_id = _dnssd_client_get_new_id();
+ gai->state = dnssd_getaddrinfo_state_starting;
+
+ _dnssd_client_register_getaddrinfo(gai);
+
+ err = _dnssd_client_send_getaddrinfo_command(gai);
+ if (err) {
+ _dnssd_client_fail_getaddrinfo(gai, err);
+ }
+
+exit:
+ return;
+}
+
+static void
+_dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t gai, unsigned long events);
+
+static OSStatus
+_dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
+{
+ OSStatus err;
+ xpc_object_t const hostname = dnssd_xpc_parameters_get_hostname_object(me->params);
+ require_action_quiet(hostname, exit, err = kParamErr);
+
+ me->hostname = xpc_copy(hostname);
+ require_action_quiet(me->hostname, exit, err = kNoResourcesErr);
+
+ me->event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, me->user_queue);
+ require_action_quiet(me->event_source, exit, err = kNoResourcesErr);
+
+ dnssd_retain(me);
+ dispatch_source_t const event_source = me->event_source;
+ dispatch_source_set_event_handler(me->event_source,
+ ^{
+ _dnssd_getaddrinfo_process_events(me, dispatch_source_get_data(event_source));
+ });
+ dispatch_source_set_cancel_handler(me->event_source,
+ ^{
+ dnssd_release(me);
+ });
+ dispatch_activate(me->event_source);
+ err = kNoErr;
+
+exit:
+ if (err) {
+ dnssd_retain(me);
+ dispatch_async(me->user_queue,
+ ^{
+ if (me->event_handler) {
+ me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(err));
+ }
+ dnssd_release(me);
+ });
+ }
+ return err;
+}
+
+static void
+_dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me, unsigned long events)
+{
+ if (events & DNSSD_EVENT_REMOVE_ALL) {
+ if (me->event_handler) {
+ me->event_handler(dnssd_event_remove_all, kDNSServiceErr_NoError);
+ }
+ }
+
+ if (events & DNSSD_EVENT_HAVE_RESULTS) {
+ dnssd_getaddrinfo_result_t result;
+ dnssd_getaddrinfo_result_t result_array[32];
+ dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
+
+ size_t result_count = 0;
+ while ((result = result_list) != NULL) {
+ result_list = result->next;
+ result->next = NULL;
+ result_array[result_count++] = result;
+
+ if ((result_count == countof(result_array)) || !result_list) {
+ if (me->result_handler) {
+ me->result_handler(result_array, result_count);
+ }
+ for (size_t i = 0; i < result_count; ++i) {
+ dnssd_release(result_array[i]);
+ }
+ result_count = 0;
+ }
+ }
+ }
+
+ if (events & DNSSD_EVENT_ERROR) {
+ __block OSStatus error;
+ dispatch_sync(me->mutex_queue,
+ ^{
+ error = me->error;
+ me->error = kNoErr;
+ });
+ if (me->event_handler && error) {
+ me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(error));
+ }
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+ gai->next = g_gai_list;
+ g_gai_list = gai;
+ dnssd_retain(gai);
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+ dnssd_getaddrinfo_t *ptr;
+ for (ptr = &g_gai_list; *ptr; ptr = &(*ptr)->next)
+ {
+ if (*ptr == gai) {
+ break;
+ }
+ }
+ if (*ptr) {
+ *ptr = gai->next;
+ gai->next = NULL;
+ dnssd_release(gai);
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply);
+
+static OSStatus
+_dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai)
+{
+ OSStatus err;
+ xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
+ require_action_quiet(msg, exit, err = kNoResourcesErr);
+
+ dnssd_xpc_message_set_id(msg, gai->command_id);
+ dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_GETADDRINFO);
+ dnssd_xpc_message_set_parameters(msg, gai->params);
+
+ dnssd_retain(gai);
+ xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
+ ^(xpc_object_t reply)
+ {
+ _dnssd_client_handle_getaddrinfo_reply(gai, reply);
+ dnssd_release(gai);
+ });
+ xpc_release(msg);
+ err = kNoErr;
+
+exit:
+ return err;
+}
+
+static void
+_dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply)
+{
+ require_quiet(gai->state == dnssd_getaddrinfo_state_starting, exit);
+
+ if (xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
+ const OSStatus error = dnssd_xpc_message_get_error(reply, NULL);
+ if (error) {
+ _dnssd_client_fail_getaddrinfo(gai, error);
+ } else {
+ gai->state = dnssd_getaddrinfo_state_started;
+ }
+ } else if (reply != XPC_ERROR_CONNECTION_INTERRUPTED) {
+ OSStatus error;
+ if (reply == XPC_ERROR_CONNECTION_INVALID) {
+ error = kDNSServiceErr_ServiceNotRunning;
+ } else {
+ error = kDNSServiceErr_Unknown;
+ }
+ _dnssd_client_fail_getaddrinfo(gai, error);
+ }
+
+exit:
+ return;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error)
+{
+ _dnssd_client_deregister_getaddrinfo(gai);
+ gai->state = dnssd_getaddrinfo_state_failed;
+ _dnssd_getaddrinfo_post_error_event(gai, error);
+}
+
+//======================================================================================================================
+// _dnssd_getaddrinfo_result_create_from_dictionary
+//======================================================================================================================
+
+static bool
+_dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
+ DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
+ xpc_object_t *out_rdata, xpc_object_t *out_auth_tag);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
+ xpc_object_t actual_hostname, int addr_family, const void *addr_data, uint32_t interface_index,
+ xpc_object_t auth_tag, OSStatus *out_error);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname, xpc_object_t result_dict, OSStatus *out_error)
+{
+ OSStatus err;
+ xpc_object_t actual_hostname, rdata, auth_tag;
+ DNSServiceErrorType error;
+ DNSServiceFlags flags;
+ uint32_t interface_index;
+ uint16_t rtype;
+ dnssd_getaddrinfo_result_t result = NULL;
+
+ const bool success = _dnssd_extract_result_dict_values(result_dict, &actual_hostname, &error, &flags,
+ &interface_index, &rtype, NULL, &rdata, &auth_tag);
+ require_action_quiet(success, exit, err = kMalformedErr);
+
+ if ((error != kDNSServiceErr_NoError) &&
+ (error != kDNSServiceErr_NoSuchRecord)) {
+ err = kUnexpectedErr;
+ goto exit;
+ }
+ require_action_quiet((rtype == kDNSServiceType_A) || (rtype == kDNSServiceType_AAAA), exit, err = kTypeErr);
+
+ dnssd_getaddrinfo_result_type_t result_type;
+ if (error == kDNSServiceErr_NoSuchRecord) {
+ result_type = dnssd_getaddrinfo_result_type_no_address;
+ } else {
+ if (flags & kDNSServiceFlagsAdd) {
+ if (flags & kDNSServiceFlagsExpiredAnswer) {
+ result_type = dnssd_getaddrinfo_result_type_expired;
+ } else {
+ result_type = dnssd_getaddrinfo_result_type_add;
+ }
+ } else {
+ result_type = dnssd_getaddrinfo_result_type_remove;
+ }
+ if (rtype == kDNSServiceType_A) {
+ require_action_quiet(xpc_data_get_length(rdata) == 4, exit, err = kMalformedErr);
+ } else {
+ require_action_quiet(xpc_data_get_length(rdata) == 16, exit, err = kMalformedErr);
+ }
+ }
+ const int addr_family = (rtype == kDNSServiceType_A) ? AF_INET : AF_INET6;
+ result = _dnssd_getaddrinfo_result_create(result_type, hostname, actual_hostname, addr_family,
+ xpc_data_get_bytes_ptr(rdata), interface_index, auth_tag, &err);
+ require_noerr_quiet(err, exit);
+
+exit:
+ if (err) {
+ dnssd_forget(&result);
+ }
+ if (out_error) {
+ *out_error = err;
+ }
+ return result;
+}
+
+static bool
+_dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
+ DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
+ xpc_object_t *out_rdata, xpc_object_t *out_auth_tag)
+{
+ bool result_is_valid = false;
+ xpc_object_t const hostname = dnssd_xpc_result_get_record_name_object(result);
+ require_quiet(hostname, exit);
+
+ xpc_object_t const rdata = dnssd_xpc_result_get_record_data_object(result);
+ require_quiet(rdata, exit);
+
+ if (out_hostname) {
+ *out_hostname = hostname;
+ }
+ if (out_error) {
+ *out_error = dnssd_xpc_result_get_error(result, NULL);
+ }
+ if (out_flags) {
+ *out_flags = dnssd_xpc_result_get_flags(result, NULL);
+ }
+ if (out_interface_index) {
+ *out_interface_index = dnssd_xpc_result_get_interface_index(result, NULL);
+ }
+ if (out_type) {
+ *out_type = dnssd_xpc_result_get_record_type(result, NULL);
+ }
+ if (out_class) {
+ *out_class = dnssd_xpc_result_get_record_class(result, NULL);
+ }
+ if (out_rdata) {
+ *out_rdata = rdata;
+ }
+ if (out_auth_tag) {
+ *out_auth_tag = dnssd_xpc_result_get_authentication_tag_object(result);
+ }
+ result_is_valid = true;
+
+exit:
+ return result_is_valid;
+}
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
+ xpc_object_t actual_hostname, int addr_family, const void *addr_data, uint32_t interface_index,
+ xpc_object_t auth_tag, OSStatus *out_error)
+{
+ OSStatus err;
+ dnssd_getaddrinfo_result_t result = NULL;
+ dnssd_getaddrinfo_result_t obj = _dnssd_getaddrinfo_result_alloc();
+ require_action_quiet(obj, exit, err = kNoMemoryErr);
+
+ switch (type) {
+ case dnssd_getaddrinfo_result_type_add:
+ case dnssd_getaddrinfo_result_type_remove:
+ case dnssd_getaddrinfo_result_type_no_address:
+ case dnssd_getaddrinfo_result_type_expired:
+ break;
+
+ default:
+ err = kTypeErr;
+ goto exit;
+ }
+ obj->type = type;
+ obj->interface_index = interface_index;
+
+ require_action_quiet(xpc_get_type(hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
+
+ obj->hostname = xpc_copy(hostname);
+ require_action_quiet(obj->hostname, exit, err = kNoResourcesErr);
+
+ require_action_quiet(xpc_get_type(actual_hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
+
+ obj->actual_hostname = xpc_copy(actual_hostname);
+ require_action_quiet(obj->actual_hostname, exit, err = kNoResourcesErr);
+
+ require_action_quiet((addr_family == AF_INET) || (addr_family == AF_INET6), exit, err = kTypeErr);
+
+ if (addr_family == AF_INET) {
+ obj->addr.sa.sa_family = AF_INET;
+ obj->addr.v4.sin_len = sizeof(struct sockaddr_in);
+ if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
+ memcpy(&obj->addr.v4.sin_addr.s_addr, addr_data, 4);
+ }
+ } else {
+ obj->addr.sa.sa_family = AF_INET6;
+ obj->addr.v6.sin6_len = sizeof(struct sockaddr_in6);
+ if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
+ memcpy(&obj->addr.v6.sin6_addr.s6_addr, addr_data, 16);
+ }
+ }
+
+ if (auth_tag) {
+ require_action_quiet(xpc_get_type(auth_tag) == XPC_TYPE_DATA, exit, err = kTypeErr);
+
+ obj->auth_tag = xpc_copy(auth_tag);
+ require_action_quiet(obj->auth_tag, exit, err = kNoResourcesErr);
+ }
+ result = obj;
+ obj = NULL;
+ err = kNoErr;
+
+exit:
+ if (out_error) {
+ *out_error = err;
+ }
+ dnssd_release_null_safe(obj);
+ return result;
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Misc. Helpers
+#endif
+
+static DNSServiceErrorType
+_dnssd_osstatus_to_dns_service_error(OSStatus error)
+{
+ switch (error) {
+ case kNoMemoryErr:
+ case kNoResourcesErr:
+ error = kDNSServiceErr_NoMemory;
+ break;
+
+ case kParamErr:
+ error = kDNSServiceErr_BadParam;
+ break;
+
+ default:
+ if ((error >= kGenericErrorBase) && (error <= kGenericErrorEnd)) {
+ error = kDNSServiceErr_Unknown;
+ }
+ break;
+ }
+ return error;
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DNSSD_OBJECT_H__
+#define __DNSSD_OBJECT_H__
+
+#include "dnssd_private.h"
+
+//======================================================================================================================
+#pragma mark - dnssd_object Private Method Declarations
+
+char *
+dnssd_object_copy_description(dnssd_any_t object, bool debug, bool privacy);
+
+void
+dnssd_object_finalize(dnssd_any_t object);
+
+#define DNSSD_OBJECT_ALLOC_DECLARE(NAME) \
+ dnssd_ ## NAME ## _t \
+ dnssd_object_ ## NAME ## _alloc(size_t size)
+
+DNSSD_OBJECT_ALLOC_DECLARE(getaddrinfo);
+DNSSD_OBJECT_ALLOC_DECLARE(getaddrinfo_result);
+
+#endif // __DNSSD_OBJECT_H__
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "dnssd_object.h"
+
+#import <stdlib.h>
+#import <Foundation/Foundation.h>
+#import <os/object_private.h>
+
+#if 0
+//======================================================================================================================
+#pragma mark - Class Declarations
+#endif
+
+#define DNSSD_OBJECT_CLASS_DECLARE(NAME) \
+ _OS_OBJECT_DECL_SUBCLASS_INTERFACE(dnssd_ ## NAME, dnssd_object) \
+ extern int _dnssd_dummy_variable
+
+_OS_OBJECT_DECL_SUBCLASS_INTERFACE(dnssd_object, object)
+
+DNSSD_OBJECT_CLASS_DECLARE(getaddrinfo);
+DNSSD_OBJECT_CLASS_DECLARE(getaddrinfo_result);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Class Definitions
+#endif
+
+@implementation OS_OBJECT_CLASS(dnssd_object)
+- (void)dealloc
+{
+ dnssd_object_finalize(self);
+ [super dealloc];
+}
+
+- (NSString *)description
+{
+ char * const desc = dnssd_object_copy_description(self, false, false);
+ if (desc) {
+ NSString * const string = [NSString stringWithUTF8String:desc];
+ free(desc);
+ return string;
+ } else {
+ return nil;
+ }
+}
+
+- (NSString *)debugDescription
+{
+ char * const desc = dnssd_object_copy_description(self, true, false);
+ if (desc) {
+ NSString * const string = [NSString stringWithUTF8String:desc];
+ free(desc);
+ return string;
+ } else {
+ return nil;
+ }
+}
+
+- (NSString *)redactedDescription
+{
+ char * const desc = dnssd_object_copy_description(self, false, true);
+ if (desc) {
+ NSString * const string = [NSString stringWithUTF8String:desc];
+ free(desc);
+ return string;
+ } else {
+ return nil;
+ }
+}
+@end
+
+#define DNSSD_CLASS(NAME) OS_OBJECT_CLASS(dnssd_ ## NAME)
+#define DNSSD_OBJECT_CLASS_DEFINE(NAME) \
+ @implementation DNSSD_CLASS(NAME) \
+ @end \
+ \
+ dnssd_ ## NAME ## _t \
+ dnssd_object_ ## NAME ## _alloc(const size_t size) \
+ { \
+ return (dnssd_## NAME ##_t)_os_object_alloc([DNSSD_CLASS(NAME) class], size); \
+ } \
+ extern int _dnssd_dummy_variable
+
+DNSSD_OBJECT_CLASS_DEFINE(getaddrinfo);
+DNSSD_OBJECT_CLASS_DEFINE(getaddrinfo_result);
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DNSSD_PRIVATE_H__
+#define __DNSSD_PRIVATE_H__
+
+#include <dispatch/dispatch.h>
+#include <dns_sd.h>
+#include <os/object.h>
+
+#if OS_OBJECT_USE_OBJC
+ #define DNSSD_DECL(NAME) OS_OBJECT_DECL_SUBCLASS(dnssd_ ## NAME, dnssd_object)
+ #define DNSSD_RETURNS_RETAINED OS_OBJECT_RETURNS_RETAINED
+
+ OS_OBJECT_DECL(dnssd_object,);
+#else
+ #define DNSSD_DECL(NAME) typedef struct dnssd_ ## NAME ## _s * dnssd_ ## NAME ## _t
+ #define DNSSD_RETURNS_RETAINED
+
+ DNSSD_DECL(object);
+#endif
+
+#define DNSSD_ASSUME_NONNULL_BEGIN OS_ASSUME_NONNULL_BEGIN
+#define DNSSD_ASSUME_NONNULL_END OS_ASSUME_NONNULL_END
+
+DNSSD_DECL(getaddrinfo);
+DNSSD_DECL(getaddrinfo_result);
+
+DNSSD_ASSUME_NONNULL_BEGIN
+
+#if OS_OBJECT_USE_OBJC
+ typedef dnssd_object_t dnssd_any_t;
+#else
+ #if !defined(__cplusplus)
+ typedef union {
+ dnssd_object_t base;
+ dnssd_getaddrinfo_t gai;
+ dnssd_getaddrinfo_result_t gai_result;
+ } dnssd_any_t __attribute__((__transparent_union__));
+ #else
+ typedef void * dnssd_any_t;
+ #endif
+#endif
+
+#define DNSSD_MALLOC __attribute__((__malloc__))
+#define DNSSD_AVAILABLE SPI_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
+
+__BEGIN_DECLS
+
+/*!
+ * @brief
+ * Increments the reference count of a dnssd object.
+ *
+ * @param object
+ * The dnssd object.
+ *
+ * @discussion
+ * Calls to dnssd_retain() must be balanced with calls to dnssd_release().
+ */
+DNSSD_AVAILABLE
+void
+dnssd_retain(dnssd_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+#undef dnssd_retain
+#define dnssd_retain(object) [(object) retain]
+#endif
+
+/*!
+ * @brief
+ * Decrements the reference count of a dnssd object.
+ *
+ * @param object
+ * The dnssd object.
+ *
+ * @discussion
+ * Calls to dnssd_retain() must be balanced with calls to dnssd_release().
+ */
+DNSSD_AVAILABLE
+void
+dnssd_release(dnssd_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+#undef dnssd_release
+#define dnssd_release(object) [(object) release]
+#endif
+
+
+/*!
+ * @brief
+ * Provides a textual description of a dnssd object.
+ *
+ * @param object
+ * The dnssd object.
+ *
+ * @result
+ * Textual description of the object as a C string.
+ *
+ * @discussion
+ * The string returned by this function must be released with <code>free(3)</code>.
+ */
+DNSSD_AVAILABLE
+DNSSD_MALLOC char * _Nullable
+dnssd_copy_description(dnssd_any_t object);
+
+/*!
+ * @brief
+ * Creates a getaddrinfo object.
+ *
+ * @result
+ * A new getaddrinfo object.
+ *
+ * @discussion
+ * A getaddrinfo object resolves a hostname to its IPv4 and IPv6 addresses.
+ */
+DNSSD_AVAILABLE
+DNSSD_RETURNS_RETAINED dnssd_getaddrinfo_t _Nullable
+dnssd_getaddrinfo_create(void);
+
+/*!
+ * @brief
+ * Specifies the queue on which to invoke the getaddrinfo object's result and event blocks.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param queue
+ * A serial queue.
+ *
+ * @discussion
+ * This call must be made before activating the getaddrinfo object.
+ *
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t gai, dispatch_queue_t queue);
+
+/*!
+ * @brief
+ * Specifies the DNSServiceFlags to use for the getaddrinfo operation.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param flags
+ * Flags.
+ *
+ * @discussion
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t gai, DNSServiceFlags flags);
+
+/*!
+ * @brief
+ * Specifies the hostname to resolve.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param hostname
+ * Hostname as a fully-qualified domain name.
+ *
+ * @discussion
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t gai, const char *hostname);
+
+/*!
+ * @brief
+ * Specifies the index of the interface via which to resolve the hostname.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param interface_index
+ * Interface index.
+ *
+ * @discussion
+ * If <code>kDNSServiceInterfaceIndexAny</code> is used as the interface index, then special behavior applies. If
+ * the hostname is in the "local." domain, then an attempt will be made to resolve the hostname via all active
+ * mDNS-capable interfaces. If the hostname is in any other domain, then the hostname will be resolved via the
+ * primary interface.
+ *
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t gai, uint32_t interface_index);
+
+/*!
+ * @brief
+ * Specifies the types of addresses to which to resolve the hostname.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param protocols
+ * Protocols.
+ *
+ * @discussion
+ * Set <code>protocols</code> to <code>kDNSServiceProtocol_IPv4</code> to resolve the hostname to IPv4 addresses.
+ *
+ * Set <code>protocols</code> to <code>kDNSServiceProtocol_IPv6</code> to resolve the hostname to IPv6 addresses.
+ *
+ * Set <code>protocols</code> to <code>kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6</code> to resolve the
+ * hostname to both IPv4 and IPv6 addresses.
+ *
+ * Set <code>protocols</code> to 0 to limit resolution to addresses of protocols of which the host has routable
+ * addresses. That is, an attempt will be made to resolve the hostname to IPv4 addresses if and only if the host
+ * has a routable IPv4 address. Likewise, an attempt will be made to resolve the hostname to IPv6 addresses if and
+ * only if the host has a routable IPv6 address.
+ *
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t gai, DNSServiceProtocol protocols);
+
+/*!
+ * @brief
+ * Sets the process ID (PID) of the process on whose behalf the getaddrinfo operation is being performed.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param pid
+ * PID of the process being represented.
+ *
+ * @discussion
+ * If a delegate PID is set, then the calling process must have the proper entitlement in order for the
+ * getaddrinfo operation to not fail with a kDNSServiceErr_NotAuth error.
+ *
+ * This function is an alternative to <code>dnssd_getaddrinfo_set_delegate_uuid()</code>.
+ *
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t gai, pid_t pid);
+
+/*!
+ * @brief
+ * Sets the UUID of the process on whose behalf the getaddrinfo operation is being performed.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param uuid
+ * UUID of the process being represented.
+ *
+ * @discussion
+ * If a delegate UUID is set, then the calling process must have the proper entitlement in order for the
+ * getaddrinfo operation to not fail with the <code>kDNSServiceErr_NotAuth</code> error.
+ *
+ * This function is an alternative to <code>dnssd_getaddrinfo_set_delegate_pid()</code>.
+ *
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t gai, uuid_t _Nonnull uuid);
+
+/*!
+ * @brief
+ * Specifies whether or not getaddrinfo results (of types <code>dnssd_getaddrinfo_result_type_add</code> and
+ * <code>dnssd_getaddrinfo_result_type_expired</code>) should include authentication tags from the stub resolver.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param need
+ * Pass <code>true</code> if authenticated results are needed, otherwise, pass <code>false</code>.
+ *
+ * @discussion
+ * This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t gai, bool need);
+
+/*!
+ * @brief
+ * Activates a getaddrinfo object.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @discussion
+ * This function has no effect on a getaddrinfo object that has already been activated or has been invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai);
+
+/*!
+ * @brief
+ * Asynchronously invalidates a getaddrinfo object.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @discussion
+ * As a result of calling this function, the getaddrinfo object's event handler will be invoked with a
+ * <code>dnssd_event_invalidated</code> event. After this, the object's event and result handlers will never be
+ * invoked again.
+ *
+ * This function has no effect on a getaddrinfo object that has already been invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t gai);
+
+/*!
+ * @brief
+ * Handler for getaddrinfo results.
+ *
+ * @param result_array
+ * C array of getaddrinfo results.
+ *
+ * @param result_count
+ * Size of the array in terms of number of results.
+ */
+typedef void (^dnssd_getaddrinfo_result_handler_t)(dnssd_getaddrinfo_result_t _Nonnull * _Nonnull result_array,
+ size_t result_count);
+
+/*!
+ * @brief
+ * Specifies a getaddrinfo object's result handler.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param handler
+ * Result handler.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t gai, dnssd_getaddrinfo_result_handler_t _Nullable handler);
+
+/*!
+ * @brief
+ * Events that can occur during the lifetime of a getaddrinfo object.
+ */
+typedef enum {
+ /*! @const dnssd_event_error An error occurred. */
+ dnssd_event_error = 1,
+ /*! @const dnssd_event_remove_all All results prior to this event are no longer valid. */
+ dnssd_event_remove_all = 2,
+ /*! @const dnssd_event_invalidated The object has been invalidated. */
+ dnssd_event_invalidated = 3,
+} dnssd_event_t;
+
+/*!
+ * @brief
+ * Handler for getaddrinfo events.
+ *
+ * @param event
+ * Event.
+ *
+ * @param error
+ * The error associated with a <code>dnssd_event_error</code> event. Ignore for all other types of events.
+ *
+ * @discussion
+ * After a <code>dnssd_event_invalidated</code> event, a getaddrinfo object's result and event handlers will never
+ * be invoked again.
+ */
+typedef void (^dnssd_event_handler_t)(dnssd_event_t event, DNSServiceErrorType error);
+
+/*!
+ * @brief
+ * Sets a getaddrinfo object's event handler.
+ *
+ * @param gai
+ * The getaddrinfo object.
+ *
+ * @param handler
+ * Event handler.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t gai, dnssd_event_handler_t _Nullable handler);
+
+/*!
+ * @brief
+ * Types of getaddrinfo results.
+ */
+typedef enum {
+ /*! @const dnssd_getaddrinfo_result_type_add The contained hostname and address pair is valid. */
+ dnssd_getaddrinfo_result_type_add = 1,
+ /*! @const dnssd_getaddrinfo_result_type_remove The contained hostname and address pair is no longer valid. */
+ dnssd_getaddrinfo_result_type_remove = 2,
+ /*! @const dnssd_getaddrinfo_result_type_no_address The contained hostname has no address of a particular type. */
+ dnssd_getaddrinfo_result_type_no_address = 3,
+ /*! @const dnssd_getaddrinfo_result_type_expired A hostname and address pair contained came from an expired cached record and may no longer be valid. */
+ dnssd_getaddrinfo_result_type_expired = 4,
+} dnssd_getaddrinfo_result_type_t;
+
+/*!
+ * @brief
+ * Gets a getaddrinfo result's type.
+ *
+ * @param gai_result
+ * The getaddrinfo result.
+ *
+ * @result
+ * Result type.
+ */
+DNSSD_AVAILABLE
+dnssd_getaddrinfo_result_type_t
+dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ * @brief
+ * Gets a getaddrinfo result's actual hostname.
+ *
+ * @param gai_result
+ * The getaddrinfo result.
+ *
+ * @result
+ * The getaddrinfo result's actual hostname.
+ *
+ * @discussion
+ * The hostname returned by this function is the canonical name of the hostname that was requested. In other
+ * words, it's the canonical name of the hostname set with <code>dnssd_getaddrinfo_set_hostname()</code>.
+ *
+ * The pointer returned by this function is valid until the getaddrinfo result is released.
+ */
+DNSSD_AVAILABLE
+const char *
+dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ * @brief
+ * Gets a getaddrinfo result's address.
+ *
+ * @param gai_result
+ * The getaddrinfo result.
+ *
+ * @result
+ * The getaddrinfo result's address as a sockaddr structure.
+ *
+ * @discussion
+ * For getaddrinfo results of type <code>dnssd_getaddrinfo_result_type_no_address</code>, the sockaddr structure's
+ * sa_family member variable can be used to determine the type of address that the hostname lacks.
+ */
+DNSSD_AVAILABLE
+const struct sockaddr *
+dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ * @brief
+ * Gets a getaddrinfo result's hostname.
+ *
+ * @param gai_result
+ * The getaddrinfo result.
+ *
+ * @result
+ * The getaddrinfo result's hostname.
+ *
+ * @discussion
+ * The hostname returned by this function is the hostname whose resolution was requested. In other words, it's
+ * equal to the hostname set with <code>dnssd_getaddrinfo_set_hostname()</code>.
+ *
+ * The pointer returned by this function is valid until the getaddrinfo result is released.
+ */
+DNSSD_AVAILABLE
+const char *
+dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ * @brief
+ * Gets the interface index to which a getaddrinfo result pertains.
+ *
+ * @param gai_result
+ * The getaddrinfo result.
+ *
+ * @result
+ * For hostnames that were resolved via mDNS, the return value is the index of the interface via which the
+ * hostname was resolved. For hostnames that were resolved via DNS, the return value is 0.
+ */
+DNSSD_AVAILABLE
+uint32_t
+dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ * @brief
+ * Gets a getaddrinfo result's authentication tag.
+ *
+ * @param gai_result
+ * The getaddrinfo result.
+ *
+ * @param out_length
+ * If non-NULL, gets set to the length of the authentication tag.
+ *
+ * @result
+ * A pointer to the getaddrinfo result's authentication tag, if it has one. Otherwise, NULL.
+ *
+ * @discussion
+ * The returned pointer, if non-NULL, is valid until the getaddrinfo result is released.
+ */
+DNSSD_AVAILABLE
+const void * _Nullable
+dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t gai_result, size_t *_Nullable out_length);
+
+static inline const char *
+dnssd_getaddrinfo_result_type_to_string(dnssd_getaddrinfo_result_type_t result)
+{
+ switch (result) {
+ case dnssd_getaddrinfo_result_type_add: return "Add";
+ case dnssd_getaddrinfo_result_type_remove: return "Remove";
+ case dnssd_getaddrinfo_result_type_no_address: return "NoAddress";
+ case dnssd_getaddrinfo_result_type_expired: return "Expired";
+ default: return "?";
+ }
+}
+
+static inline const char *
+dnssd_event_to_string(dnssd_event_t event)
+{
+ switch (event) {
+ case dnssd_event_remove_all: return "RemoveAll";
+ case dnssd_event_error: return "Error";
+ case dnssd_event_invalidated: return "Invalidated";
+ default: return "?";
+ }
+}
+
+__END_DECLS
+
+DNSSD_ASSUME_NONNULL_END
+
+#endif // __DNSSD_PRIVATE_H__
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dnssd_server.h"
+
+#include "ClientRequests.h"
+#include "dnssd_xpc.h"
+#include "mDNSMacOSX.h"
+
+#include <CoreUtils/CommonServices.h>
+#include <CoreUtils/DebugServices.h>
+#include <libproc.h>
+#include <net/necp.h>
+#include <sys/proc_info.h>
+#include <xpc/private.h>
+
+#if 0
+//======================================================================================================================
+#pragma mark - Kind Declarations
+#endif
+
+#define DX_STRUCT(NAME) struct dx_ ## NAME ## _s
+#define DX_TYPE(NAME) dx_ ## NAME ## _t
+#define DX_KIND_DECLARE(NAME) typedef DX_STRUCT(NAME) * DX_TYPE(NAME)
+
+#define DX_KIND_DECLARE_FULL(NAME) \
+ DX_KIND_DECLARE(NAME); \
+ \
+ static void \
+ _dx_ ## NAME ## _invalidate(DX_TYPE(NAME) object); \
+ \
+ static void \
+ _dx_ ## NAME ## _finalize(DX_TYPE(NAME) object); \
+ \
+ static DX_TYPE(NAME) \
+ _dx_ ## NAME ## _alloc(void)
+
+// Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
+// comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
+// the warning hasn't been disabled.
+
+#define DX_BASE_CHECK(NAME, SUPER) \
+ check_compile_time(offsetof(DX_STRUCT(NAME), base) == 0); \
+ check_compile_time(sizeof_field(DX_STRUCT(NAME), base) == sizeof(DX_STRUCT(SUPER))); \
+ extern int _dx_base_type_check[sizeof(&(((DX_TYPE(NAME))0)->base) == ((DX_TYPE(SUPER))0))]
+
+#define DX_KIND_DEFINE(NAME, SUPER) \
+ static const struct dx_kind_s _dx_ ## NAME ## _kind = { \
+ &_dx_ ## SUPER ##_kind, \
+ _dx_ ## NAME ## _invalidate, \
+ _dx_ ## NAME ## _finalize, \
+ }; \
+ \
+ static DX_TYPE(NAME) \
+ _dx_ ## NAME ## _alloc(void) \
+ { \
+ const DX_TYPE(NAME) obj = (DX_TYPE(NAME))calloc(1, sizeof(*obj)); \
+ require_quiet(obj, exit); \
+ \
+ const dx_base_t base = (dx_base_t)obj; \
+ base->ref_count = 1; \
+ base->kind = &_dx_ ## NAME ## _kind; \
+ \
+ exit: \
+ return obj; \
+ } \
+ DX_BASE_CHECK(NAME, SUPER)
+
+DX_KIND_DECLARE(base);
+DX_KIND_DECLARE(request);
+DX_KIND_DECLARE_FULL(session);
+DX_KIND_DECLARE_FULL(getaddrinfo_request);
+
+typedef union {
+ dx_base_t base;
+ dx_session_t session;
+ dx_request_t request;
+ dx_getaddrinfo_request_t getaddrinfo_request;
+} dx_any_t __attribute__((__transparent_union__));
+
+typedef void (*dx_invalidate_f)(dx_any_t object);
+typedef void (*dx_finalize_f)(dx_any_t object);
+
+typedef const struct dx_kind_s * dx_kind_t;
+struct dx_kind_s {
+ dx_kind_t superkind; // This kind's superkind. All kinds have a superkind, except the base kind.
+ dx_invalidate_f invalidate; // Stops an object's outstanding operations, if any.
+ dx_finalize_f finalize; // Releases object's resources right before the object is freed.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - Base Kind Definition
+#endif
+
+struct dx_base_s {
+ dx_kind_t kind; // The object's kind.
+ int32_t ref_count; // Reference count.
+};
+
+static const struct dx_kind_s _dx_base_kind = {
+ NULL, // No superkind.
+ NULL, // No invalidate method.
+ NULL, // No finalize method.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - Request Kind Definition
+#endif
+
+struct dx_request_s {
+ struct dx_base_s base; // Object base.
+ dx_request_t next; // Next request in list.
+ xpc_object_t result_array; // Array of pending results.
+ uint64_t command_id; // ID to distinquish multiple commands during a session.
+ uint32_t request_id; // Request ID, used for logging purposes.
+ DNSServiceErrorType error; // Pending error.
+ bool sent_error; // True if the pending error has been sent to client.
+};
+
+static void
+_dx_request_finalize(dx_any_t request);
+
+static const struct dx_kind_s _dx_request_kind = {
+ &_dx_base_kind,
+ NULL, // No invalidate method.
+ _dx_request_finalize,
+};
+DX_BASE_CHECK(request, base);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Session Kind Definition
+#endif
+
+struct dx_session_s {
+ struct dx_base_s base; // Object base;
+ dx_session_t next; // Next session in list.
+ dx_request_t request_list; // List of outstanding requests.
+ xpc_connection_t connection; // Underlying XPC connection.
+ bool has_delegate_entitlement; // True if the client is entitled to be a delegate.
+};
+
+DX_KIND_DEFINE(session, base);
+
+#if 0
+//======================================================================================================================
+#pragma mark - GetAddrInfo Request Kind Definition
+#endif
+
+struct dx_getaddrinfo_request_s {
+ struct dx_request_s base; // Request object base.
+ GetAddrInfoClientRequest gai; // Underlying GetAddrInfoClientRequest.
+ xpc_object_t hostname; // Hostname to be resolved for getaddrinfo requests.
+ uuid_t client_uuid; // Client's UUID for authenticating results.
+ bool need_auth; // True if results need to be authenticated.
+ bool active; // True if the GetAddrInfoClientRequest is currently active.
+};
+
+DX_KIND_DEFINE(getaddrinfo_request, request);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Local Prototypes
+#endif
+
+static dispatch_queue_t
+_dx_server_queue(void);
+
+static void
+_dx_server_register_session(dx_session_t session);
+
+static void
+_dx_server_deregister_session(dx_session_t session);
+
+static void
+_dx_retain(dx_any_t object);
+
+static void
+_dx_release(dx_any_t object);
+#define _dx_release_null_safe(X) do { if (X) { _dx_release(X); } } while (0)
+
+static void
+_dx_invalidate(dx_any_t object);
+
+static dx_session_t
+_dx_session_create(xpc_connection_t connection);
+
+static void
+_dx_session_activate(dx_session_t me);
+
+static DNSServiceErrorType
+_dx_session_handle_getaddrinfo_command(dx_session_t session, xpc_object_t msg);
+
+static DNSServiceErrorType
+_dx_session_handle_stop_command(dx_session_t session, xpc_object_t msg);
+
+static void
+_dx_session_send_results(dx_session_t session);
+
+static dx_getaddrinfo_request_t
+_dx_getaddrinfo_request_create(uint64_t command_id, uint32_t request_id);
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_set_hostname(dx_getaddrinfo_request_t request, xpc_object_t hostname);
+
+static void
+_dx_getaddrinfo_request_set_need_authenticaed_results(dx_getaddrinfo_request_t request, bool need,
+ const uuid_t client_uuid);
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_activate(dx_getaddrinfo_request_t request, uint32_t interface_index, DNSServiceFlags flags,
+ DNSServiceProtocol protocols, pid_t pid, const uuid_t uuid, uid_t uid);
+
+static void
+_dx_getaddrinfo_request_result_handler(mDNS *m, DNSQuestion *question, const ResourceRecord *answer,
+ QC_result qc_result, DNSServiceErrorType error, void *context);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Server Functions
+#endif
+
+static void
+_dx_server_handle_new_connection(xpc_connection_t connection);
+
+mDNSexport void
+dnssd_server_init(void)
+{
+ static xpc_connection_t listener = NULL;
+
+ listener = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dx_server_queue(),
+ XPC_CONNECTION_MACH_SERVICE_LISTENER);
+ xpc_connection_set_event_handler(listener,
+ ^(xpc_object_t event)
+ {
+ if (xpc_get_type(event) == XPC_TYPE_CONNECTION) {
+ _dx_server_handle_new_connection((xpc_connection_t)event);
+ }
+ });
+ xpc_connection_activate(listener);
+}
+
+static void
+_dx_server_handle_new_connection(xpc_connection_t connection)
+{
+ const dx_session_t session = _dx_session_create(connection);
+ if (session) {
+ _dx_session_activate(session);
+ _dx_server_register_session(session);
+ _dx_release(session);
+ } else {
+ xpc_connection_cancel(connection);
+ }
+}
+
+
+//======================================================================================================================
+
+static dx_session_t g_session_list = NULL;
+
+mDNSexport void
+dnssd_server_idle(void)
+{
+ for (dx_session_t session = g_session_list; session; session = session->next) {
+ _dx_session_send_results(session);
+ }
+}
+
+//======================================================================================================================
+
+static dispatch_queue_t
+_dx_server_queue(void)
+{
+ static dispatch_once_t once = 0;
+ static dispatch_queue_t queue = NULL;
+
+ dispatch_once(&once,
+ ^{
+ const dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
+ QOS_CLASS_UTILITY, 0);
+ queue = dispatch_queue_create("com.apple.dnssd.server", attr);
+ });
+ return queue;
+}
+
+//======================================================================================================================
+
+static void
+_dx_server_register_session(dx_session_t session)
+{
+ session->next = g_session_list;
+ g_session_list = session;
+ _dx_retain(session);
+}
+
+//======================================================================================================================
+
+static void
+_dx_server_deregister_session(dx_session_t session)
+{
+ dx_session_t *ptr;
+ for (ptr = &g_session_list; *ptr; ptr = &(*ptr)->next) {
+ if (*ptr == session) {
+ break;
+ }
+ }
+ if (*ptr) {
+ *ptr = session->next;
+ session->next = NULL;
+ _dx_release(session);
+ }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Base Methods
+#endif
+
+static void
+_dx_retain(dx_any_t object)
+{
+ ++object.base->ref_count;
+}
+
+//======================================================================================================================
+
+static void
+_dx_release(dx_any_t object)
+{
+ if (--object.base->ref_count == 0) {
+ for (dx_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+ if (kind->finalize) {
+ kind->finalize(object);
+ }
+ }
+ free(object.base);
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dx_invalidate(dx_any_t object)
+{
+ for (dx_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+ if (kind->invalidate) {
+ kind->invalidate(object);
+ return;
+ }
+ }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Session Methods
+#endif
+
+static dx_session_t
+_dx_session_create(xpc_connection_t connection)
+{
+ const dx_session_t obj = _dx_session_alloc();
+ require_quiet(obj, exit);
+
+ obj->connection = connection;
+ xpc_retain(obj->connection);
+
+exit:
+ return obj;
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_handle_message(dx_session_t session, xpc_object_t msg);
+
+#define DNSSD_DELEGATE_ENTITLEMENT "com.apple.private.network.socket-delegate"
+
+static void
+_dx_session_activate(dx_session_t me)
+{
+ const xpc_object_t value = xpc_connection_copy_entitlement_value(me->connection, DNSSD_DELEGATE_ENTITLEMENT);
+ if (value) {
+ if (value == XPC_BOOL_TRUE) {
+ me->has_delegate_entitlement = true;
+ }
+ xpc_release(value);
+ }
+ _dx_retain(me);
+ xpc_connection_set_target_queue(me->connection, _dx_server_queue());
+ xpc_connection_set_event_handler(me->connection,
+ ^(xpc_object_t event) {
+ const xpc_type_t type = xpc_get_type(event);
+ if (type == XPC_TYPE_DICTIONARY) {
+ KQueueLock();
+ _dx_session_handle_message(me, event);
+ KQueueUnlock("_dx_session_handle_message");
+ } else if (event == XPC_ERROR_CONNECTION_INVALID) {
+ KQueueLock();
+ _dx_server_deregister_session(me);
+ KQueueUnlock("_dx_server_deregister_session");
+ _dx_session_invalidate(me);
+ _dx_release(me);
+ } else {
+ xpc_connection_cancel(me->connection);
+ }
+ });
+ xpc_connection_activate(me->connection);
+}
+
+static void
+_dx_session_handle_message(dx_session_t me, xpc_object_t msg)
+{
+ DNSServiceErrorType error;
+ const char * const command = dnssd_xpc_message_get_command(msg);
+ require_action_quiet(command, exit, error = kDNSServiceErr_BadParam);
+
+ if (strcmp(command, DNSSD_COMMAND_GETADDRINFO) == 0) {
+ error = _dx_session_handle_getaddrinfo_command(me, msg);
+ } else if (strcmp(command, DNSSD_COMMAND_STOP) == 0) {
+ error = _dx_session_handle_stop_command(me, msg);
+ } else {
+ error = kDNSServiceErr_BadParam;
+ }
+
+exit:
+ {
+ const xpc_object_t reply = xpc_dictionary_create_reply(msg);
+ if (likely(reply)) {
+ dnssd_xpc_message_set_error(reply, error);
+ xpc_connection_send_message(me->connection, reply);
+ xpc_release(reply);
+ } else {
+ xpc_connection_cancel(me->connection);
+ }
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_invalidate(dx_session_t me)
+{
+ xpc_connection_forget(&me->connection);
+ dx_request_t req;
+ while ((req = me->request_list) != NULL)
+ {
+ me->request_list = req->next;
+ _dx_invalidate(req);
+ _dx_release(req);
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_finalize(dx_session_t me)
+{
+ (void)me;
+}
+
+//======================================================================================================================
+
+static bool
+_dx_get_getaddrinfo_params(xpc_object_t msg, uint64_t *out_command_id, xpc_object_t *out_hostname,
+ uint32_t *out_interface_index, DNSServiceFlags *out_flags, DNSServiceProtocol *out_protocols,
+ pid_t *out_delegate_pid, const uint8_t **out_delegate_uuid, bool *out_need_auth_tags);
+
+extern mDNS mDNSStorage;
+#define g_mdns mDNSStorage
+
+static DNSServiceErrorType
+_dx_session_handle_getaddrinfo_command(dx_session_t me, xpc_object_t msg)
+{
+ dx_getaddrinfo_request_t req = NULL;
+ DNSServiceErrorType error;
+ uint64_t command_id;
+ xpc_object_t hostname;
+ uint32_t interface_index;
+ DNSServiceFlags flags;
+ DNSServiceProtocol protocols;
+ pid_t pid;
+ const uint8_t * uuid;
+ bool need_auth;
+
+ const bool valid = _dx_get_getaddrinfo_params(msg, &command_id, &hostname, &interface_index, &flags, &protocols,
+ &pid, &uuid, &need_auth);
+ require_action_quiet(valid, exit, error = kDNSServiceErr_BadParam);
+
+ if (uuid || (pid != 0)) {
+ require_action_quiet(me->has_delegate_entitlement, exit, error = kDNSServiceErr_NoAuth);
+ } else {
+ pid = xpc_connection_get_pid(me->connection);
+ }
+
+ req = _dx_getaddrinfo_request_create(command_id, g_mdns.next_request_id++);
+ require_action_quiet(req, exit, error = kDNSServiceErr_NoMemory);
+
+ error = _dx_getaddrinfo_request_set_hostname(req, hostname);
+ require_noerr_quiet(error, exit);
+
+ if (need_auth) {
+ struct proc_uniqidentifierinfo info;
+ const int n = proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
+ if (n == (int)sizeof(info)) {
+ _dx_getaddrinfo_request_set_need_authenticaed_results(req, true, info.p_uuid);
+ }
+ }
+
+ const uid_t euid = xpc_connection_get_euid(me->connection);
+ error = _dx_getaddrinfo_request_activate(req, interface_index, flags, protocols, pid, uuid, euid);
+ require_noerr_quiet(error, exit);
+
+ req->base.next = me->request_list;
+ me->request_list = (dx_request_t)req;
+ req = NULL;
+
+exit:
+ _dx_release_null_safe(req);
+ static_analyzer_malloc_freed(req);
+ return error;
+}
+
+static bool
+_dx_get_getaddrinfo_params(xpc_object_t msg, uint64_t *out_command_id, xpc_object_t *out_hostname,
+ uint32_t *out_interface_index, DNSServiceFlags *out_flags, DNSServiceProtocol *out_protocols,
+ pid_t *out_delegate_pid, const uint8_t **out_delegate_uuid, bool *out_need_auth_tags)
+{
+ bool params_are_valid = false;
+ bool valid;
+ const uint64_t command_id = dnssd_xpc_message_get_id(msg, &valid);
+ require_quiet(valid, exit);
+
+ const xpc_object_t params = dnssd_xpc_message_get_parameters(msg);
+ require_quiet(params, exit);
+
+ xpc_object_t hostname = dnssd_xpc_parameters_get_hostname_object(params);
+ require_quiet(hostname, exit);
+
+ const uint32_t interface_index = dnssd_xpc_parameters_get_interface_index(params, &valid);
+ require_quiet(valid, exit);
+
+ const DNSServiceFlags flags = dnssd_xpc_parameters_get_flags(params, &valid);
+ require_quiet(valid, exit);
+
+ const uint32_t protocols = dnssd_xpc_parameters_get_protocols(params, &valid);
+ require_quiet(valid, exit);
+
+ pid_t pid;
+ const uint8_t * const uuid = dnssd_xpc_parameters_get_delegate_uuid(params);
+ if (uuid) {
+ pid = 0;
+ } else {
+ pid = dnssd_xpc_parameters_get_delegate_pid(params, NULL);
+ }
+
+ *out_command_id = command_id;
+ *out_hostname = hostname;
+ *out_interface_index = interface_index;
+ *out_flags = flags;
+ *out_protocols = protocols;
+ *out_delegate_pid = pid;
+ *out_delegate_uuid = uuid;
+ *out_need_auth_tags = dnssd_xpc_parameters_get_need_authentication_tags(params);
+ params_are_valid = true;
+
+exit:
+ return params_are_valid;
+}
+
+//======================================================================================================================
+
+static DNSServiceErrorType
+_dx_session_handle_stop_command(dx_session_t me, xpc_object_t msg)
+{
+ bool valid;
+ DNSServiceErrorType error;
+ const uint64_t command_id = dnssd_xpc_message_get_id(msg, &valid);
+ require_action_quiet(valid, exit, error = kDNSServiceErr_BadParam);
+
+ dx_request_t * ptr;
+ dx_request_t req;
+ for (ptr = &me->request_list; (req = *ptr) != NULL; ptr = &req->next) {
+ if (req->command_id == command_id) {
+ break;
+ }
+ }
+ require_action_quiet(req, exit, error = kDNSServiceErr_BadReference);
+
+ *ptr = req->next;
+ req->next = NULL;
+
+ _dx_invalidate(req);
+ _dx_release(req);
+ error = kDNSServiceErr_NoError;
+
+exit:
+ return error;
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_send_results(dx_session_t me)
+{
+ bool success = false;
+ for (dx_request_t req = me->request_list; req; req = req->next) {
+ if (req->result_array && (xpc_array_get_count(req->result_array) > 0)) {
+ const xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+ require_quiet(msg, exit);
+
+ dnssd_xpc_message_set_id(msg, req->command_id);
+ dnssd_xpc_message_set_error(msg, kDNSServiceErr_NoError);
+ dnssd_xpc_message_set_results(msg, req->result_array);
+ xpc_connection_send_message(me->connection, msg);
+ xpc_release(msg);
+
+ xpc_release(req->result_array);
+ req->result_array = xpc_array_create(NULL, 0);
+ require_quiet(req->result_array, exit);
+ }
+ if (req->error && !req->sent_error) {
+ const xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+ require_quiet(msg, exit);
+
+ dnssd_xpc_message_set_id(msg, req->command_id);
+ dnssd_xpc_message_set_error(msg, req->error);
+ xpc_connection_send_message(me->connection, msg);
+ xpc_release(msg);
+ req->sent_error = true;
+ }
+ }
+ success = true;
+
+exit:
+ if (unlikely(!success)) {
+ xpc_connection_cancel(me->connection);
+ }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Request Methods
+#endif
+
+static void
+_dx_request_finalize(dx_request_t me)
+{
+ xpc_forget(&me->result_array);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - GetAddrInfo Request Methods
+#endif
+
+static dx_getaddrinfo_request_t
+_dx_getaddrinfo_request_create(uint64_t command_id, uint32_t request_id)
+{
+ dx_getaddrinfo_request_t req = NULL;
+ dx_getaddrinfo_request_t obj = _dx_getaddrinfo_request_alloc();
+ require_quiet(obj, exit);
+
+ obj->base.command_id = command_id;
+ obj->base.request_id = request_id;
+ obj->base.result_array = xpc_array_create(NULL, 0);
+ require_quiet(obj->base.result_array, exit);
+
+ req = obj;
+ obj = NULL;
+
+exit:
+ _dx_release_null_safe(obj);
+ return req;
+}
+
+//======================================================================================================================
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_set_hostname(dx_getaddrinfo_request_t me, xpc_object_t hostname)
+{
+ DNSServiceErrorType err;
+ require_action_quiet(xpc_string_get_length(hostname) <= MAX_ESCAPED_DOMAIN_NAME, exit,
+ err = kDNSServiceErr_BadParam);
+
+ xpc_release_null_safe(me->hostname);
+ me->hostname = xpc_copy(hostname);
+ require_action_quiet(me->hostname, exit, err = kDNSServiceErr_NoMemory);
+
+ err = kDNSServiceErr_NoError;
+
+exit:
+ return err;
+}
+
+//======================================================================================================================
+
+static void
+_dx_getaddrinfo_request_set_need_authenticaed_results(dx_getaddrinfo_request_t me, bool need, const uuid_t client_uuid)
+{
+ if (need) {
+ uuid_copy(me->client_uuid, client_uuid);
+ me->need_auth = true;
+ } else {
+ uuid_clear(me->client_uuid);
+ me->need_auth = false;
+ }
+}
+
+//======================================================================================================================
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_activate(dx_getaddrinfo_request_t me, uint32_t interface_index, DNSServiceFlags flags,
+ DNSServiceProtocol protocols, pid_t pid, const uuid_t uuid, uid_t uid)
+{
+ DNSServiceErrorType err;
+ const char * const hostname_str = xpc_string_get_string_ptr(me->hostname);
+ require_action_quiet(hostname_str, exit, err = kDNSServiceErr_Unknown);
+
+ err = GetAddrInfoClientRequestStart(&me->gai, me->base.request_id, hostname_str, interface_index, flags,
+ protocols, pid, uuid, uid, _dx_getaddrinfo_request_result_handler, me);
+ require_noerr_quiet(err, exit);
+
+ _dx_retain(me);
+ me->active = true;
+
+exit:
+ return err;
+}
+
+//======================================================================================================================
+
+static void
+_dx_getaddrinfo_request_invalidate(dx_getaddrinfo_request_t me)
+{
+ if (me->active) {
+ GetAddrInfoClientRequestStop(&me->gai);
+ me->active = false;
+ _dx_release(me);
+ }
+}
+
+//======================================================================================================================
+
+static void
+_dx_getaddrinfo_request_finalize(dx_getaddrinfo_request_t me)
+{
+ xpc_forget(&me->hostname);
+}
+
+//======================================================================================================================
+
+#if defined(NECP_CLIENT_ACTION_SIGN)
+#define DNSSD_AUTHENTICATION_TAG_SIZE 32 // XXX: Defined as a workaround until NECP header defines this length.
+
+static bool
+_dx_authenticate_answer(uuid_t client_id, xpc_object_t hostname, int record_type, const void *record_data,
+ uint8_t out_auth_tag[STATIC_PARAM DNSSD_AUTHENTICATION_TAG_SIZE]);
+#endif
+
+static void
+_dx_getaddrinfo_request_result_handler(mDNS *m, DNSQuestion *question, const ResourceRecord *answer,
+ QC_result qc_result, DNSServiceErrorType error, void *context)
+{
+ (void)question;
+
+ const dx_getaddrinfo_request_t me = (dx_getaddrinfo_request_t)context;
+ if (error && (error != kDNSServiceErr_NoSuchRecord)) {
+ if (!me->base.error) {
+ me->base.error = error;
+ }
+ goto exit;
+ }
+ require_quiet((answer->rrtype == kDNSServiceType_A) || (answer->rrtype == kDNSServiceType_AAAA), exit);
+
+ const void * rdata_ptr;
+ size_t rdata_len;
+ if (!error) {
+ if (answer->rrtype == kDNSServiceType_A) {
+ rdata_ptr = answer->rdata->u.ipv4.b;
+ rdata_len = 4;
+ } else {
+ rdata_ptr = answer->rdata->u.ipv6.b;
+ rdata_len = 16;
+ }
+ } else {
+ rdata_ptr = NULL;
+ rdata_len = 0;
+ }
+
+ DNSServiceFlags flags = 0;
+ if (qc_result != QC_rmv) {
+ flags |= kDNSServiceFlagsAdd;
+ }
+ if (answer->mortality == Mortality_Ghost) {
+ flags |= kDNSServiceFlagsExpiredAnswer;
+ }
+ if (!question->InitialCacheMiss) {
+ flags |= kDNSServiceFlagAnsweredFromCache;
+ }
+
+ const uint32_t interface_index = mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNStrue);
+ const xpc_object_t result = xpc_dictionary_create(NULL, NULL, 0);
+ if (likely(result)) {
+ char name_str[MAX_ESCAPED_DOMAIN_NAME];
+ ConvertDomainNameToCString(answer->name, name_str);
+
+ dnssd_xpc_result_set_error(result, error);
+ dnssd_xpc_result_set_flags(result, flags);
+ dnssd_xpc_result_set_interface_index(result, interface_index);
+ dnssd_xpc_result_set_record_name(result, name_str);
+ dnssd_xpc_result_set_record_type(result, answer->rrtype);
+ dnssd_xpc_result_set_record_class(result, answer->rrclass);
+ dnssd_xpc_result_set_record_data(result, rdata_ptr, rdata_len);
+
+#if defined(NECP_CLIENT_ACTION_SIGN)
+ if (me->need_auth && !error && (flags & kDNSServiceFlagsAdd)) {
+ uint8_t auth_tag[DNSSD_AUTHENTICATION_TAG_SIZE];
+ const bool success = _dx_authenticate_answer(me->client_uuid, me->hostname, answer->rrtype, rdata_ptr,
+ auth_tag);
+ if (success) {
+ dnssd_xpc_result_set_authentication_tag(result, auth_tag, sizeof(auth_tag));
+ }
+ }
+#endif
+ xpc_array_append_value(me->base.result_array, result);
+ xpc_release(result);
+ } else {
+ me->base.error = kDNSServiceErr_NoMemory;
+ }
+
+exit:
+ return;
+}
+
+#if defined(NECP_CLIENT_ACTION_SIGN)
+typedef struct {
+ struct necp_client_resolver_answer hdr;
+ uint8_t hostname[MAX_ESCAPED_DOMAIN_NAME];
+} dx_necp_answer_t;
+
+check_compile_time(offsetof(dx_necp_answer_t, hdr) == 0);
+check_compile_time(endof_field(struct necp_client_resolver_answer, hostname_length) == offsetof(dx_necp_answer_t, hostname));
+
+static bool
+_dx_authenticate_answer(uuid_t client_id, xpc_object_t hostname, int record_type, const void *record_data,
+ uint8_t out_auth_tag[STATIC_PARAM DNSSD_AUTHENTICATION_TAG_SIZE])
+{
+ static int necp_fd = -1;
+
+ bool success = false;
+ if (necp_fd < 0) {
+ necp_fd = necp_open(0);
+ }
+ require_quiet(necp_fd >= 0, exit);
+
+ dx_necp_answer_t answer;
+ memset(&answer, 0, sizeof(answer));
+
+ struct necp_client_resolver_answer * const hdr = &answer.hdr;
+ uuid_copy(hdr->client_id, client_id);
+
+ hdr->sign_type = NECP_CLIENT_SIGN_TYPE_RESOLVER_ANSWER;
+
+ switch (record_type) {
+ case kDNSServiceType_A:
+ hdr->address_answer.sa.sa_family = AF_INET;
+ hdr->address_answer.sa.sa_len = sizeof(struct sockaddr_in);
+ memcpy(&hdr->address_answer.sin.sin_addr.s_addr, record_data, 4);
+ break;
+
+ case kDNSServiceType_AAAA:
+ hdr->address_answer.sa.sa_family = AF_INET6;
+ hdr->address_answer.sa.sa_len = sizeof(struct sockaddr_in6);
+ memcpy(hdr->address_answer.sin6.sin6_addr.s6_addr, record_data, 16);
+ break;
+
+ default:
+ goto exit;
+ }
+ const size_t hostname_len = xpc_string_get_length(hostname);
+ require_quiet(hostname_len <= sizeof(answer.hostname), exit);
+
+ hdr->hostname_length = (uint32_t)hostname_len;
+ memcpy(answer.hostname, xpc_string_get_string_ptr(hostname), hdr->hostname_length);
+
+ const int necp_err = necp_client_action(necp_fd, NECP_CLIENT_ACTION_SIGN, (void *)&answer,
+ sizeof(answer.hdr) + hdr->hostname_length, out_auth_tag, DNSSD_AUTHENTICATION_TAG_SIZE);
+ require_noerr_quiet(necp_err, exit);
+
+ success = true;
+
+exit:
+ return success;
+}
+#endif // defined(NECP_CLIENT_ACTION_SIGN)
--- /dev/null
+/*
+ * Copyright (c) 2018 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DNSSD_SERVER_H__
+#define __DNSSD_SERVER_H__
+
+#include "mDNSEmbeddedAPI.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mDNSexport void
+dnssd_server_init(void);
+
+mDNSexport void
+dnssd_server_idle(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DNSSD_SERVER_H__
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dnssd_xpc.h"
+
+#if 0
+//======================================================================================================================
+#pragma mark - XPC Dictionary Helper Declarations
+#endif
+
+static int32_t
+_dnssd_xpc_dictionary_get_int32(xpc_object_t dict, const char *key, bool *out_valid);
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64(xpc_object_t dict, const char *key, bool *out_valid);
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64_limited(xpc_object_t dict, const char *key, int64_t min, int64_t max, bool *out_valid);
+
+static uint16_t
+_dnssd_xpc_dictionary_get_uint16(xpc_object_t dict, const char *key, bool *out_valid);
+
+static uint32_t
+_dnssd_xpc_dictionary_get_uint32(xpc_object_t dict, const char *key, bool *out_valid);
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64(xpc_object_t dict, const char *key, bool *out_valid);
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64_limited(xpc_object_t dict, const char *key, uint64_t min, uint64_t max,
+ bool *out_valid);
+
+static xpc_object_t
+_dnssd_xpc_dictionary_get_value(xpc_object_t dict, const char *key, xpc_type_t type);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Top-Level Message Dictionaries
+#endif
+
+#define DNSSD_XPC_MESSAGE_KEY_COMMAND "command"
+#define DNSSD_XPC_MESSAGE_KEY_ERROR "error"
+#define DNSSD_XPC_MESSAGE_KEY_ID "id"
+#define DNSSD_XPC_MESSAGE_KEY_PARAMS "params"
+#define DNSSD_XPC_MESSAGE_KEY_RESULTS "results"
+
+//======================================================================================================================
+
+const char *
+dnssd_xpc_message_get_command(xpc_object_t msg)
+{
+ return xpc_dictionary_get_string(msg, DNSSD_XPC_MESSAGE_KEY_COMMAND);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_command(xpc_object_t msg, const char *command)
+{
+ xpc_dictionary_set_string(msg, DNSSD_XPC_MESSAGE_KEY_COMMAND, command);
+}
+
+//======================================================================================================================
+
+DNSServiceErrorType
+dnssd_xpc_message_get_error(xpc_object_t msg, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_int32(msg, DNSSD_XPC_MESSAGE_KEY_ERROR, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_error(xpc_object_t msg, DNSServiceErrorType error)
+{
+ xpc_dictionary_set_int64(msg, DNSSD_XPC_MESSAGE_KEY_ERROR, error);
+}
+
+//======================================================================================================================
+
+uint64_t
+dnssd_xpc_message_get_id(xpc_object_t msg, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint64(msg, DNSSD_XPC_MESSAGE_KEY_ID, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_id(xpc_object_t msg, uint64_t ident)
+{
+ xpc_dictionary_set_uint64(msg, DNSSD_XPC_MESSAGE_KEY_ID, ident);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_message_get_parameters(xpc_object_t msg)
+{
+ return xpc_dictionary_get_dictionary(msg, DNSSD_XPC_MESSAGE_KEY_PARAMS);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_parameters(xpc_object_t msg, xpc_object_t params)
+{
+ xpc_dictionary_set_value(msg, DNSSD_XPC_MESSAGE_KEY_PARAMS, params);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_message_get_results(xpc_object_t msg)
+{
+ return xpc_dictionary_get_array(msg, DNSSD_XPC_MESSAGE_KEY_RESULTS);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_results(xpc_object_t msg, xpc_object_t results)
+{
+ xpc_dictionary_set_value(msg, DNSSD_XPC_MESSAGE_KEY_RESULTS, results);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Parameter Dictionaries
+#endif
+
+#define DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID "delegate_id"
+#define DNSSD_XPC_PARAMETERS_KEY_FLAGS "flags"
+#define DNSSD_XPC_PARAMETERS_KEY_HOSTNAME "hostname"
+#define DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX "interface_index"
+#define DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS "need_auth_tags"
+#define DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS "protocols"
+
+//======================================================================================================================
+
+pid_t
+dnssd_xpc_parameters_get_delegate_pid(xpc_object_t params, bool *out_valid)
+{
+ return (pid_t)_dnssd_xpc_dictionary_get_int64(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_delegate_pid(xpc_object_t params, pid_t pid)
+{
+ xpc_dictionary_set_int64(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, pid);
+}
+
+//======================================================================================================================
+
+const uint8_t *
+dnssd_xpc_parameters_get_delegate_uuid(xpc_object_t params)
+{
+ return xpc_dictionary_get_uuid(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_delegate_uuid(xpc_object_t params, uuid_t uuid)
+{
+ xpc_dictionary_set_uuid(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, uuid);
+}
+
+//======================================================================================================================
+
+DNSServiceFlags
+dnssd_xpc_parameters_get_flags(xpc_object_t params, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_FLAGS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_flags(xpc_object_t params, DNSServiceFlags flags)
+{
+ xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_FLAGS, flags);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_parameters_get_hostname_object(xpc_object_t params)
+{
+ return _dnssd_xpc_dictionary_get_value(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME, XPC_TYPE_STRING);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_hostname(xpc_object_t params, const char *hostname)
+{
+ xpc_dictionary_set_string(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME, hostname);
+}
+
+//======================================================================================================================
+
+uint32_t
+dnssd_xpc_parameters_get_interface_index(xpc_object_t params, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_interface_index(xpc_object_t params, uint32_t interface_index)
+{
+ xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX, interface_index);
+}
+
+//======================================================================================================================
+
+bool
+dnssd_xpc_parameters_get_need_authentication_tags(xpc_object_t params)
+{
+ return xpc_dictionary_get_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_need_authentication_tags(xpc_object_t params, bool need_auth_tags)
+{
+ xpc_dictionary_set_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS, need_auth_tags);
+}
+
+//======================================================================================================================
+
+DNSServiceProtocol
+dnssd_xpc_parameters_get_protocols(xpc_object_t params, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_protocols(xpc_object_t params, DNSServiceProtocol protocols)
+{
+ xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS, protocols);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Result Dictionaries
+#endif
+
+#define DNSSD_XPC_RESULT_KEY_AUTH_TAG "auth_tag"
+#define DNSSD_XPC_RESULT_KEY_ERROR "error"
+#define DNSSD_XPC_RESULT_KEY_FLAGS "flags"
+#define DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX "interface_index"
+#define DNSSD_XPC_RESULT_KEY_RECORD_CLASS "rclass"
+#define DNSSD_XPC_RESULT_KEY_RECORD_DATA "rdata"
+#define DNSSD_XPC_RESULT_KEY_RECORD_NAME "rname"
+#define DNSSD_XPC_RESULT_KEY_RECORD_TYPE "rtype"
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_result_get_authentication_tag_object(xpc_object_t result)
+{
+ return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_AUTH_TAG, XPC_TYPE_DATA);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_authentication_tag(xpc_object_t result, const void *auth_tag_ptr, size_t auth_tag_len)
+{
+ xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_AUTH_TAG, auth_tag_ptr, auth_tag_len);
+}
+
+//======================================================================================================================
+
+DNSServiceErrorType
+dnssd_xpc_result_get_error(xpc_object_t result, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_int32(result, DNSSD_XPC_RESULT_KEY_ERROR, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_error(xpc_object_t result, DNSServiceErrorType error)
+{
+ xpc_dictionary_set_int64(result, DNSSD_XPC_RESULT_KEY_ERROR, error);
+}
+
+//======================================================================================================================
+
+DNSServiceFlags
+dnssd_xpc_result_get_flags(xpc_object_t result, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint32(result, DNSSD_XPC_RESULT_KEY_FLAGS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_flags(xpc_object_t result, DNSServiceFlags flags)
+{
+ xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_FLAGS, flags);
+}
+
+//======================================================================================================================
+
+uint32_t
+dnssd_xpc_result_get_interface_index(xpc_object_t result, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint32(result, DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_interface_index(xpc_object_t result, uint32_t interface_index)
+{
+ xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX, interface_index);
+}
+
+//======================================================================================================================
+
+uint16_t
+dnssd_xpc_result_get_record_class(xpc_object_t result, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_CLASS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_class(xpc_object_t result, uint16_t class)
+{
+ xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_CLASS, class);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_result_get_record_data_object(xpc_object_t result)
+{
+ return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_RECORD_DATA, XPC_TYPE_DATA);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_data(xpc_object_t result, const void *data_ptr, size_t data_len)
+{
+ xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_RECORD_DATA, data_ptr, data_len);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_result_get_record_name_object(xpc_object_t result)
+{
+ return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_RECORD_NAME, XPC_TYPE_STRING);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_name(xpc_object_t result, const char *name)
+{
+ xpc_dictionary_set_string(result, DNSSD_XPC_RESULT_KEY_RECORD_NAME, name);
+}
+
+//======================================================================================================================
+
+uint16_t
+dnssd_xpc_result_get_record_type(xpc_object_t result, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_TYPE, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_type(xpc_object_t result, uint16_t type)
+{
+ xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_TYPE, type);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - XPC Dictionary Helpers
+#endif
+
+static int32_t
+_dnssd_xpc_dictionary_get_int32(xpc_object_t dict, const char *key, bool *out_valid)
+{
+ return (int32_t)_dnssd_xpc_dictionary_get_int64_limited(dict, key, INT32_MIN, INT32_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64(xpc_object_t dict, const char *key, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_int64_limited(dict, key, INT64_MIN, INT64_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64_limited(xpc_object_t dict, const char *key, int64_t min, int64_t max, bool *out_valid)
+{
+ int64_t i64;
+ bool valid;
+
+ xpc_object_t const value = _dnssd_xpc_dictionary_get_value(dict, key, XPC_TYPE_INT64);
+ if (value) {
+ i64 = xpc_int64_get_value(value);
+ if ((i64 >= min) && (i64 <= max)) {
+ valid = true;
+ } else {
+ i64 = 0;
+ valid = false;
+ }
+ } else {
+ i64 = 0;
+ valid = false;
+ }
+ if (out_valid) {
+ *out_valid = valid;
+ }
+ return i64;
+}
+
+//======================================================================================================================
+
+static uint16_t
+_dnssd_xpc_dictionary_get_uint16(xpc_object_t dict, const char *key, bool *out_valid)
+{
+ return (uint16_t)_dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT16_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static uint32_t
+_dnssd_xpc_dictionary_get_uint32(xpc_object_t dict, const char *key, bool *out_valid)
+{
+ return (uint32_t)_dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT32_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64(xpc_object_t dict, const char *key, bool *out_valid)
+{
+ return _dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT64_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64_limited(xpc_object_t dict, const char *key, uint64_t min, uint64_t max,
+ bool *out_valid)
+{
+ uint64_t u64;
+ bool valid;
+
+ xpc_object_t const value = _dnssd_xpc_dictionary_get_value(dict, key, XPC_TYPE_UINT64);
+ if (value) {
+ u64 = xpc_uint64_get_value(value);
+ if ((u64 >= min) && (u64 <= max)) {
+ valid = true;
+ } else {
+ u64 = 0;
+ valid = false;
+ }
+ } else {
+ u64 = 0;
+ valid = false;
+ }
+ if (out_valid) {
+ *out_valid = valid;
+ }
+ return u64;
+}
+
+//======================================================================================================================
+
+static xpc_object_t
+_dnssd_xpc_dictionary_get_value(xpc_object_t dict, const char *key, xpc_type_t type)
+{
+ xpc_object_t value = xpc_dictionary_get_value(dict, key);
+ return (value && (xpc_get_type(value) == type)) ? value : NULL;
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DNSSD_XPC_H__
+#define __DNSSD_XPC_H__
+
+#include <CoreUtils/CommonServices.h>
+#include <dns_sd.h>
+#include <xpc/xpc.h>
+
+#define DNSSD_MACH_SERVICE_NAME "com.apple.dnssd.service"
+
+#define DNSSD_COMMAND_GETADDRINFO "getaddrinfo"
+#define DNSSD_COMMAND_STOP "stop"
+
+CU_ASSUME_NONNULL_BEGIN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * @brief
+ * Gets command as a C string from XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @result
+ * Command, if present. Otherwise, NULL.
+ */
+const char * _Nullable
+dnssd_xpc_message_get_command(xpc_object_t msg);
+
+/*!
+ * @brief
+ * Gets error code from XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Error code, if present. Otherwise, 0.
+ */
+DNSServiceErrorType
+dnssd_xpc_message_get_error(xpc_object_t msg, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets command instance ID from XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * ID, if present. Otherwise, 0.
+ */
+uint64_t
+dnssd_xpc_message_get_id(xpc_object_t msg, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets command parameter dictionary from XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @result
+ * Command parameter dictionary, if present. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_message_get_parameters(xpc_object_t msg);
+
+/*!
+ * @brief
+ * Gets result array from XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @result
+ * Result array, if present. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_message_get_results(xpc_object_t msg);
+
+/*!
+ * @brief
+ * Sets command in XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param command
+ * Command as a C string.
+ */
+void
+dnssd_xpc_message_set_command(xpc_object_t msg, const char *command);
+
+/*!
+ * @brief
+ * Sets error code in XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param error
+ * Error code.
+ */
+void
+dnssd_xpc_message_set_error(xpc_object_t msg, DNSServiceErrorType error);
+
+/*!
+ * @brief
+ * Sets command instance ID in XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param ident
+ * Command instance ID.
+ */
+void
+dnssd_xpc_message_set_id(xpc_object_t msg, uint64_t ident);
+
+/*!
+ * @brief
+ * Sets command parameters dictionary in XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param params
+ * Command parameters dictionary.
+ */
+void
+dnssd_xpc_message_set_parameters(xpc_object_t msg, xpc_object_t params);
+
+/*!
+ * @brief
+ * Sets command result array in XPC message.
+ *
+ * @param msg
+ * XPC message.
+ *
+ * @param results
+ * Command result array.
+ */
+void
+dnssd_xpc_message_set_results(xpc_object_t msg, xpc_object_t results);
+
+/*!
+ * @brief
+ * Gets delegate ID as a PID from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Delegate ID as PID, if present. Otherwise, 0.
+ */
+pid_t
+dnssd_xpc_parameters_get_delegate_pid(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets delegate ID as a UUID from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @result
+ * Delegate ID as UUID, if present. Otherwise, NULL.
+ */
+const uint8_t * _Nullable
+dnssd_xpc_parameters_get_delegate_uuid(xpc_object_t params);
+
+/*!
+ * @brief
+ * Gets flags from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Flags, if present. Otherwise, 0.
+ */
+DNSServiceFlags
+dnssd_xpc_parameters_get_flags(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets hostname from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @result
+ * Hostname, if present, as an XPC string object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_parameters_get_hostname_object(xpc_object_t params);
+
+/*!
+ * @brief
+ * Gets interface index from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @para out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Interface index, if present. Otherwise, 0.
+ */
+uint32_t
+dnssd_xpc_parameters_get_interface_index(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets need_auth_tags boolean value from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @result
+ * A boolean value.
+ */
+bool
+dnssd_xpc_parameters_get_need_authentication_tags(xpc_object_t params);
+
+/*!
+ * @brief
+ * Gets protocols from a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Protocols, if present. Otherwise, 0.
+ */
+DNSServiceProtocol
+dnssd_xpc_parameters_get_protocols(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Sets delegate ID as a PID in a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param pid
+ * PID.
+ */
+void
+dnssd_xpc_parameters_set_delegate_pid(xpc_object_t params, pid_t pid);
+
+/*!
+ * @brief
+ * Sets delegate ID as a UUID in a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param uuid
+ * UUID.
+ */
+void
+dnssd_xpc_parameters_set_delegate_uuid(xpc_object_t params, uuid_t _Nonnull uuid);
+
+/*!
+ * @brief
+ * Sets flags in a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param flags
+ * Flags.
+ */
+void
+dnssd_xpc_parameters_set_flags(xpc_object_t params, DNSServiceFlags flags);
+
+/*!
+ * @brief
+ * Sets hostname in a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param hostname
+ * Hostname.
+ */
+void
+dnssd_xpc_parameters_set_hostname(xpc_object_t params, const char *hostname);
+
+/*!
+ * @brief
+ * Sets interface index in a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param interface_index
+ * Interface index.
+ */
+void
+dnssd_xpc_parameters_set_interface_index(xpc_object_t params, uint32_t interface_index);
+
+/*!
+ * @brief
+ * Sets whether mDNSResponder should include an authentication tag for each hostname resolution.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param need
+ * Pass <code>true</code> to enable this behavior. Pass <code>false</code> to disable it.
+ */
+void
+dnssd_xpc_parameters_set_need_authentication_tags(xpc_object_t params, bool need);
+
+/*!
+ * @brief
+ * Sets protocols in a command parameters dictionary.
+ *
+ * @param params
+ * Command parameters dictionary.
+ *
+ * @param protocols
+ * Protocols.
+ */
+void
+dnssd_xpc_parameters_set_protocols(xpc_object_t params, DNSServiceProtocol protocols);
+
+/*!
+ * @brief
+ * Gets authentication tag from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @result
+ * Authentication tag, if present, as an XPC data object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_result_get_authentication_tag_object(xpc_object_t result);
+
+/*!
+ * @brief
+ * Gets error code from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Error code, if present. Otherwise, 0.
+ */
+DNSServiceErrorType
+dnssd_xpc_result_get_error(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets flags from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Flags, if present. Otherwise, 0.
+ */
+DNSServiceFlags
+dnssd_xpc_result_get_flags(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets interface index from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Interface index, if present. Otherwise, 0.
+ */
+uint32_t
+dnssd_xpc_result_get_interface_index(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets record class from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Record class, if present. Otherwise, 0.
+ */
+uint16_t
+dnssd_xpc_result_get_record_class(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Gets record data from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @result
+ * Record data, if present, as an XPC data object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_result_get_record_data_object(xpc_object_t result);
+
+/*!
+ * @brief
+ * Gets record name from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @result
+ * Record name, if present, as an XPC string object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_result_get_record_name_object(xpc_object_t result);
+
+/*!
+ * @brief
+ * Gets record type from a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param out_valid
+ * If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ * @result
+ * Record type, if present. Otherwise, 0.
+ */
+uint16_t
+dnssd_xpc_result_get_record_type(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ * @brief
+ * Sets the authentication tag in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param auth_tag_ptr
+ * Pointer to the authentication tag.
+ *
+ * @param auth_tag_len
+ * Length of the authentication tag.
+ */
+void
+dnssd_xpc_result_set_authentication_tag(xpc_object_t result, const void *auth_tag_ptr, size_t auth_tag_len);
+
+/*!
+ * @brief
+ * Sets the error code in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param error
+ * Error code.
+ */
+void
+dnssd_xpc_result_set_error(xpc_object_t result, DNSServiceErrorType error);
+
+/*!
+ * @brief
+ * Sets flags in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param flags
+ * Flags.
+ */
+void
+dnssd_xpc_result_set_flags(xpc_object_t result, DNSServiceFlags flags);
+
+/*!
+ * @brief
+ * Sets interface index in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param interface_index
+ * Interface index.
+ */
+void
+dnssd_xpc_result_set_interface_index(xpc_object_t result, uint32_t interface_index);
+
+/*!
+ * @brief
+ * Sets record class in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param class
+ * Record class.
+ */
+void
+dnssd_xpc_result_set_record_class(xpc_object_t result, uint16_t class);
+
+/*!
+ * @brief
+ * Sets the record data in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param data_ptr
+ * Pointer to the record data.
+ *
+ * @param data_len
+ * Length of the record data.
+ */
+void
+dnssd_xpc_result_set_record_data(xpc_object_t result, const void * _Nullable data_ptr, size_t data_len);
+
+/*!
+ * @brief
+ * Sets record name in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param name
+ * Record name.
+ */
+void
+dnssd_xpc_result_set_record_name(xpc_object_t result, const char *name);
+
+/*!
+ * @brief
+ * Sets record type in a command result dictionary.
+ *
+ * @param result
+ * The command result dictionary.
+ *
+ * @param type
+ * Record type.
+ */
+void
+dnssd_xpc_result_set_record_type(xpc_object_t result, uint16_t type);
+
+#ifdef __cplusplus
+}
+#endif
+
+CU_ASSUME_NONNULL_END
+
+#endif // __DNSSD_XPC_H__
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>com.apple.security.network.client</key>
- <true/>
- <key>com.apple.security.network.server</key>
- <true/>
- <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
- <true/>
-</dict>
-</plist>
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2007-2019 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.
#include <CoreFoundation/CoreFoundation.h>
#include <sys/cdefs.h>
+#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <mach/mach.h>
#include "helper-server.h"
#include <xpc/private.h>
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
#define NO_SECURITYFRAMEWORK 1
#endif
mDNSBool result = defaultVal;
boolean = CFPreferencesCopyAppValue(key, kmDNSHelperProgramArgs);
- if (boolean)
+ if (boolean != NULL)
{
if (CFGetTypeID(boolean) == CFBooleanGetTypeID())
result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse;
case p2p_packetfilter:
{
+ size_t count = 0;
pfArray_t pfports;
pfArray_t pfprotocols;
const char *if_name;
uint32_t cmd;
- uint32_t count;
+ xpc_object_t xpc_obj_port_array;
+ size_t port_array_count = 0;
+ xpc_object_t xpc_obj_protocol_array;
+ size_t protocol_array_count = 0;
cmd = xpc_dictionary_get_uint64(req, "pf_opcode");
if_name = xpc_dictionary_get_string(req, "pf_ifname");
- count = xpc_dictionary_get_uint64(req, "pf_count");
-
- pfports[0] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port0");
- pfports[1] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port1");
- pfports[2] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port2");
- pfports[3] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port3");
-
- pfprotocols[0] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol0");
- pfprotocols[1] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol1");
- pfprotocols[2] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol2");
- pfprotocols[3] = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol3");
-
+ xpc_obj_port_array = xpc_dictionary_get_value(req, "xpc_obj_array_port");
+ if ((void *)xpc_obj_port_array != NULL)
+ port_array_count = xpc_array_get_count(xpc_obj_port_array);
+ xpc_obj_protocol_array = xpc_dictionary_get_value(req, "xpc_obj_array_protocol");
+ if ((void *)xpc_obj_protocol_array != NULL)
+ protocol_array_count = xpc_array_get_count(xpc_obj_protocol_array);
+ if (port_array_count != protocol_array_count)
+ break;
+ if (port_array_count > PFPortArraySize)
+ break;
+ count = port_array_count;
+
+ for (size_t i = 0; i < count; i++) {
+ pfports[i] = (uint16_t)xpc_array_get_uint64(xpc_obj_port_array, i);
+ pfprotocols[i] = (uint16_t)xpc_array_get_uint64(xpc_obj_protocol_array, i);
+ }
+
os_log_info(log_handle,"Calling new PacketFilterControl()");
PacketFilterControl(cmd, if_name, count, pfports, pfprotocols);
break;
case set_localaddr_cacheentry:
{
int if_index, family;
-
+ size_t ip_len, eth_len;
+
if_index = xpc_dictionary_get_uint64(req, "slace_ifindex");
family = xpc_dictionary_get_uint64(req, "slace_family");
-
- const uint8_t* ip = xpc_dictionary_get_data(req, "slace_ip", NULL);
- const uint8_t* eth = xpc_dictionary_get_data(req, "slace_eth", NULL);
-
- os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family);
- SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code);
-
- /*
- static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
+ const uint8_t * const ip = (const uint8_t *)xpc_dictionary_get_data(req, "slace_ip", &ip_len);
+ if (ip_len != sizeof(v6addr_t))
{
- if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
- {
- os_log(log_handle, "inet_ntop failed: %s", strerror(errno));
- return -1;
- }
- else
- {
- return 0;
- }
+ error_code = kHelperErr_ParamErr;
+ break;
}
- ethaddr_t eth = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } ;
- const uint8_t* slace_ip = NULL;
- v6addr_t addr_ipv6;
- size_t ip_len;
- slace_ip = xpc_dictionary_get_data(req, "slace_ip", &ip_len);
- if (slace_ip && (ip_len == sizeof(v6addr_t)))
+ const uint8_t * const eth = (const uint8_t *)xpc_dictionary_get_data(req, "slace_eth", ð_len);
+ if (eth_len != sizeof(ethaddr_t))
{
- os_log(log_handle, "mDNSResponderHelper: doing memcpy()");
- memcpy(&addr_ipv6, slace_ip, ip_len);
+ error_code = kHelperErr_ParamErr;
+ break;
}
- char test_ipv6_str[46];
- v6addr_to_string(addr_ipv6, test_ipv6_str, sizeof(test_ipv6_str));
- os_log(log_handle, "mDNSResponderHelper: handle_request: set_localaddr_cacheentry: test_ipv6_str is %s", test_ipv6_str);
- */
-
+
+ os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family);
+
+ SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code);
break;
}
{
uint16_t lport, rport, win;
uint32_t seq, ack;
+ size_t sadd6_len, dadd6_len;
lport = xpc_dictionary_get_uint64(req, "send_keepalive_lport");
rport = xpc_dictionary_get_uint64(req, "send_keepalive_rport");
ack = xpc_dictionary_get_uint64(req, "send_keepalive_ack");
win = xpc_dictionary_get_uint64(req, "send_keepalive_win");
- const uint8_t* sadd6 = xpc_dictionary_get_data(req, "send_keepalive_sadd", NULL);
- const uint8_t* dadd6 = xpc_dictionary_get_data(req, "send_keepalive_dadd", NULL);
-
+ const uint8_t * const sadd6 = (const uint8_t *)xpc_dictionary_get_data(req, "send_keepalive_sadd", &sadd6_len);
+ const uint8_t * const dadd6 = (const uint8_t *)xpc_dictionary_get_data(req, "send_keepalive_dadd", &dadd6_len);
+ if ((sadd6_len != sizeof(v6addr_t)) || (dadd6_len != sizeof(v6addr_t)))
+ {
+ error_code = kHelperErr_ParamErr;
+ break;
+ }
+
os_log_info(log_handle, "helper-main: handle_request: send_keepalive: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
lport, rport, seq, ack, win);
uint32_t seq, ack;
uint16_t win;
int32_t intfid;
+ size_t laddr_len, raddr_len;
lport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_lport");
rport = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_rport");
family = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_family");
-
- const uint8_t* laddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", NULL);
- const uint8_t* raddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", NULL);
-
+
+ const uint8_t * const laddr = (const uint8_t *)xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", &laddr_len);
+ const uint8_t * const raddr = (const uint8_t *)xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", &raddr_len);
+ if ((laddr_len != sizeof(v6addr_t)) || (raddr_len != sizeof(v6addr_t)))
+ {
+ error_code = kHelperErr_ParamErr;
+ break;
+ }
+
os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: lport is[%d] rport is[%d] family is [%d]",
lport, rport, family);
break;
}
- case autotunnel_setkeys:
- {
- uint16_t lport, rport;
- int replace_del;
- const char *fqdnstr;
-
- lport = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_lport");
- rport = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_rport");
- replace_del = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_repdel");
-
- const uint8_t* local_inner = xpc_dictionary_get_data(req, "autotunnelsetkeys_localinner", NULL);
- const uint8_t* local_outer = xpc_dictionary_get_data(req, "autotunnelsetkeys_localouter", NULL);
- const uint8_t* remote_inner = xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteinner", NULL);
- const uint8_t* remote_outer = xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteouter", NULL);
-
- fqdnstr = xpc_dictionary_get_string(req, "autotunnelsetkeys_fqdnStr");
-
- os_log_info(log_handle, "helper-main: handle_request: autotunnel_setkeys: lport is[%d] rport is[%d] replace_del is [%d]",
- lport, rport, replace_del);
-
-
- HelperAutoTunnelSetKeys(replace_del, local_inner, local_outer, lport, remote_inner, remote_outer, rport, fqdnstr, &error_code);
-
- break;
- }
-
-
case keychain_getsecrets:
{
unsigned int num_sec = 0;
if (response)
{
- xpc_dictionary_set_uint64(response, "keychain_num_secrets", num_sec);
+ xpc_dictionary_set_uint64(response, "keychain_num_secrets", num_sec);
xpc_dictionary_set_data(response, "keychain_secrets", (void *)secrets, sec_cnt);
- xpc_dictionary_set_uint64(response, "keychain_secrets_count", sec_cnt);
}
- os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %d, secrets is %lu, secrets_Cnt is %d",
- num_sec, secrets, sec_cnt);
+ os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %u, secrets is %lu, secrets_Cnt is %u",
+ num_sec, secrets, sec_cnt);
if (secrets)
vm_deallocate(mach_task_self(), secrets, sec_cnt);
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2007-2019 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.
#include <servers/bootstrap.h>
#include <IOKit/IOReturn.h>
#include <CoreFoundation/CoreFoundation.h>
-#include "mDNSDebug.h"
#include "helper.h"
#include <dispatch/dispatch.h>
#include <arpa/inet.h>
//*************************************************************************************************************
// Globals
static dispatch_queue_t HelperQueue;
-static xpc_connection_t helper_xpc_conn = NULL;
static int64_t maxwait_secs = 5LL;
//*************************************************************************************************************
-mDNSlocal void Init_Connection(const char *servname)
+mDNSlocal xpc_connection_t Create_Connection(void)
{
- helper_xpc_conn = xpc_connection_create_mach_service(servname, HelperQueue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
-
- xpc_connection_set_event_handler(helper_xpc_conn, ^(xpc_object_t event)
+ xpc_connection_t connection = xpc_connection_create_mach_service(kHelperService, HelperQueue,
+ XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+ if (connection)
{
- mDNSHELPER_DEBUG("Init_Connection xpc: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
- });
-
- xpc_connection_resume(helper_xpc_conn);
+ xpc_connection_set_event_handler(connection, ^(xpc_object_t event)
+ {
+ mDNSHELPER_DEBUG("Create_Connection xpc: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ });
+ xpc_connection_activate(connection);
+ }
+ return connection;
}
-mDNSlocal int SendDict_ToServer(xpc_object_t msg)
+mDNSlocal int SendDict_ToServer(xpc_object_t msg, xpc_object_t *out_reply)
{
+ xpc_connection_t connection;
+ dispatch_semaphore_t sem = NULL;
+ __block xpc_object_t reply = NULL;
__block int errorcode = kHelperErr_NoResponse;
HelperLog("SendDict_ToServer Sending msg to Daemon", msg);
- dispatch_semaphore_t sem = dispatch_semaphore_create(0);
- dispatch_retain(sem); // for the block below
+ connection = Create_Connection();
+ if (!connection)
+ {
+ goto exit;
+ }
+
+ sem = dispatch_semaphore_create(0);
+ if (!sem)
+ {
+ goto exit;
+ }
- xpc_connection_send_message_with_reply(helper_xpc_conn, msg, HelperQueue, ^(xpc_object_t recv_msg)
+ dispatch_retain(sem); // for the block below
+ xpc_connection_send_message_with_reply(connection, msg, HelperQueue, ^(xpc_object_t recv_msg)
{
- xpc_type_t type = xpc_get_type(recv_msg);
+ const xpc_type_t type = xpc_get_type(recv_msg);
if (type == XPC_TYPE_DICTIONARY)
{
HelperLog("SendDict_ToServer Received reply msg from Daemon", recv_msg);
uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus);
- errorcode = xpc_dictionary_get_int64(recv_msg, kHelperErrCode);
+ errorcode = (int)xpc_dictionary_get_int64(recv_msg, kHelperErrCode);
switch (reply_status)
{
LogMsg("default: Unexpected reply from Helper");
break;
}
+ reply = recv_msg;
+ xpc_retain(reply);
}
else
{
dispatch_semaphore_signal(sem);
dispatch_release(sem);
-
});
if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0)
+ {
LogMsg("SendDict_ToServer: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait");
-
- dispatch_release(sem);
-
- mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode);
-
- return errorcode;
-}
-mDNSlocal xpc_object_t SendDict_GetReply(xpc_object_t msg)
-{
- // Create empty dictionary
- __block xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- if (!dict) return NULL;
- xpc_retain(dict);
-
- HelperLog("SendDict_GetReply Sending msg to Daemon", msg);
+ // If we insist on using a semaphore timeout, then cancel the connection if the timeout is reached.
+ // This forces the reply block to be called if a reply wasn't received to keep things serialized.
+ xpc_connection_cancel(connection);
+ dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+ }
+ if (out_reply)
+ {
+ *out_reply = reply;
+ reply = NULL;
+ }
- dispatch_semaphore_t sem = dispatch_semaphore_create(0);
- dispatch_retain(sem); // for the block below
+ mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode);
- xpc_connection_send_message_with_reply(helper_xpc_conn, msg, HelperQueue, ^(xpc_object_t recv_msg)
+exit:
+ if (connection)
{
- xpc_type_t type = xpc_get_type(recv_msg);
-
- if (type == XPC_TYPE_DICTIONARY)
- {
- HelperLog("SendDict_GetReply Received reply msg from Daemon", recv_msg);
- uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus);
-
- switch (reply_status)
- {
- case kHelperReply_ACK:
- mDNSHELPER_DEBUG("NoError: successful reply");
- break;
- default:
- LogMsg("default: Unexpected reply from Helper");
- break;
- }
- // Copy result into dict reply
- xpc_dictionary_apply(recv_msg, ^bool(const char *key, xpc_object_t value)
- {
- xpc_dictionary_set_value(dict, key, value);
- return true;
- });
- }
- else
- {
- LogMsg("SendDict_GetReply Received unexpected reply from daemon [%s]",
- xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION));
- HelperLog("SendDict_GetReply Unexpected Reply contents", recv_msg);
- }
-
- dispatch_semaphore_signal(sem);
- dispatch_release(sem);
- xpc_release(dict);
-
- });
-
- if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0)
+ xpc_connection_cancel(connection);
+ xpc_release(connection);
+ }
+ if (sem)
{
- LogMsg("SendDict_GetReply: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait");
- xpc_release(dict);
dispatch_release(sem);
-
- return NULL;
}
-
- dispatch_release(sem);
-
- return dict;
+ if (reply)
+ {
+ xpc_release(reply);
+ }
+ return errorcode;
}
//**************************************************************************************************************
mDNSHELPER_DEBUG("mDNSPreferencesSetName: XPC IPC Test oldname %s newname %s", names.oldname, names.newname);
- Init_Connection(kHelperService);
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(dict, kPrefsOldName, names.oldname);
xpc_dictionary_set_string(dict, kPrefsNewName, names.newname);
- SendDict_ToServer(dict);
+ SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
void mDNSRequestBPF()
{
mDNSHELPER_DEBUG("mDNSRequestBPF: Using XPC IPC");
- Init_Connection(kHelperService);
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, kHelperMode, bpf_request);
- SendDict_ToServer(dict);
+ SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
int err_code = kHelperErr_NotConnected;
mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC calling out to Helper key is [%d] interval is [%d]", key, interval);
- Init_Connection(kHelperService);
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, "powerreq_key", key);
xpc_dictionary_set_uint64(dict, "powerreq_interval", interval);
- err_code = SendDict_ToServer(dict);
+ err_code = SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC calling out to Helper: ifindex is [%d] family is [%d]", ifindex, family);
- Init_Connection(kHelperService);
-
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, kHelperMode, set_localaddr_cacheentry);
xpc_dictionary_set_data(dict, "slace_ip", (uint8_t*)ip, sizeof(v6addr_t));
xpc_dictionary_set_data(dict, "slace_eth", (uint8_t*)eth, sizeof(ethaddr_t));
- err_code = SendDict_ToServer(dict);
+ err_code = SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text
{
mDNSHELPER_DEBUG("mDNSNotify() calling out to Helper XPC IPC title[%s] msg[%s]", title, msg);
-
- Init_Connection(kHelperService);
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_string(dict, "notify_title", title);
xpc_dictionary_set_string(dict, "notify_msg", msg);
- SendDict_ToServer(dict);
+ SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
CFPropertyListRef plist = NULL;
CFDataRef bytes = NULL;
unsigned int numsecrets = 0;
- unsigned int secretsCnt = 0;
+ size_t secretsCnt = 0;
int error_code = kHelperErr_NotConnected;
xpc_object_t reply_dict = NULL;
const void *sec = NULL;
- size_t secrets_size = 0;
mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper");
- Init_Connection(kHelperService);
-
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, kHelperMode, keychain_getsecrets);
- reply_dict = SendDict_GetReply(dict);
+ SendDict_ToServer(dict, &reply_dict);
if (reply_dict != NULL)
{
numsecrets = xpc_dictionary_get_uint64(reply_dict, "keychain_num_secrets");
- sec = xpc_dictionary_get_data(reply_dict, "keychain_secrets", &secrets_size);
- secretsCnt = xpc_dictionary_get_uint64(reply_dict, "keychain_secrets_count");
+ sec = xpc_dictionary_get_data(reply_dict, "keychain_secrets", &secretsCnt);
error_code = xpc_dictionary_get_int64(reply_dict, kHelperErrCode);
}
- mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper: numsecrets is %d, secretsCnt is %d error_code is %d secret_size is %d",
- numsecrets, secretsCnt, error_code, secrets_size);
+ mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper: numsecrets is %u, secretsCnt is %u error_code is %d",
+ numsecrets, (unsigned int)secretsCnt, error_code);
if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)sec, secretsCnt, kCFAllocatorNull)))
{
return error_code;
}
-
-int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
- v6addr_t local_outer, short local_port, v6addr_t remote_inner,
- v6addr_t remote_outer, short remote_port, const char* const prefix, const domainname *const fqdn)
-{
-
- int err_code = kHelperErr_NotConnected;
-
- mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC calling out to Helper. Parameters are repdel[%d], lport[%d], rport[%d], prefix[%s], fqdn[%##s]",
- replacedelete, local_port, remote_port, prefix, fqdn->c);
-
-
- char buf1[INET6_ADDRSTRLEN];
- char buf2[INET6_ADDRSTRLEN];
- char buf3[INET6_ADDRSTRLEN];
- char buf4[INET6_ADDRSTRLEN];
-
- buf1[0] = 0;
- buf2[0] = 0;
- buf3[0] = 0;
- buf4[0] = 0;
-
- inet_ntop(AF_INET6, local_inner, buf1, sizeof(buf1));
- inet_ntop(AF_INET6, local_outer, buf2, sizeof(buf2));
- inet_ntop(AF_INET6, remote_inner, buf3, sizeof(buf3));
- inet_ntop(AF_INET6, remote_outer, buf4, sizeof(buf4));
-
- char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10] = { 0 }; // Assume the prefix is no larger than 10 chars
- if (fqdn)
- {
- mDNSPlatformStrCopy(fqdnStr, prefix);
- ConvertDomainNameToCString(fqdn, fqdnStr + mDNSPlatformStrLen(prefix));
- }
-
- mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC calling out to Helper: Parameters are local_inner is %s, local_outeris %s, remote_inner is %s, remote_outer is %s",
- buf1, buf2, buf3, buf4);
-
- Init_Connection(kHelperService);
-
- // Create Dictionary To Send
- xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
- xpc_dictionary_set_uint64(dict, kHelperMode, autotunnel_setkeys);
-
- xpc_dictionary_set_data(dict, "autotunnelsetkeys_localinner", (uint8_t*)local_inner, sizeof(v6addr_t));
- xpc_dictionary_set_data(dict, "autotunnelsetkeys_localouter", (uint8_t*)local_outer, sizeof(v6addr_t));
- xpc_dictionary_set_data(dict, "autotunnelsetkeys_remoteinner", (uint8_t*)remote_inner, sizeof(v6addr_t));
- xpc_dictionary_set_data(dict, "autotunnelsetkeys_remoteouter", (uint8_t*)remote_outer, sizeof(v6addr_t));
-
- xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_lport", local_port);
- xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_rport", remote_port);
- xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_repdel", replacedelete);
-
- // xpc_dictionary_set_string(dict, "autotunnelsetkeys_prefix", prefix);
- xpc_dictionary_set_string(dict, "autotunnelsetkeys_fqdnStr", fqdnStr);
-
- err_code = SendDict_ToServer(dict);
-
- xpc_release(dict);
- dict = NULL;
-
- mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC returning error_code %d", err_code);
-
- mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: this should NOT be done in mDNSResponder/Helper. For future we shall be using <rdar://problem/13792729>");
- return err_code;
-}
-
void mDNSSendWakeupPacket(unsigned int ifid, char *eth_addr, char *ip_addr, int iteration)
{
// (void) ip_addr; // unused
mDNSHELPER_DEBUG("mDNSSendWakeupPacket: Entered ethernet address[%s],ip_address[%s], interface_id[%d], iteration[%d]",
eth_addr, ip_addr, ifid, iteration);
- Init_Connection(kHelperService);
-
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, kHelperMode, send_wakepkt);
xpc_dictionary_set_string(dict, "ip_address", ip_addr);
xpc_dictionary_set_uint64(dict, "swp_iteration", iteration);
- SendDict_ToServer(dict);
+ SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
mDNSPlatformMemCopy(pfa.protocolArray, protocolArray, sizeof(pfArray_t));
mDNSHELPER_DEBUG("mDNSPacketFilterControl: XPC IPC, ifname %s", ifname);
- Init_Connection(kHelperService);
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, "pf_opcode", command);
if (ifname)
xpc_dictionary_set_string(dict, "pf_ifname", ifname);
- xpc_dictionary_set_uint64(dict, "pf_count", count);
-
- xpc_dictionary_set_uint64(dict, "pf_port0", pfa.portArray[0]);
- xpc_dictionary_set_uint64(dict, "pf_port1", pfa.portArray[1]);
- xpc_dictionary_set_uint64(dict, "pf_port2", pfa.portArray[2]);
- xpc_dictionary_set_uint64(dict, "pf_port3", pfa.portArray[3]);
-
- xpc_dictionary_set_uint64(dict, "pf_protocol0", pfa.protocolArray[0]);
- xpc_dictionary_set_uint64(dict, "pf_protocol1", pfa.protocolArray[1]);
- xpc_dictionary_set_uint64(dict, "pf_protocol2", pfa.protocolArray[2]);
- xpc_dictionary_set_uint64(dict, "pf_protocol3", pfa.protocolArray[3]);
- SendDict_ToServer(dict);
+
+ xpc_object_t xpc_obj_portArray = xpc_array_create(NULL, 0);
+ xpc_object_t xpc_obj_protocolArray = xpc_array_create(NULL, 0);
+
+ for (size_t i = 0; i < count && i < PFPortArraySize; i++) {
+ xpc_array_set_uint64(xpc_obj_portArray, XPC_ARRAY_APPEND, pfa.portArray[i]);
+ xpc_array_set_uint64(xpc_obj_protocolArray, XPC_ARRAY_APPEND, pfa.protocolArray[i]);
+ }
+ xpc_dictionary_set_value(dict, "xpc_obj_array_port", xpc_obj_portArray);
+ xpc_dictionary_set_value(dict, "xpc_obj_array_protocol", xpc_obj_protocolArray);
+ xpc_release(xpc_obj_portArray);
+ xpc_release(xpc_obj_protocolArray);
+
+ SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
inet_ntop(AF_INET6, dadd, buf2, sizeof(buf2));
mDNSHELPER_DEBUG("mDNSSendKeepalive: Using XPC IPC calling out to Helper: sadd is %s, dadd is %s", buf1, buf2);
- Init_Connection(kHelperService);
-
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, kHelperMode, send_keepalive);
xpc_dictionary_set_uint64(dict, "send_keepalive_ack", ack);
xpc_dictionary_set_uint64(dict, "send_keepalive_win", win);
- SendDict_ToServer(dict);
+ SendDict_ToServer(dict, NULL);
xpc_release(dict);
dict = NULL;
inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2));
mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo:: Using XPC IPC calling out to Helper: laddr is %s, raddr is %s", buf1, buf2);
- Init_Connection(kHelperService);
-
// Create Dictionary To Send
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
xpc_dictionary_set_uint64(dict, kHelperMode, retreive_tcpinfo);
xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_lport", lport);
xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_rport", rport);
- reply_dict = SendDict_GetReply(dict);
+ SendDict_ToServer(dict, &reply_dict);
if (reply_dict != NULL)
{
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2007-2019 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.
#include "mDNSEmbeddedAPI.h"
#include "dns_sd.h"
#include "dnssd_ipc.h"
-#include "libpfkey.h"
#include "helper.h"
#include "helper-server.h"
#include "P2PPacketFilter.h"
#define RTF_IFSCOPE 0x1000000
#endif
-#if TARGET_OS_EMBEDDED
-#ifndef MDNS_NO_IPSEC
-#define MDNS_NO_IPSEC 1
-#endif
-
+#if TARGET_OS_IPHONE
#define NO_CFUSERNOTIFICATION 1
#define NO_SECURITYFRAMEWORK 1
#endif
formatNotDNSKey,
formatDdnsTypeItem,
formatDnsPrefixedServiceItem,
-#if MDNSRESPONDER_BTMM_SUPPORT
- formatBtmmPrefixedServiceItem
-#endif
};
// On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
#ifndef NO_SECURITYFRAMEWORK
-#if MDNSRESPONDER_BTMM_SUPPORT
-static const char btmmprefix[] = "btmmdns:";
-#endif
static const char dnsprefix[] = "dns:";
static const char ddns[] = "ddns";
static const char ddnsrev[] = "sndd";
}
if (attributes->attr[1].length >= sizeof(dnsprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, dnsprefix, sizeof(dnsprefix)-1))
format = formatDnsPrefixedServiceItem;
-#if MDNSRESPONDER_BTMM_SUPPORT
- else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1))
- format = formatBtmmPrefixedServiceItem;
-#endif
else if (attributes->attr[0].length == sizeof(ddns)-1 && 0 == strncasecmp(attributes->attr[0].data, ddns, sizeof(ddns)-1))
format = formatDdnsTypeItem;
else if (attributes->attr[0].length == sizeof(ddnsrev)-1 && 0 == strncasecmp(attributes->attr[0].data, ddnsrev, sizeof(ddnsrev)-1))
data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
break;
case formatDnsPrefixedServiceItem:
-#if MDNSRESPONDER_BTMM_SUPPORT
- case formatBtmmPrefixedServiceItem:
-#endif
data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
break;
default:
*err = KERN_SUCCESS;
}
-
-#ifndef MDNS_NO_IPSEC
-
-static const char configHeader[] = "# BackToMyMac\n";
-static const char g_racoon_config_dir[] = "/var/run/racoon/";
-static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
-
-static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
-{
- int major = 0, minor = 0;
- char letter = 0, buildver[256]="<Unknown>";
- CFDictionaryRef vers = _CFCopySystemVersionDictionary();
- if (vers)
- {
- CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
- if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
- sscanf(buildver, "%d%c%d", &major, &letter, &minor);
- CFRelease(vers);
- }
- else
- os_log_info(log_handle, "_CFCopySystemVersionDictionary failed");
-
- if (!major) { major=16; letter = 'A'; minor = 300; os_log_info(log_handle, "Note: No Major Build Version number found; assuming 16A300"); }
- if (letter_out) *letter_out = letter;
- if (minor_out) *minor_out = minor;
- return(major);
-}
-
-static int UseOldRacoon()
-{
- static int g_oldRacoon = -1;
-
- if (g_oldRacoon == -1)
- {
- char letter = 0;
- int minor = 0;
- g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
- os_log_debug(log_handle, "%s", g_oldRacoon ? "old" : "new");
- }
-
- return g_oldRacoon;
-}
-
-static int RacoonSignal()
-{
- return UseOldRacoon() ? SIGHUP : SIGUSR1;
-}
-
-static int notifyRacoon(void)
-{
- os_log_debug(log_handle,"entry");
- static const char racoon_pid_path[] = "/var/run/racoon.pid";
- char buf[] = "18446744073709551615"; /* largest 64-bit integer */
- char *p = NULL;
- ssize_t n = 0;
- unsigned long m = 0;
- int fd = open(racoon_pid_path, O_RDONLY);
-
- if (0 > fd)
- {
- os_log_debug(log_handle,"open \"%s\" failed, and that's OK: %s", racoon_pid_path,
- strerror(errno));
- return kHelperErr_RacoonNotificationFailed;
- }
- n = read(fd, buf, sizeof(buf)-1);
- close(fd);
- if (1 > n)
- {
- os_log_debug(log_handle,"read of \"%s\" failed: %s", racoon_pid_path,
- n == 0 ? "empty file" : strerror(errno));
- return kHelperErr_RacoonNotificationFailed;
- }
- buf[n] = '\0';
- m = strtoul(buf, &p, 10);
- if (*p != '\0' && !isspace(*p))
- {
- os_log_debug(log_handle,"invalid PID \"%s\" (around '%c')", buf, *p);
- return kHelperErr_RacoonNotificationFailed;
- }
- if (2 > m)
- {
- os_log_debug(log_handle,"refusing to kill PID %lu", m);
- return kHelperErr_RacoonNotificationFailed;
- }
- if (0 != kill(m, RacoonSignal()))
- {
- os_log_debug(log_handle,"Could not signal racoon (%lu): %s", m, strerror(errno));
- return kHelperErr_RacoonNotificationFailed;
- }
-
- os_log_debug(log_handle, "Sent racoon (%lu) signal %d", m, RacoonSignal());
- return 0;
-}
-
-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 void closefds(int from)
-{
- int fd = 0;
- struct dirent entry, *entryp = NULL;
- DIR *dirp = opendir("/dev/fd");
-
- if (dirp == NULL)
- {
- /* fall back to the erroneous getdtablesize method */
- for (fd = from; fd < getdtablesize(); ++fd)
- close(fd);
- return;
- }
- while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
- {
- fd = atoi(entryp->d_name);
- if (fd >= from && fd != dirfd(dirp))
- close(fd);
- }
- closedir(dirp);
-}
-
-
-static int startRacoonOld(void)
-{
- os_log_debug(log_handle,"entry");
- char * const racoon_args[] = { "/usr/sbin/racoon", "-e", NULL };
- ssize_t n = 0;
- pid_t pid = 0;
- int status = 0;
-
- if (0 == (pid = fork()))
- {
- closefds(0);
- execve(racoon_args[0], racoon_args, NULL);
- os_log_info(log_handle, "execve of \"%s\" failed: %s",
- racoon_args[0], strerror(errno));
- exit(2);
- }
- os_log_info(log_handle,"racoon (pid=%lu) started",
- (unsigned long)pid);
- n = waitpid(pid, &status, 0);
- if (-1 == n)
- {
- os_log(log_handle, "Unexpected waitpid failure: %s",
- strerror(errno));
- return kHelperErr_RacoonStartFailed;
- }
- else if (pid != n)
- {
- os_log(log_handle, "Unexpected waitpid return value %d", (int)n);
- return kHelperErr_RacoonStartFailed;
- }
- else if (WIFSIGNALED(status))
- {
- os_log(log_handle,
- "racoon (pid=%lu) terminated due to signal %d",
- (unsigned long)pid, WTERMSIG(status));
- return kHelperErr_RacoonStartFailed;
- }
- else if (WIFSTOPPED(status))
- {
- os_log(log_handle,
- "racoon (pid=%lu) has stopped due to signal %d",
- (unsigned long)pid, WSTOPSIG(status));
- return kHelperErr_RacoonStartFailed;
- }
- else if (0 != WEXITSTATUS(status))
- {
- os_log(log_handle,
- "racoon (pid=%lu) exited with status %d",
- (unsigned long)pid, WEXITSTATUS(status));
- return kHelperErr_RacoonStartFailed;
- }
- os_log_debug(log_handle, "racoon (pid=%lu) daemonized normally", (unsigned long)pid);
- return 0;
-}
-
-// constant and structure for the racoon control socket
-#define VPNCTL_CMD_PING 0x0004
-typedef struct vpnctl_hdr_struct
-{
- u_int16_t msg_type;
- u_int16_t flags;
- u_int32_t cookie;
- u_int32_t reserved;
- u_int16_t result;
- u_int16_t len;
-} vpnctl_hdr;
-
-static int startRacoon(void)
-{
- os_log_debug(log_handle,"entry");
- int fd = socket(PF_UNIX, SOCK_STREAM, 0);
- if (0 > fd)
- {
- os_log(log_handle,"Could not create endpoint for racoon control socket: %d %s",
- errno, strerror(errno));
- return kHelperErr_RacoonStartFailed;
- }
-
- 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)
- {
- os_log(log_handle, "Could not connect racoon control socket %s: %d %s",
- racoon_control_sock_path, errno, strerror(errno));
- return kHelperErr_RacoonStartFailed;
- }
-
- u_int32_t btmm_cookie = 0x4d4d5442;
- vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
- size_t bytes = 0;
- ssize_t ret = 0;
-
- while (bytes < sizeof(vpnctl_hdr))
- {
- ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
- if (ret == -1)
- {
- os_log(log_handle, "Could not write to racoon control socket: %d %s", errno, strerror(errno));
- return kHelperErr_RacoonStartFailed;
- }
- bytes += ret;
- }
-
- int nfds = fd + 1;
- fd_set fds;
- int counter = 0;
- struct timeval tv;
- bytes = 0;
- h.cookie = 0;
-
- for (counter = 0; counter < 100; counter++)
- {
- FD_ZERO(&fds);
- FD_SET(fd, &fds);
- tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
-
- result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
- if (result > 0)
- {
- if (FD_ISSET(fd, &fds))
- {
- ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
-
- if (ret == -1)
- {
- os_log(log_handle,"Could not read from racoon control socket: %d %s", errno, strerror(errno));
- break;
- }
- bytes += ret;
- if (bytes >= sizeof(vpnctl_hdr)) break;
- }
- else
- {
- os_log_debug(log_handle, "select returned but fd_isset not on expected fd");
- }
- }
- else if (result < 0)
- {
- const int select_errno = errno;
- os_log_debug(log_handle, "select returned %d errno %d %s", result, select_errno, strerror(select_errno));
- if (select_errno != EINTR) break;
- }
- }
-
- close(fd);
-
- if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie)
- return kHelperErr_RacoonStartFailed;
-
- os_log_debug(log_handle, "racoon started");
- return 0;
-}
-
-static int kickRacoon(void)
-{
- if ( 0 == notifyRacoon() )
- return 0;
- return UseOldRacoon() ? startRacoonOld() : startRacoon();
-}
-
-typedef enum _mDNSTunnelPolicyWhich
-{
- kmDNSTunnelPolicySetup,
- kmDNSTunnelPolicyTeardown,
- kmDNSTunnelPolicyGenerate
-} mDNSTunnelPolicyWhich;
-
-// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
-// kmDNSNoTunnel is used for other Policy types
-typedef enum _mDNSTunnelType
-{
- kmDNSNoTunnel,
- kmDNSIPv6IPv4Tunnel,
- kmDNSIPv6IPv6Tunnel
-} mDNSTunnelType;
-
-static const uint8_t kWholeV6Mask = 128;
-
-static unsigned int routeSeq = 1;
-
-static int setupTunnelRoute(const v6addr_t local, const v6addr_t remote)
-{
- struct
- {
- struct rt_msghdr hdr;
- struct sockaddr_in6 dst;
- struct sockaddr_in6 gtwy;
- } msg;
- int err = 0;
- int s = -1;
-
- if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
- {
- os_log(log_handle,"socket(PF_ROUTE, ...) failed: %s", strerror(errno));
-
- err = kHelperErr_RoutingSocketCreationFailed;
- goto fin;
- }
-
- memset(&msg, 0, sizeof(msg));
- msg.hdr.rtm_msglen = sizeof(msg);
- msg.hdr.rtm_type = RTM_ADD;
- /* The following flags are set by `route add -inet6 -host ...` */
- msg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC;
- msg.hdr.rtm_version = RTM_VERSION;
- msg.hdr.rtm_seq = routeSeq++;
- msg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
- msg.hdr.rtm_inits = RTV_MTU;
- msg.hdr.rtm_rmx.rmx_mtu = 1280;
-
- msg.dst.sin6_len = sizeof(msg.dst);
- msg.dst.sin6_family = AF_INET6;
- memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
-
- msg.gtwy.sin6_len = sizeof(msg.gtwy);
- msg.gtwy.sin6_family = AF_INET6;
- memcpy(&msg.gtwy.sin6_addr, local, sizeof(msg.gtwy.sin6_addr));
-
- /* send message, ignore error when route already exists */
- if (0 > write(s, &msg, msg.hdr.rtm_msglen))
- {
- const int errno_ = errno;
-
- os_log_info(log_handle,"write to routing socket failed: %s", strerror(errno_));
- if (EEXIST != errno_)
- {
- err = kHelperErr_RouteAdditionFailed;
- goto fin;
- }
- }
-
-fin:
- if (0 <= s)
- close(s);
- return err;
-}
-
-static int teardownTunnelRoute(const v6addr_t remote)
-{
- struct
- {
- struct rt_msghdr hdr;
- struct sockaddr_in6 dst;
- } msg;
- int err = 0;
- int s = -1;
-
- if (0 > (s = socket(PF_ROUTE, SOCK_RAW, AF_INET)))
- {
- os_log(log_handle, "socket(PF_ROUTE, ...) failed: %s", strerror(errno));
- err = kHelperErr_RoutingSocketCreationFailed;
- goto fin;
- }
- memset(&msg, 0, sizeof(msg));
-
- msg.hdr.rtm_msglen = sizeof(msg);
- msg.hdr.rtm_type = RTM_DELETE;
- msg.hdr.rtm_version = RTM_VERSION;
- msg.hdr.rtm_seq = routeSeq++;
- msg.hdr.rtm_addrs = RTA_DST;
-
- msg.dst.sin6_len = sizeof(msg.dst);
- msg.dst.sin6_family = AF_INET6;
- memcpy(&msg.dst.sin6_addr, remote, sizeof(msg.dst.sin6_addr));
- if (0 > write(s, &msg, msg.hdr.rtm_msglen))
- {
- const int errno_ = errno;
-
- os_log_debug(log_handle,"write to routing socket failed: %s", strerror(errno_));
-
- if (ESRCH != errno_)
- {
- err = kHelperErr_RouteDeletionFailed;
- goto fin;
- }
- }
-
-fin:
- if (0 <= s)
- close(s);
- return err;
-}
-
-static int v4addr_to_string(v4addr_t addr, char *buf, size_t buflen)
-{
- if (NULL == inet_ntop(AF_INET, addr, buf, buflen))
- {
- os_log(log_handle, "v4addr_to_string() inet_ntop failed: %s", strerror(errno));
- return kHelperErr_InvalidNetworkAddress;
- }
- else
- {
- return 0;
- }
-}
-
-static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
-{
- if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
- {
- os_log(log_handle, "v6addr_to_string inet_ntop failed: %s", strerror(errno));
- return kHelperErr_InvalidNetworkAddress;
- }
- else
- {
- return 0;
- }
-}
-
-static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
-{
- struct stat s;
- int ret = stat(racoon_config_dir, &s);
- if (ret != 0)
- {
- if (errno != ENOENT)
- {
- os_log(log_handle, "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)
- {
- os_log(log_handle, "mkdir \"%s\" failed: %s",
- racoon_config_dir, strerror(errno));
- return -1;
- }
- else
- {
- os_log_info(log_handle, "created directory \"%s\"", racoon_config_dir);
- }
- }
- }
- else if (!(s.st_mode & S_IFDIR))
- {
- os_log(log_handle, "\"%s\" is not a directory!",
- racoon_config_dir);
- return -1;
- }
-
- return 0;
-}
-
-
-
-/* Caller owns object returned in `policy' */
-static int generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
- v4addr_t src, uint16_t src_port,
- v4addr_t dst, uint16_t dst_port,
- const v6addr_t src6, const v6addr_t dst6,
- ipsec_policy_t *policy, size_t *len)
-{
- char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
- char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
- char buf[512];
- char *inOut = in ? "in" : "out";
- ssize_t n = 0;
- int err = 0;
-
- *policy = NULL;
- *len = 0;
-
- switch (which)
- {
- case kmDNSTunnelPolicySetup:
- if (type == kmDNSIPv6IPv4Tunnel)
- {
- if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
- goto fin;
- if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
- goto fin;
- n = snprintf(buf, sizeof(buf),
- "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
- inOut, srcs, src_port, dsts, dst_port);
- }
- else if (type == kmDNSIPv6IPv6Tunnel)
- {
- if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
- goto fin;
- if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
- goto fin;
- n = snprintf(buf, sizeof(buf),
- "%s ipsec esp/tunnel/%s-%s/require",
- inOut, srcs6, dsts6);
- }
- break;
- case kmDNSTunnelPolicyTeardown:
- n = strlcpy(buf, inOut, sizeof(buf));
- break;
- case kmDNSTunnelPolicyGenerate:
- n = snprintf(buf, sizeof(buf), "%s generate", inOut);
- break;
- default:
- err = kHelperErr_IPsecPolicyCreationFailed;
- goto fin;
- }
-
- if (n >= (int)sizeof(buf))
- {
- err = kHelperErr_ResultTooLarge;
- goto fin;
- }
-
- os_log_info(log_handle, "policy=\"%s\"", buf);
-
- if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
- {
- os_log_info(log_handle, "Could not create IPsec policy from \"%s\"", buf);
- err = kHelperErr_IPsecPolicyCreationFailed;
- goto fin;
- }
- *len = ((ipsec_policy_t)(*policy))->sadb_x_policy_len * 8;
-
-fin:
- return err;
-}
-
-static int sendPolicy(int s, int setup,
- struct sockaddr *src, uint8_t src_bits,
- struct sockaddr *dst, uint8_t dst_bits,
- ipsec_policy_t policy, size_t len)
-{
- static unsigned int policySeq = 0;
- int err = 0;
-
- os_log_debug(log_handle, "entry, setup=%d", setup);
-
- if (setup)
- err = pfkey_send_spdadd(s, src, src_bits, dst, dst_bits, -1,
- (char *)policy, len, policySeq++);
- else
- err = pfkey_send_spddelete(s, src, src_bits, dst, dst_bits, -1,
- (char *)policy, len, policySeq++);
-
- if (0 > err)
- {
- os_log(log_handle, "Could not set IPsec policy: %s", ipsec_strerror());
- err = kHelperErr_IPsecPolicySetFailed;
- goto fin;
- }
- else
- {
- err = 0;
- }
-
- os_log_debug(log_handle, "succeeded");
-
-fin:
- return err;
-}
-
-static int removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
-{
- int err = 0;
-
- os_log_debug(log_handle, "entry");
-
- err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
- if (0 > err)
- {
- os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
- err = kHelperErr_IPsecRemoveSAFailed;
- goto fin;
- }
- err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
- if (0 > err)
- {
- os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
- err = kHelperErr_IPsecRemoveSAFailed;
- goto fin;
- }
- else
- err = 0;
-
- os_log_debug(log_handle, "succeeded");
-
-fin:
- return err;
-}
-
-static int doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
- const v6addr_t loc_inner, uint8_t loc_bits,
- v4addr_t loc_outer, uint16_t loc_port,
- const v6addr_t rmt_inner, uint8_t rmt_bits,
- v4addr_t rmt_outer, uint16_t rmt_port,
- const v6addr_t loc_outer6, const v6addr_t rmt_outer6)
-{
- struct sockaddr_in6 sin6_loc;
- struct sockaddr_in6 sin6_rmt;
- ipsec_policy_t policy = NULL;
- size_t len = 0;
- int s = -1;
- int err = 0;
-
- os_log_debug(log_handle,"entry");
- if (0 > (s = pfkey_open()))
- {
- os_log(log_handle, "Could not create IPsec policy socket: %s", ipsec_strerror());
- err = kHelperErr_IPsecPolicySocketCreationFailed;
- goto fin;
- }
-
- memset(&sin6_loc, 0, sizeof(sin6_loc));
- sin6_loc.sin6_len = sizeof(sin6_loc);
- sin6_loc.sin6_family = AF_INET6;
- sin6_loc.sin6_port = htons(0);
- memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
-
- memset(&sin6_rmt, 0, sizeof(sin6_rmt));
- sin6_rmt.sin6_len = sizeof(sin6_rmt);
- sin6_rmt.sin6_family = AF_INET6;
- sin6_rmt.sin6_port = htons(0);
- memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
-
- int setup = which != kmDNSTunnelPolicyTeardown;
-
- if (0 != (err = generateTunnelPolicy(which, type, 1,
- rmt_outer, rmt_port,
- loc_outer, loc_port,
- rmt_outer6, loc_outer6,
- &policy, &len)))
- goto fin;
-
- if (0 != (err = sendPolicy(s, setup,
- (struct sockaddr *)&sin6_rmt, rmt_bits,
- (struct sockaddr *)&sin6_loc, loc_bits,
- policy, len)))
- goto fin;
-
- if (NULL != policy)
- {
- free(policy);
- policy = NULL;
- }
-
- if (0 != (err = generateTunnelPolicy(which, type, 0,
- loc_outer, loc_port,
- rmt_outer, rmt_port,
- loc_outer6, rmt_outer6,
- &policy, &len)))
- goto fin;
- if (0 != (err = sendPolicy(s, setup,
- (struct sockaddr *)&sin6_loc, loc_bits,
- (struct sockaddr *)&sin6_rmt, rmt_bits,
- policy, len)))
- goto fin;
-
- if (which == kmDNSTunnelPolicyTeardown)
- {
- if (rmt_port) // Outer tunnel is IPv4
- {
- if (loc_outer && rmt_outer)
- {
- struct sockaddr_in sin_loc;
- struct sockaddr_in sin_rmt;
- memset(&sin_loc, 0, sizeof(sin_loc));
- sin_loc.sin_len = sizeof(sin_loc);
- sin_loc.sin_family = AF_INET;
- memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
-
- memset(&sin_rmt, 0, sizeof(sin_rmt));
- sin_rmt.sin_len = sizeof(sin_rmt);
- sin_rmt.sin_family = AF_INET;
- memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
- if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
- goto fin;
- }
- }
- else
- {
- if (loc_outer6 && rmt_outer6)
- {
- struct sockaddr_in6 sin6_lo;
- struct sockaddr_in6 sin6_rm;
-
- memset(&sin6_lo, 0, sizeof(sin6_lo));
- sin6_lo.sin6_len = sizeof(sin6_lo);
- sin6_lo.sin6_family = AF_INET6;
- memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
-
- memset(&sin6_rm, 0, sizeof(sin6_rm));
- sin6_rm.sin6_len = sizeof(sin6_rm);
- sin6_rm.sin6_family = AF_INET6;
- memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
- if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
- goto fin;
- }
- }
- }
-
- os_log_debug(log_handle,"succeeded");
-
-fin:
- if (s >= 0)
- pfkey_close(s);
- if (NULL != policy)
- free(policy);
- return err;
-}
-
-#endif /* ndef MDNS_NO_IPSEC */
-
-int HelperAutoTunnelSetKeys(int replacedelete, const v6addr_t loc_inner, const v6addr_t loc_outer6, uint16_t loc_port, const v6addr_t rmt_inner,
- const v6addr_t rmt_outer6, uint16_t rmt_port, const char *id, int *err)
-{
-#ifndef MDNS_NO_IPSEC
- static const char config[] =
- "%s"
- "remote %s [%u] {\n"
- " disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
- " exchange_mode aggressive;\n"
- " doi ipsec_doi;\n"
- " situation identity_only;\n"
- " verify_identifier off;\n"
- " generate_policy on;\n"
- " my_identifier user_fqdn \"%s\";\n"
- " shared_secret keychain \"%s\";\n"
- " nonce_size 16;\n"
- " lifetime time 15 min;\n"
- " initial_contact on;\n"
- " support_proxy on;\n"
- " nat_traversal force;\n"
- " proposal_check claim;\n"
- " proposal {\n"
- " encryption_algorithm aes;\n"
- " hash_algorithm sha256;\n"
- " authentication_method pre_shared_key;\n"
- " dh_group 2;\n"
- " lifetime time 15 min;\n"
- " }\n"
- " proposal {\n"
- " encryption_algorithm aes;\n"
- " hash_algorithm sha1;\n"
- " authentication_method pre_shared_key;\n"
- " dh_group 2;\n"
- " lifetime time 15 min;\n"
- " }\n"
- "}\n\n"
- "sainfo address %s any address %s any {\n"
- " pfs_group 2;\n"
- " lifetime time 10 min;\n"
- " encryption_algorithm aes;\n"
- " authentication_algorithm hmac_sha256,hmac_sha1;\n"
- " compression_algorithm deflate;\n"
- "}\n\n"
- "sainfo address %s any address %s any {\n"
- " pfs_group 2;\n"
- " lifetime time 10 min;\n"
- " encryption_algorithm aes;\n"
- " authentication_algorithm hmac_sha256,hmac_sha1;\n"
- " compression_algorithm deflate;\n"
- "}\n";
- char path[PATH_MAX] = "";
- char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
- ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
- FILE *fp = NULL;
- int fd = -1;
- char tmp_path[PATH_MAX] = "";
- v4addr_t loc_outer, rmt_outer;
-
- os_log_debug(log_handle,"HelperAutoTunnelSetKeys: entry");
- *err = kHelperErr_NoErr;
-
- char buf1[INET6_ADDRSTRLEN];
- char buf2[INET6_ADDRSTRLEN];
- char buf3[INET6_ADDRSTRLEN];
- char buf4[INET6_ADDRSTRLEN];
-
- buf1[0] = 0;
- buf2[0] = 0;
- buf3[0] = 0;
- buf4[0] = 0;
-
- inet_ntop(AF_INET6, loc_inner, buf1, sizeof(buf1));
- inet_ntop(AF_INET6, loc_outer6, buf2, sizeof(buf2));
- inet_ntop(AF_INET6, rmt_inner, buf3, sizeof(buf3));
- inet_ntop(AF_INET6, rmt_outer6, buf4, sizeof(buf4));
-
- os_log_info(log_handle, "HelperAutoTunnelSetKeys: Parameters are local_inner is %s, local_outer is %s, remote_inner is %s, remote_outer is %s id is %s",
- buf1, buf2, buf3, buf4, id);
-
- switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
- {
- case kmDNSAutoTunnelSetKeysReplace:
- case kmDNSAutoTunnelSetKeysDelete:
- break;
- default:
- *err = kHelperErr_InvalidTunnelSetKeysOperation;
- goto fin;
- }
-
- if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
- goto fin;
- if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
- goto fin;
-
- os_log_debug(log_handle, "loc_inner=%s rmt_inner=%s", li, ri);
-
- if (!rmt_port)
- {
- loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
- rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
-
- if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
- goto fin;
- if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
- goto fin;
-
- os_log_debug(log_handle, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
-
- if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.conf", GetRacoonConfigDir(), ro6))
- {
- *err = kHelperErr_ResultTooLarge;
- goto fin;
- }
- }
- else
- {
- loc_outer[0] = loc_outer6[0];
- loc_outer[1] = loc_outer6[1];
- loc_outer[2] = loc_outer6[2];
- loc_outer[3] = loc_outer6[3];
-
- rmt_outer[0] = rmt_outer6[0];
- rmt_outer[1] = rmt_outer6[1];
- rmt_outer[2] = rmt_outer6[2];
- rmt_outer[3] = rmt_outer6[3];
-
- if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
- goto fin;
- if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
- goto fin;
-
- os_log_debug(log_handle, "IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
- lo, loc_port, ro, rmt_port);
-
- if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.%u.conf", GetRacoonConfigDir(), ro, rmt_port))
- {
- *err = kHelperErr_ResultTooLarge;
- goto fin;
- }
- }
-
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
- {
- if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
- {
- *err = kHelperErr_RacoonConfigCreationFailed;
- goto fin;
- }
- if ((int)sizeof(tmp_path) <=
- snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
- {
- *err = kHelperErr_ResultTooLarge;
- goto fin;
- }
- if (0 > (fd = mkstemp(tmp_path)))
- {
- os_log(log_handle, "mkstemp \"%s\" failed: %s", tmp_path, strerror(errno));
- *err = kHelperErr_RacoonConfigCreationFailed;
- goto fin;
- }
- if (NULL == (fp = fdopen(fd, "w")))
- {
- os_log(log_handle, "fdopen: %s", strerror(errno));
- *err = kHelperErr_RacoonConfigCreationFailed;
- goto fin;
- }
-
- fd = -1;
- fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
- fclose(fp);
- fp = NULL;
-
- if (0 > rename(tmp_path, path))
- {
- os_log(log_handle, "rename \"%s\" \"%s\" failed: %s", tmp_path, path, strerror(errno));
- *err = kHelperErr_RacoonConfigCreationFailed;
- goto fin;
- }
- }
- else
- {
- if (0 != unlink(path))
- os_log_debug(log_handle, "unlink \"%s\" failed: %s", path, strerror(errno));
- }
-
- if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
- loc_inner, kWholeV6Mask, loc_outer, loc_port,
- rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
- goto fin;
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
- 0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
- loc_inner, kWholeV6Mask, loc_outer, loc_port,
- rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
- goto fin;
-
- if (0 != (*err = teardownTunnelRoute(rmt_inner)))
- goto fin;
-
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
- 0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
- goto fin;
-
- if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
- 0 != (*err = kickRacoon()))
- goto fin;
-
- os_log_debug(log_handle, "succeeded");
-
-fin:
- if (NULL != fp)
- fclose(fp);
- if (0 <= fd)
- close(fd);
- unlink(tmp_path);
-#else
- (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
- (void)rmt_outer6; (void)rmt_port; (void)id;
-
- *err = kHelperErr_IPsecDisabled;
-#endif /* MDNS_NO_IPSEC */
- update_idle_timer();
- return KERN_SUCCESS;
-}
-
-
-
-
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2019 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.
send_keepalive = 8,
retreive_tcpinfo = 9,
keychain_getsecrets = 10,
- autotunnel_setkeys = 11,
- request_other,
} HelperModes;
typedef enum
kHelperErr_RouteAdditionFailed = -17,
kHelperErr_RacoonStartFailed = -18,
kHelperErr_RacoonNotificationFailed = -19,
+ kHelperErr_ParamErr = -20,
} HelperErrorCodes;
kmDNSDown
};
-enum mDNSAutoTunnelSetKeysReplaceDelete
-{
- kmDNSAutoTunnelSetKeysReplace = 1,
- kmDNSAutoTunnelSetKeysDelete
-};
-
-
// helper parses the system keychain and returns the information to mDNSResponder.
// It returns four attributes. Attributes are defined after how they show up in
// keychain access utility (the actual attribute name to retrieve these are different).
extern void mDNSNotify(const char *title, const char *msg); // Both strings are UTF-8 text
extern void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new);
extern int mDNSKeychainGetSecrets(CFArrayRef *secrets);
-extern int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
- v6addr_t local_outer, short local_port, v6addr_t remote_inner,
- v6addr_t remote_outer, short remote_port, const char *const prefix, const domainname *const fqdn);
extern void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration);
extern void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray);
extern void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win);
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2015 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.
- */
-
-/* $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
-/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */
-
-/*
- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-extern int __ipsec_errcode;
-extern void __ipsec_set_strerror __P((const char *));
-
-#define EIPSEC_NO_ERROR 0 /*success*/
-#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/
-#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/
-#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/
-#define EIPSEC_INVAL_VERSION 4 /*invalid version*/
-#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/
-#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/
-#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/
-#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/
-#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/
-#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/
-#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/
-#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/
-#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/
-#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/
-#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/
-#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/
-#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/
-#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/
-#define EIPSEC_NO_PROTO 19 /*no protocol specified*/
-#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/
-#define EIPSEC_NO_BUFS 21 /*no buffers available*/
-#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/
-#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/
-#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/
-#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/
-#define EIPSEC_SYSTEM_ERROR 26 /*system error*/
-#define EIPSEC_MAX 27 /*unknown error*/
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2015 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.
- */
-
-/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
-/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej Exp $ */
-
-/*
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-struct sadb_msg;
-extern void pfkey_sadump __P((struct sadb_msg *));
-extern void pfkey_spdump __P((struct sadb_msg *));
-
-struct sockaddr;
-struct sadb_alg;
-int ipsec_check_keylen __P((u_int, u_int, u_int));
-int ipsec_check_keylen2 __P((u_int, u_int, u_int));
-int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *));
-u_int pfkey_set_softrate __P((u_int, u_int));
-u_int pfkey_get_softrate __P((u_int));
-int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
- struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
-int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
- struct sockaddr *, u_int32_t, u_int32_t, u_int,
- caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
- u_int64_t, u_int64_t, u_int32_t));
-int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
- struct sockaddr *, u_int32_t, u_int32_t, u_int,
- caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
- u_int64_t, u_int64_t, u_int32_t));
-int pfkey_send_delete __P((int, u_int, u_int,
- struct sockaddr *, struct sockaddr *, u_int32_t));
-int pfkey_send_delete_all __P((int, u_int, u_int,
- struct sockaddr *, struct sockaddr *));
-int pfkey_send_get __P((int, u_int, u_int,
- struct sockaddr *, struct sockaddr *, u_int32_t));
-int pfkey_send_register __P((int, u_int));
-int pfkey_recv_register __P((int));
-int pfkey_set_supported __P((struct sadb_msg *, int));
-int pfkey_send_flush __P((int, u_int));
-int pfkey_send_dump __P((int, u_int));
-int pfkey_send_promisc_toggle __P((int, int));
-int pfkey_send_spdadd __P((int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
-int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
- caddr_t, int, u_int32_t));
-int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
-int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
- caddr_t, int, u_int32_t));
-int pfkey_send_spddelete __P((int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
-int pfkey_send_spddelete2 __P((int, u_int32_t));
-int pfkey_send_spdget __P((int, u_int32_t));
-int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
-int pfkey_send_spdflush __P((int));
-int pfkey_send_spddump __P((int));
-
-int pfkey_open __P((void));
-void pfkey_close __P((int));
-struct sadb_msg *pfkey_recv __P((int));
-int pfkey_send __P((int, struct sadb_msg *, int));
-int pfkey_align __P((struct sadb_msg *, caddr_t *));
-int pfkey_check __P((caddr_t *));
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
#if TARGET_OS_IPHONE
#include <MobileWiFi/WiFiManagerClient.h> // For WiFiManagerClientRef etc, declarations.
#include <dlfcn.h>
-#include <os/variant_private.h> // For os_variant_has_internal_diagnostics().
#endif // TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
+#include "system_utilities.h" // For os_variant_has_internal_diagnostics().
+#endif
+
// Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
#include <Kernel/IOKit/apple80211/apple80211_var.h>
-#if MDNSRESPONDER_BTMM_SUPPORT
-#include <AWACS.h>
-#endif
-
#if APPLE_OSX_mDNSResponder
#include <ne_session.h> // for ne_session_set_socket_attributes()
#endif
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
#include <IOKit/platform/IOPlatformSupportPrivate.h>
-#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#endif
#ifdef UNIT_TEST
#include "unittest.h"
static CFStringRef NetworkChangedKey_StateInterfacePrefix;
static CFStringRef NetworkChangedKey_DynamicDNS = CFSTR("Setup:/Network/DynamicDNS");
static CFStringRef NetworkChangedKey_PowerSettings = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
-#if MDNSRESPONDER_BTMM_SUPPORT
-static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
-static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
-#endif
static char HINFO_HWstring_buffer[32];
static char *HINFO_HWstring = "Device";
dispatch_queue_t SSLqueue;
-#if TARGET_OS_EMBEDDED
-#define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
-#endif
-
#if APPLE_OSX_mDNSResponder
static mDNSu8 SPMetricPortability = 99;
static mDNSu8 SPMetricMarginalPower = 99;
static mDNSu8 SPMetricTotalPower = 99;
static mDNSu8 SPMetricFeatures = 1; /* The current version supports TCP Keep Alive Feature */
-mDNSexport domainname ActiveDirectoryPrimaryDomain;
-mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
-mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
#endif // APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+domainname ActiveDirectoryPrimaryDomain;
+static int ActiveDirectoryPrimaryDomainLabelCount;
+static mDNSAddr ActiveDirectoryPrimaryDomainServer;
+#endif
+
// Don't send triggers too often. We arbitrarily limit it to three minutes.
#define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
-// Used by AutoTunnel
-const char btmmprefix[] = "btmmdns:";
const char dnsprefix[] = "dns:";
// String Array used to write list of private domains to Dynamic Store
// 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.
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
#define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
#else
#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
#endif
#define SPSInterface(i) ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
+mDNSlocal void SetNetworkChanged(mDNSs32 delay);
+
mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
{
// Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
}
// Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
mDNSexport void LogMemCorruption(const char *format, ...)
{
char buffer[512];
// Returns true if it is an AppleTV based hardware running iOS, false otherwise
mDNSlocal mDNSBool IsAppleTV(void)
{
-#if TARGET_OS_EMBEDDED
- static mDNSBool sInitialized = mDNSfalse;
- static mDNSBool sIsAppleTV = mDNSfalse;
- CFStringRef deviceClass = NULL;
-
- if(!sInitialized)
- {
- deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
- if(deviceClass)
- {
- if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
- sIsAppleTV = mDNStrue;
- CFRelease(deviceClass);
- }
- sInitialized = mDNStrue;
- }
- return(sIsAppleTV);
+#if TARGET_OS_TV
+ return mDNStrue;
#else
return mDNSfalse;
-#endif // TARGET_OS_EMBEDDED
+#endif
}
mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
return mDNSNULL;
}
+mDNSexport mdns_interface_monitor_t GetInterfaceMonitorForIndex(uint32_t ifIndex)
+{
+ mDNS *const m = &mDNSStorage;
+
+ // We assume that interface should always be real interface, and should never be 0.
+ if (ifIndex == 0) return NULL;
+
+ if (!m->p->InterfaceMonitors)
+ {
+ m->p->InterfaceMonitors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
+ if (!m->p->InterfaceMonitors)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Failed to create InterfaceMonitors array");
+ return NULL;
+ }
+ }
+
+ // Search for interface monitor given the interface index.
+ mdns_interface_monitor_t monitor;
+ for (CFIndex i = 0, n = CFArrayGetCount(m->p->InterfaceMonitors); i < n; i++)
+ {
+ monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, i);
+ if (mdns_interface_monitor_get_interface_index(monitor) == ifIndex) return monitor;
+ }
+
+ // If we come here, it means the interface is a new interface that needs to be monitored.
+ monitor = mdns_interface_monitor_create(ifIndex);
+ if (!monitor)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Failed to create an interface monitor for index %u", ifIndex);
+ return NULL;
+ }
+ CFArrayAppendValue(m->p->InterfaceMonitors, monitor);
+
+ // Put the monitor into serial queue.
+ mdns_interface_monitor_set_queue(monitor, dispatch_get_main_queue());
+
+ // When the interface configuration is changed, this block will be called.
+ mdns_interface_monitor_set_update_handler(monitor,
+ ^(mdns_interface_flags_t changeFlags)
+ {
+ const mdns_interface_flags_t relevantFlags =
+ mdns_interface_flag_expensive |
+ mdns_interface_flag_constrained |
+ mdns_interface_flag_clat46;
+ if ((changeFlags & relevantFlags) == 0) return;
+
+ KQueueLock();
+ const CFRange range = CFRangeMake(0, CFArrayGetCount(m->p->InterfaceMonitors));
+ if (CFArrayContainsValue(m->p->InterfaceMonitors, range, monitor))
+ {
+ m->p->if_interface_changed = mDNStrue;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "Monitored interface changed: %@", monitor);
+#endif
+ // Let mDNSResponder update its network configuration.
+ mDNS_Lock(m);
+ SetNetworkChanged((mDNSPlatformOneSecond + 39) / 40); // 25 ms delay
+ mDNS_Unlock(m);
+ }
+ KQueueUnlock("interface monitor update handler");
+ });
+
+ mdns_interface_monitor_set_event_handler(monitor,
+ ^(mdns_event_t event, OSStatus error)
+ {
+ switch (event)
+ {
+ case mdns_event_invalidated:
+ mdns_release(monitor);
+ break;
+
+ case mdns_event_error:
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Interface monitor for index %u error: %ld",
+ mdns_interface_monitor_get_interface_index(monitor), (long) error);
+ KQueueLock();
+ if (m->p->InterfaceMonitors)
+ {
+ const CFRange range = CFRangeMake(0, CFArrayGetCount(m->p->InterfaceMonitors));
+ const CFIndex i = CFArrayGetFirstIndexOfValue(m->p->InterfaceMonitors, range, monitor);
+ if (i >= 0) CFArrayRemoveValueAtIndex(m->p->InterfaceMonitors, i);
+ }
+ KQueueUnlock("interface monitor event handler");
+ mdns_interface_monitor_invalidate(monitor);
+ break;
+
+ default:
+ break;
+ }
+ });
+ mdns_interface_monitor_activate(monitor);
+
+ return monitor;
+}
+
mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
{
(void) m;
NetworkInterfaceInfoOSX *i;
if (id == mDNSInterface_Any ) return(0);
if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
- if (id == mDNSInterface_Unicast ) return(0);
if (id == mDNSInterface_P2P ) return(kDNSServiceInterfaceIndexP2P);
if (id == mDNSInterface_BLE ) return(kDNSServiceInterfaceIndexBLE);
}
#ifdef UNIT_TEST
-// Run the unit test main
UNITTEST_SETSOCKOPT
#else
mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
else if (transType == mDNSTransport_TCP)
{
TCPSocket* sock = (TCPSocket*) sockCxt;
- return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
+ return sock->fd;
}
else
{
int s = -1, err;
mStatus result = mStatus_NoError;
int sendto_errno;
+ const DNSMessage *const dns_msg = msg;
if (InterfaceID)
{
if (displayed < 1000)
{
displayed++;
- LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets",
+ mDNSVal16(dns_msg->h.id));
}
#endif
}
// a different machine that does not support it
if (err < 0)
{
- if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
+ if (errno != ENOPROTOOPT)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d",
+ mDNSVal16(dns_msg->h.id), errno);
+ }
err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
if (err < 0 && !m->NetworkChanged)
- LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] setsockopt - IP_MULTICAST_IF error " PRI_IPv4_ADDR " %d errno %d (" PUB_S ")",
+ mDNSVal16(dns_msg->h.id), &info->ifa_v4addr, err, errno, strerror(errno));
+ }
}
#else
err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
if (err < 0 && !m->NetworkChanged)
- LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] setsockopt - IP_MULTICAST_IF error " PRI_IPv4_ADDR " %d errno %d (" PUB_S ")",
+ mDNSVal16(dns_msg->h.id), &info->ifa_v4addr, err, errno, strerror(errno));
+ }
#endif
}
}
const int setsockopt_errno = errno;
char name[IFNAMSIZ];
if (if_indextoname(info->scope_id, name) != NULL)
- LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, setsockopt_errno, strerror(setsockopt_errno));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] setsockopt - IPV6_MULTICAST_IF error %d errno %d (" PUB_S ")",
+ mDNSVal16(dns_msg->h.id), err, setsockopt_errno, strerror(setsockopt_errno));
+ }
else
- LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface",
+ mDNSVal16(dns_msg->h.id), info->scope_id);
+ }
}
}
#ifdef IPV6_BOUND_IF
if (!mDNSAddrIsDNSMulticast(dst))
{
if (info->scope_id == 0)
- LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] IPV6_BOUND_IF socket option not set -- info %p (" PUB_S ") scope_id is zero",
+ mDNSVal16(dns_msg->h.id), info, ifa_name);
+ }
else
+ {
setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+ }
}
}
#endif
}
-
else
{
- LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
+ "[Q%u] mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!", mDNSVal16(dns_msg->h.id));
return mStatus_BadParamErr;
}
if (s >= 0)
+ {
verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
+ }
else
+ {
verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
+ }
// Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
// If we don't have the corresponding type of socket available, then return mStatus_Invalid
if (err < 0)
{
static int MessageCount = 0;
- LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
- s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u",
+ mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
if (!mDNSAddressIsAllDNSLinkGroup(dst))
{
if ((sendto_errno == EHOSTUNREACH) || (sendto_errno == ENETUNREACH)) return(mStatus_HostUnreachErr);
// Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_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, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u",
+ mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
+ }
else
{
MessageCount++;
- if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
- LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
- s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
- else // If logging is enabled, remove the cap and log aggressively
- LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
- s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
+ if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[Q%u] mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u MessageCount is %d",
+ mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
+ }
+ else // If logging is enabled, remove the cap and log aggressively
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[Q%u] mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u MessageCount is %d",
+ mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
+ }
}
result = mStatus_UnknownErr;
return(result);
}
-mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
+mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
{
static unsigned int numLogMessages = 0;
if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
return(-1);
}
+ if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
+ {
+ if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
+ s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
+ return(-1);
+ }
if (msg.msg_flags & MSG_CTRUNC)
{
if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
return(-1);
}
+
*fromlen = msg.msg_namelen;
- if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
- {
- if (numLogMessages++ < 100)
- {
- LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %ld msg.msg_controllen %lu < sizeof(struct cmsghdr) %lu",
- s, (long)n, (unsigned long)msg.msg_controllen, (unsigned long)sizeof(struct cmsghdr));
- }
- goto exit;
- }
// Parse each option out of the ancillary data.
for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
{
*ttl = *(int*)CMSG_DATA(cmPtr);
}
-exit:
return(n);
}
-// What is this for, and why does it use xor instead of a simple quality check? -- SC
+// What is this for, and why does it use xor instead of a simple equality check? -- SC
mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
{
NetworkInterfaceInfo *intf;
{
KQSocketSet *const ss = (KQSocketSet *)context;
mDNS *const m = ss->m;
- int err = 0, count = 0, closed = 0;
+ int err = 0, count = 0, closed = 0, recvfrom_errno = 0;
if (filter != EVFILT_READ)
LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
char packetifname[IF_NAMESIZE] = "";
mDNSu8 ttl;
err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
- if (err < 0) break;
+ if (err < 0)
+ {
+ recvfrom_errno = errno;
+ break;
+ }
if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
(destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0] == 0xFF))) m->p->num_mcasts++;
InterfaceID = FindMyInterface(&destAddr);
}
-// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
-// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
+// LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
+// &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
// mDNSCoreReceive may close the socket we're reading from. We must break out of our
// loop when that happens, or we may try to read from an invalid FD. We do this by
// If a client application's sockets are marked as defunct
// sockets we have delegated to it with SO_DELEGATED will also go defunct.
// We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
- if (err < 0 && errno == ENOTCONN)
+ if (err < 0 && recvfrom_errno == ENOTCONN)
{
LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
close(s1);
return;
}
- if (err < 0 && (errno != EWOULDBLOCK || count == 0))
+ if (err < 0 && (recvfrom_errno != EWOULDBLOCK || count == 0))
{
// Something is busted here.
// kqueue says there is a packet, but myrecvfrom says there is not.
// Find out about other socket parameter that can help understand why select() says the socket is ready for read
// All of this is racy, as data may have arrived after the call to select()
static unsigned int numLogMessages = 0;
- const int save_errno = errno;
int so_error = -1;
int so_nread = -1;
int fionread = -1;
- socklen_t solen = sizeof(int);
+ socklen_t solen;
fd_set readfds;
struct timeval timeout;
int selectresult;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
+ solen = (socklen_t)sizeof(so_error);
if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
+ solen = (socklen_t)sizeof(so_nread);
if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
if (ioctl(s1, FIONREAD, &fionread) == -1)
LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
if (numLogMessages++ < 100)
LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
- s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
+ s1, err, recvfrom_errno, strerror(recvfrom_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
if (numLogMessages > 5)
NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
"Congratulations, you've reproduced an elusive bug.\r"
mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
{
mDNSBool c = !sock->connected;
- sock->connected = mDNStrue;
+ if (!sock->connected && sock->err == mStatus_NoError)
+ {
+ sock->connected = mDNStrue;
+ }
sock->callback(sock, sock->context, c, sock->err);
// Note: the callback may call CloseConnection here, which frees the context structure!
}
// We already checked for NULL in hostname and this should never happen. Hence, returning -1
// (error not in OSStatus space) is okay.
- if (!sock->hostname.c[0])
+ if (!sock->hostname || !sock->hostname->c[0])
{
LogMsg("ERROR: tlsSetupSock: hostname NULL");
err = -1;
goto fail;
}
- ConvertDomainNameToCString(&sock->hostname, domname_cstr);
+ ConvertDomainNameToCString(sock->hostname, domname_cstr);
err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
if (err)
{
}
else
{
- if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+ if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
else LogMsg("doSSLHandshake: sock->fd is -1");
if (err == errSSLWouldBlock)
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);
+ KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
// Dispatch it on a separate queue to help avoid blocking other threads/queues, and
// to limit the number of threads used for SSLHandshake
//if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
// EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
if (filter == EVFILT_WRITE)
- KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
+ {
+ // sock->connected gets set by doTcpSocketCallback(), which may be called from here, or may be called
+ // from the TLS connect code. If we asked for a writability test, we are connecting
+ // (sock->connected == mDNSFalse).
+ if (sock->connected)
+ {
+ LogInfo("ERROR: TCPConnectCallback called with write event when socket is connected.");
+ }
+ else
+ {
+ int result = 0;
+ socklen_t len = (socklen_t)sizeof(result);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
+ {
+ LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
+ sock->fd, errno, strerror(errno));
+ sock->err = mStatus_ConnFailed;
+ }
+ else
+ {
+ if (result != 0)
+ {
+ sock->err = mStatus_ConnFailed;
+ if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
+ {
+ LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+ sock->fd, result, strerror(result));
+ }
+ else
+ {
+ LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+ sock->fd, result, strerror(result));
+ }
+ }
+ }
+ }
+ KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
+ // If we set the EVFILT_READ event in mDNSPlatformTCPConnect, it's possible to get a read event
+ // before the write event--apparently the socket is both readable and writable once that happens,
+ // even if the connect fails. If we set it here, after we've gotten a successful connection, then
+ // we shouldn't run into that problem.
+ if (sock->err == mStatus_NoError &&
+ KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+ {
+ // And of course if that fails, we can't use the connection even though we have it.
+ LogMsg("ERROR: tcpKQSocketCallback - KQueueSet failed");
+ sock->err = mStatus_TransientErr;
+ }
+ }
+
if (sock->flags & kTCPSocketFlags_UseTLS)
{
#ifndef NO_SECURITYFRAMEWORK
- if (!sock->setup)
- {
- sock->setup = mDNStrue;
- sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
- if (sock->err)
+ // Don't try to set up TLS if the connect failed.
+ if (sock->err == mStatus_NoError) {
+ if (!sock->setup)
{
- LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
+ sock->setup = mDNStrue;
+ sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
+ if (sock->err)
+ {
+ LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
+ return;
+ }
+ }
+ if (sock->handshake == handshake_required)
+ {
+ spawnSSLHandshake(sock);
return;
}
- }
- if (sock->handshake == handshake_required)
- {
- spawnSSLHandshake(sock);
- return;
- }
- else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
- {
- return;
- }
- else if (sock->handshake != handshake_completed)
- {
- if (!sock->err)
- sock->err = mStatus_UnknownErr;
- LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
+ else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
+ {
+ return;
+ }
+ else if (sock->handshake != handshake_completed)
+ {
+ if (!sock->err)
+ sock->err = mStatus_UnknownErr;
+ LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
+ }
}
#else /* NO_SECURITYFRAMEWORK */
sock->err = mStatus_UnsupportedErr;
(void)task; //unused
}
#else
+
mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
{
struct kevent new_event;
mDNSs32 end = mDNSPlatformRawTime();
(void)task;
if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
- LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+ "WARNING: " PUB_S " took %d ms to complete", task, end - m->p->BigMutexStartTime);
+ }
pthread_mutex_unlock(&m->p->BigMutex);
#endif
}
-mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
{
- KQSocketSet *cp = &sock->ss;
- int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
- KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
- const int on = 1; // "on" for setsockopt
- mStatus err;
+ int skt;
- int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
- if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
-
- // for TCP sockets, the traffic class is set once and not changed
- setTrafficClass(skt, useBackgroundTrafficClass);
-
- if (sa_family == AF_INET)
+ skt = -1;
+ if (!mDNSPosixTCPSocketSetup(&skt, addrtype, port, &sock->port))
{
- // Bind it
- struct sockaddr_in addr;
- mDNSPlatformMemZero(&addr, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = port->NotAnInteger;
- err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
- if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
-
- // Receive interface identifiers
- err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
- if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
-
- mDNSPlatformMemZero(&addr, sizeof(addr));
- socklen_t len = sizeof(addr);
- err = getsockname(skt, (struct sockaddr*) &addr, &len);
- if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
-
- port->NotAnInteger = addr.sin_port;
+ if (skt != -1) close(skt);
+ return mStatus_UnknownErr;
}
- else
- {
- // Bind it
- struct sockaddr_in6 addr6;
- mDNSPlatformMemZero(&addr6, sizeof(addr6));
- addr6.sin6_family = AF_INET6;
- addr6.sin6_port = port->NotAnInteger;
- err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
- if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
-
- // We want to receive destination addresses and receive interface identifiers
- err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
- if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
-
- mDNSPlatformMemZero(&addr6, sizeof(addr6));
- socklen_t len = sizeof(addr6);
- err = getsockname(skt, (struct sockaddr *) &addr6, &len);
- if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
-
- port->NotAnInteger = addr6.sin6_port;
+
+ // for TCP sockets, the traffic class is set once and not changed
+ setTrafficClass(skt, useBackgroundTrafficClass);
- }
- *s = skt;
- k->KQcallback = tcpKQSocketCallback;
- k->KQcontext = sock;
- k->KQtask = "mDNSPlatformTCPSocket";
+ sock->fd = skt;
+ sock->kqEntry.KQcallback = tcpKQSocketCallback;
+ sock->kqEntry.KQcontext = sock;
+ sock->kqEntry.KQtask = "mDNSPlatformTCPSocket";
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
- k->readSource = mDNSNULL;
- k->writeSource = mDNSNULL;
- k->fdClosed = mDNSfalse;
+ sock->kqEntry.readSource = mDNSNULL;
+ sock->kqEntry.writeSource = mDNSNULL;
+ sock->kqEntry.fdClosed = mDNSfalse;
#endif
return mStatus_NoError;
}
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrtype, mDNSIPPort *port, domainname *hostname, mDNSBool useBackgroundTrafficClass)
{
mStatus err;
+ mDNSu32 lowWater = 16384;
+ size_t len = sizeof (TCPSocket);
+ if (hostname) {
+ len += sizeof (domainname);
+ }
- TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
+ TCPSocket *sock = (TCPSocket *) callocL("TCPSocket/mDNSPlatformTCPSocket", len);
if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
- mDNSPlatformMemZero(sock, sizeof(TCPSocket));
-
- sock->ss.m = &mDNSStorage;
- sock->ss.sktv4 = -1;
- sock->ss.sktv6 = -1;
- err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
-
- if (!err)
+ if (hostname)
{
- err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
- if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
+ sock->hostname = (domainname *)(sock + 1); // Allocated together so can be freed together
+ debugf("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
+ AssignDomainName(sock->hostname, hostname);
}
+
+ err = SetupTCPSocket(sock, addrtype, port, useBackgroundTrafficClass);
+
if (err)
{
LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
return(mDNSNULL);
}
- // sock->fd is used as the default fd if the caller does not call mDNSPlatformTCPConnect
- sock->fd = sock->ss.sktv4;
+
+ if (setsockopt(sock->fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater) < 0)
+ {
+ LogMsg("mDNSPlatformTCPSocket: TCP_NOTSENT_LOWAT returned %d", errno);
+ mDNSPlatformTCPCloseConnection(sock);
+ return mDNSNULL;
+ }
+
sock->callback = mDNSNULL;
sock->flags = flags;
sock->context = mDNSNULL;
return sock;
}
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
{
- KQSocketSet *cp = &sock->ss;
- int *s = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
- KQueueEntry *k = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
mStatus err = mStatus_NoError;
struct sockaddr_storage ss;
sock->handshake = handshake_required;
sock->err = mStatus_NoError;
- if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
-
if (dst->type == mDNSAddrType_IPv4)
{
struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
// Watch for connect complete (write is ready)
// EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
- if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
- return errno;
- }
-
- // Watch for incoming data
- if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
+ if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
{
LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
return errno;
}
- if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+ if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
{
LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
return mStatus_UnknownErr;
// on this interface
//
// Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
- // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
- if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
+ // UDP).
+ if (InterfaceID)
{
NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
if (dst->type == mDNSAddrType_IPv4)
{
#ifdef IP_BOUND_IF
- if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+ if (info) setsockopt(sock->fd, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
#else
(void)InterfaceID; // Unused
else
{
#ifdef IPV6_BOUND_IF
- if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+ if (info) setsockopt(sock->fd, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
#else
(void)InterfaceID; // Unused
// mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
// from which we can infer the destination address family. Hence we need to remember that here.
// Instead of remembering the address family, we remember the right fd.
- sock->fd = *s;
- sock->kqEntry = k;
+ sock->fd = sock->fd;
// initiate connection wth peer
- if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
+ if (connect(sock->fd, (struct sockaddr *)&ss, ss.ss_len) < 0)
{
if (errno == EINPROGRESS) return mStatus_ConnPending;
if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
// kQueue should notify us, but this LogMsg is to help track down if it doesn't
+ // Experimentation shows that even a connection to a local listener returns EINPROGRESS, so this
+ // will likely never happen.
+
return err;
}
+// Replace the existing socket callback with a new one, or establish a callback where none was present.
+mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
+{
+ sock->callback = callback;
+ sock->context = context;
+
+ // dnsextd currently reaches into the TCPSocket structure layer to do its own thing; this won't work for
+ // any code (e.g., the Discovery Proxy or Discovery Relay) that actually uses the mDNSPlatform layer as
+ // an opaque layer. So for that code, we have this. dnsextd should probably be platformized if it's
+ // still relevant.
+ if (!sock->callback) {
+ // Watch for incoming data
+ if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+ return mStatus_UnknownErr;
+ }
+ }
+
+ sock->kqEntry.KQcallback = tcpKQSocketCallback;
+ sock->kqEntry.KQcontext = sock;
+ sock->kqEntry.KQtask = "mDNSPlatformTCPSocket";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ sock->kqEntry.readSource = mDNSNULL;
+ sock->kqEntry.writeSource = mDNSNULL;
+ sock->kqEntry.fdClosed = mDNSfalse;
+#endif
+ return mStatus_NoError;
+}
+
// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
+// mDNSPlatformTCPAccept is only called by dnsextd.c. It's called _after_ accept has returned
+// a connected socket. The purpose appears to be to allocate and initialize the TCPSocket structure
+// and set up TLS, if required for this connection. dnsextd appears to be the only thing in mDNSResponder
+// that accepts incoming TLS connections.
mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
{
mStatus err = mStatus_NoError;
- TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
+ TCPSocket *sock = (TCPSocket *) callocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(*sock));
if (!sock) return(mDNSNULL);
- mDNSPlatformMemZero(sock, sizeof(*sock));
sock->fd = fd;
sock->flags = flags;
return(sock);
}
+mDNSlocal void tcpListenCallback(int fd, __unused short filter, void *context, __unused mDNSBool encounteredEOF)
+{
+ TCPListener *listener = context;
+ TCPSocket *sock;
+
+ sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
+ listener->callback, listener->context);
+
+ if (sock != mDNSNULL)
+ {
+ KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
+
+ sock->kqEntry.KQcallback = tcpKQSocketCallback;
+ sock->kqEntry.KQcontext = sock;
+ sock->kqEntry.KQtask = "mDNSPlatformTCPListen";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ sock->kqEntry.readSource = mDNSNULL;
+ sock->kqEntry.writeSource = mDNSNULL;
+ sock->kqEntry.fdClosed = mDNSfalse;
+#endif
+ }
+}
+
+mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+ TCPAcceptedCallback callback, void *context)
+{
+ TCPListener *ret;
+ int fd = -1;
+
+ if (!mDNSPosixTCPListen(&fd, addrtype, port, addr, reuseAddr, queueLength)) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return mDNSNULL;
+ }
+
+ // Allocate a listener structure
+ ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
+ if (ret == mDNSNULL)
+ {
+ LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
+ close(fd);
+ return mDNSNULL;
+ }
+ ret->fd = fd;
+ ret->callback = callback;
+ ret->context = context;
+ ret->socketFlags = socketFlags;
+
+ // Watch for incoming data
+ KQueueSet(ret->fd, EV_ADD, EVFILT_READ, &ret->kqEntry);
+ ret->kqEntry.KQcallback = tcpListenCallback;
+ ret->kqEntry.KQcontext = ret;
+ ret->kqEntry.KQtask = "mDNSPlatformTCPListen";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+ ret->kqEntry.readSource = mDNSNULL;
+ ret->kqEntry.writeSource = mDNSNULL;
+ ret->kqEntry.fdClosed = mDNSfalse;
+#endif
+ return ret;
+}
+
mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
{
mDNSu16 port;
sock->tlsContext = NULL;
}
#endif /* NO_SECURITYFRAMEWORK */
- if (sock->ss.sktv4 != -1)
- shutdown(sock->ss.sktv4, 2);
- if (sock->ss.sktv6 != -1)
- shutdown(sock->ss.sktv6, 2);
- CloseSocketSet(&sock->ss);
- sock->fd = -1;
-
+ if (sock->fd != -1) {
+ shutdown(sock->fd, 2);
+ mDNSPlatformCloseFD(&sock->kqEntry, sock->fd);
+ sock->fd = -1;
+ }
+
freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
}
}
ssize_t nread = 0;
*closed = mDNSfalse;
+ // We can get here if the caller set up a TCP connection but didn't check the status when it got the
+ // callback.
+ if (!sock->connected) {
+ return mStatus_DefunctConnection;
+ }
+
if (sock->flags & kTCPSocketFlags_UseTLS)
{
#ifndef NO_SECURITYFRAMEWORK
}
else
{
- static int CLOSEDcount = 0;
- static int EAGAINcount = 0;
- nread = recv(sock->fd, buf, buflen, 0);
-
- if (nread > 0)
- {
- CLOSEDcount = 0;
- EAGAINcount = 0;
- } // On success, clear our error counters
- else if (nread == 0)
- {
- *closed = mDNStrue;
- if ((++CLOSEDcount % 1000) == 0)
- {
- LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount);
- assert(CLOSEDcount < 1000);
- // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
- // crash mDNSResponder using assert() and restart fresh. See advantages below:
- // 1.Better User Experience
- // 2.CrashLogs frequency can be monitored
- // 3.StackTrace can be used for more info
- }
- }
- // else nread is negative -- see what kind of error we got
- else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
- else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
- else // errno is EAGAIN (EWOULDBLOCK) -- no data available
- {
- nread = 0;
- if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
- }
+ nread = mDNSPosixReadTCP(sock->fd, buf, buflen, closed);
}
return nread;
{
int nsent;
+ if (!sock->connected) {
+ return mStatus_DefunctConnection;
+ }
+
if (sock->flags & kTCPSocketFlags_UseTLS)
{
#ifndef NO_SECURITYFRAMEWORK
}
else
{
- nsent = send(sock->fd, msg, len, 0);
- if (nsent < 0)
- {
- if (errno == EAGAIN) nsent = 0;
- else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
- }
+ nsent = mDNSPosixWriteTCP(sock->fd, msg, len);
}
-
return nsent;
}
return sock->fd;
}
-// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
-// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+// This function checks to see if the socket is writable. It will be writable if the kernel TCP output
+// buffer is less full than TCP_NOTSENT_LOWAT. This should be half or less of the actual kernel buffer
+// size. This check is done in cases where data should be written if there's space, for example in the
+// Discovery Relay code, where we may be receiving mDNS messages at arbitrary times, and generally there
+// should be buffer space to relay them, but in exceptional cases there might not be. In this case it's
+
+mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
{
- int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+ int kfd = kqueue();
+ struct kevent kin, kout;
+ int count;
+ struct timespec ts;
+
+ if (kfd < 0)
+ {
+ LogMsg("ERROR: kqueue failed: %m");
+ return mDNSfalse;
+ }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ EV_SET(&kin, sock->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ count = kevent(kfd, &kin, 1, &kout, 1, &ts);
+ close(kfd);
+ if (count == 1 && (int)kout.ident == sock->fd && kout.filter == EVFILT_WRITE)
+ {
+ return mDNStrue;
+ }
+ return mDNSfalse;
+}
+
+// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
+// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+{
+ int *s = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
KQueueEntry *k = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
const int on = 1;
const int twofivefive = 255;
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));
+ UDPSocket *p = (UDPSocket *) callocL("UDPSocket", sizeof(*p));
if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
- mDNSPlatformMemZero(p, sizeof(UDPSocket));
p->ss.port = zeroIPPort;
p->ss.m = &mDNSStorage;
p->ss.sktv4 = -1;
// the values and schedule a task to update the MAC address in the TCP Keepalive record.
if (kr == 0)
{
- addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
+ addrMapping = (IPAddressMACMapping *) mDNSPlatformMemAllocateClear(sizeof(*addrMapping));
+ // This memory allocation is not checked for failure
+ // It also shoudn’t need to be a memory allocation at all -- why not just use a stack variable? -- SC
snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+ // Why is the address represented using text? The UpdateRMAC routine just parses it back into a six-byte MAC address. -- SC
if (family == AF_INET)
{
addrMapping->ipaddr.type = mDNSAddrType_IPv4;
mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
+ // This is the wrong size. It’s using sizeof(v6addr_t) for an IPv4 address -- SC
}
else
{
LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
//if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
- // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+ // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
//if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
- // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+ // LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
/* <rdar://problem/10287386>
* make socket non blocking see comments in bpf_callback_common for more info
#endif /* NO_SECURITYFRAMEWORK */
}
+
+mDNSlocal void mDNSDomainLabelFromCFString(CFStringRef cfs, domainlabel *const namelabel);
+
// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
{
CFStringEncoding encoding = kCFStringEncodingUTF8;
CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
- if (cfs)
- {
- CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
- CFRelease(cfs);
+
+ if (cfs == mDNSNULL) {
+ return;
}
+
+ mDNSDomainLabelFromCFString(cfs, namelabel);
+
+ CFRelease(cfs);
}
-// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
{
CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
- if (cfs)
- {
- CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
- CFRelease(cfs);
+
+ if (cfs == mDNSNULL) {
+ return;
}
+
+ mDNSDomainLabelFromCFString(cfs, namelabel);
+
+ CFRelease(cfs);
+}
+
+mDNSlocal void mDNSDomainLabelFromCFString(CFStringRef cfs, domainlabel *const namelabel)
+{
+ CFIndex num_of_bytes_write = 0;
+ CFStringGetBytes(cfs, CFRangeMake(0, CFStringGetLength(cfs)), kCFStringEncodingUTF8, 0, FALSE, namelabel->c + 1, sizeof(*namelabel) - 1, &num_of_bytes_write);
+ namelabel->c[0] = num_of_bytes_write;
}
mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
{
mDNSs32 val;
CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
- if (!state) return mDNSfalse;
+ if (state == NULL) return mDNSfalse;
if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
{ LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
return val ? mDNStrue : mDNSfalse;
{
io_name_t n1;
IOObjectGetClass(service, n1);
- LogSPS("CheckInterfaceSupport: No %s for interface %s/%s kr %d", key, intf->ifname, n1, kr);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+ "CheckInterfaceSupport: No " PUB_S " for interface " PUB_S "/" PUB_S " kr 0x%X", key, intf->ifname, n1, kr);
ret = mDNSfalse;
}
}
+#if !TARGET_OS_WATCH
mDNSlocal mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
{
return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
}
+#endif
mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
{
+#if TARGET_OS_WATCH
+ (void) i; // unused
+ return(mDNSfalse);
+#else
// We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
{
- LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+ "NetWakeInterface: returning false for " PUB_S, i->ifinfo.ifname);
return(mDNSfalse);
}
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
+ // 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("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
+ LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+ "NetWakeInterface: " PUB_S " " PRI_IP_ADDR " " PUB_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);
+#endif // TARGET_OS_WATCH
}
-mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
+mDNSlocal u_int64_t getExtendedFlags(const char *ifa_name)
{
int sockFD;
struct ifreq ifr;
if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
{
- LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
+ LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed for %s, errno = %d (%s)", ifa_name, errno, strerror(errno));
ifr.ifr_eflags = 0;
}
return ifr.ifr_eflags;
}
-#if TARGET_OS_OSX
-// IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
-mDNSlocal mDNSBool isCoprocessorInterface(int sockFD, char * ifa_name)
+mDNSlocal mDNSBool isExcludedInterface(int sockFD, char * ifa_name)
{
struct ifreq ifr;
+ // llw0 interface is excluded from Bonjour discover.
+ // There currently is no interface attributed based way to identify this interface
+ // until rdar://problem/47933782 is addressed.
+ if (strncmp(ifa_name, "llw", 3) == 0)
+ {
+ LogMsg("isExcludedInterface: excluding %s", ifa_name);
+ return mDNStrue;
+ }
+
+ // Coprocessor interfaces are also excluded.
if (sockFD < 0)
{
- LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD);
+ LogMsg("isExcludedInterface: invalid socket FD passed: %d", sockFD);
return mDNSfalse;
}
if (ioctl(sockFD, SIOCGIFFUNCTIONALTYPE, (caddr_t)&ifr) == -1)
{
- LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
+ LogMsg("isExcludedInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
return mDNSfalse;
}
if (ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC)
{
- LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name);
+ LogMsg("isExcludedInterface: excluding coprocessor interface %s", ifa_name);
return mDNStrue;
}
else
return mDNSfalse;
}
-#else // TARGET_OS_OSX
-#define isCoprocessorInterface(A, B) mDNSfalse
-#endif // TARGET_OS_OSX
-
#if TARGET_OS_IPHONE
// Function pointers for the routines we use in the MobileWiFi framework.
// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
// (e.g. sa_family not AF_INET or AF_INET6)
+
mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs32 utc)
{
mDNS *const m = &mDNSStorage;
return(*p);
}
- NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
+ NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *) callocL("NetworkInterfaceInfoOSX", sizeof(*i));
debugf("AddInterfaceToList: Making new interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
if (!i) return(mDNSNULL);
- mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
i->ifinfo.ip = ip;
i->ifinfo.mask = mask;
i->D2DInterface = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
if (i->D2DInterface)
LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
-
- i->isExpensive = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
i->isAWDL = (eflags & IFEF_AWDL) ? mDNStrue: mDNSfalse;
- if (eflags & IFEF_AWDL)
- {
- // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
- // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
- // Bonjour requests over the AWDL interface.
- i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
- AWDLInterfaceID = i->ifinfo.InterfaceID;
- LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
- }
- else
- {
- i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
- }
- i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
- i->LastSeen = utc;
- i->ifa_flags = ifa->ifa_flags;
- i->scope_id = scope_id;
- i->BSSID = bssid;
- i->sa_family = ifa->ifa_addr->sa_family;
- i->BPF_fd = -1;
- i->BPF_mcfd = -1;
- i->BPF_len = 0;
- i->Registered = mDNSNULL;
-
- // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
- i->ifinfo.McastTxRx = MulticastInterface(i);
- // Do this AFTER i->BSSID has been set up
- i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : NetWakeInterface(i);
- GetMAC(&i->ifinfo.MAC, scope_id);
- if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
- LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
-
- *p = i;
- return(i);
-}
-
-#if APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - AutoTunnel
-#endif
-
-#define kRacoonPort 4500
-
-static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
-
-#ifndef NO_SECURITYFRAMEWORK
-
-static CFMutableDictionaryRef domainStatusDict = NULL;
-
-mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
-{
- if (q->LongLived)
- {
- if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
- return mStatus_NoSuchRecord;
- else if (q->state == LLQ_Poll)
- return mStatus_PollingMode;
- else if (q->state != LLQ_Established && !q->DuplicateOf)
- return mStatus_TransientErr;
- }
-
- return mStatus_NoError;
-}
-
-mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
-{
- mStatus status = mStatus_NoError;
- DNSQuestion* q, *worst_q = mDNSNULL;
- for (q = mDNSStorage.Questions; q; q=q->next)
- if (q->AuthInfo == info)
- {
- mStatus newStatus = CheckQuestionForStatus(q);
- if (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
- else if (newStatus == mStatus_PollingMode) { status = newStatus; worst_q = q; }
- else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
- }
-
- if (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
- else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
- else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
- else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
- return status;
-}
-
-mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
-{
- AuthRecord *r;
-
- if (info->deltime) return mStatus_NoError;
- for (r = mDNSStorage.ResourceRecords; r; r = r->next)
- {
- // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
- // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
- // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
- // has already checked
- const domainname *n = r->resrec.name;
- while (n->c[0])
- {
- DomainAuthInfo *ptr;
- for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
- if (SameDomainName(&ptr->domain, n))
- {
- if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
- {
- mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
- return r->updateError;
- }
- }
- n = (const domainname *)(n->c + 1 + n->c[0]);
- }
- }
- return mStatus_NoError;
-}
-
-#endif // ndef NO_SECURITYFRAMEWORK
-
-// MUST be called with lock held
-mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
-{
-#ifdef NO_SECURITYFRAMEWORK
- (void)info;
-#else
- // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
- // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
- mDNS *const m = &mDNSStorage;
- const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
- const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
- char buffer[1024];
- CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- CFStringRef domain = NULL;
- CFStringRef tmp = NULL;
- CFNumberRef num = NULL;
- mStatus status = mStatus_NoError;
- mStatus llqStatus = mStatus_NoError;
- char llqBuffer[1024];
-
- mDNS_CheckLock(m);
-
- if (!domainStatusDict)
- {
- domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
- }
-
- if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
-
- mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
- domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
-
- if (info->deltime)
- {
- if (CFDictionaryContainsKey(domainStatusDict, domain))
- {
- CFDictionaryRemoveValue(domainStatusDict, domain);
- if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
- }
- CFRelease(domain);
- CFRelease(dict);
-
- return;
- }
-
- mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
- tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!tmp)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
- else
- {
- CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
- CFRelease(tmp);
- }
-
- if (llq)
- {
- mDNSu32 port = mDNSVal16(llq->ExternalPort);
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
- else
- {
- CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
- CFRelease(num);
- }
-
- if (llq->Result)
- {
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
- else
- {
- CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
- CFRelease(num);
- }
- }
- }
-
- if (tun)
- {
- mDNSu32 port = mDNSVal16(tun->ExternalPort);
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
- else
- {
- CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
- CFRelease(num);
- }
-
- mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
- tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!tmp)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
- else
- {
- CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
- CFRelease(tmp);
- }
-
- if (tun->Result)
- {
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
- else
- {
- CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
- CFRelease(num);
- }
- }
- }
- if (tun || llq)
- {
- mDNSu32 code = m->LastNATMapResultCode;
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
- else
- {
- CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
- CFRelease(num);
- }
- }
-
- mDNS_snprintf(buffer, sizeof(buffer), "Success");
- llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
- status = UpdateRRStatus(buffer, sizeof(buffer), info);
-
- // If we have a bad signature error updating a RR, it overrides any error as it needs to be
- // reported so that it can be fixed automatically (or the user needs to be notified)
- if (status != mStatus_NoError)
- {
- LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
- }
- else if (m->Router.type == mDNSAddrType_None)
- {
- status = mStatus_NoRouter;
- mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
- }
- else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
- {
- status = mStatus_NoRouter;
- mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
- }
- else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
- {
- status = mStatus_ServiceNotRunning;
- mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
- }
- else if (!llq && !tun)
- {
- status = mStatus_NotInitializedErr;
- mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
- }
- else if (llqStatus == mStatus_NoSuchRecord)
- {
- status = llqStatus;
- mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
- }
- else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
- {
- status = mStatus_DoubleNAT;
- mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
- }
- else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
- (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
- (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
- {
- status = mStatus_NATPortMappingDisabled;
- mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
- }
- else if ((llq && llq->Result) || (tun && tun->Result))
- {
- status = mStatus_NATTraversal;
- mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
- }
- else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
- {
- status = mStatus_NATTraversal;
- mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
- }
- else
- {
- status = llqStatus;
- mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
- LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
- }
-
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
- if (!num)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
- else
- {
- CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
- CFRelease(num);
- }
-
- tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!tmp)
- LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
- else
- {
- CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
- CFRelease(tmp);
- }
-
- if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
- !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
- {
- CFDictionarySetValue(domainStatusDict, domain, dict);
- if (!m->ShutdownTime)
- {
- LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
- mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
- }
- }
-
- CFRelease(domain);
- CFRelease(dict);
-
- debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
-#endif // def NO_SECURITYFRAMEWORK
-}
-
-// MUST be called with lock held
-mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
-{
-#ifdef NO_SECURITYFRAMEWORK
- (void) m;
-#else
- mDNS_CheckLock(m);
- DomainAuthInfo* info;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel && !info->deltime)
- UpdateAutoTunnelDomainStatus(info);
-#endif // def NO_SECURITYFRAMEWORK
-}
-
-mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m) // Determine whether we need racoon to accept incoming connections
-{
- DomainAuthInfo *info;
-
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
- break;
-
- if (info != AnonymousRacoonConfig)
- {
- AnonymousRacoonConfig = info;
- LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
- }
-}
-
-mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
-
-// Caller must hold the lock
-mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
-{
- mDNS_CheckLock(m);
-
- LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
- if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
- {
- mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
- if (err)
- {
- record->resrec.RecordType = kDNSRecordTypeUnregistered;
- LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
- return mDNSfalse;
- }
- else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
- }
- else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
-
- return mDNStrue;
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
-{
- if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
- {
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- }
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
-{
- mStatus err;
- mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
-
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
- {
- LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
- info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
- DeregisterAutoTunnelHostRecord(m, info);
- }
- else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- info->AutoTunnelHostRecord.namestorage.c[0] = 0;
- AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
- info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
- info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
- if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
- else
- {
- // Make sure we trigger the registration of all SRV records in regState_NoTarget again
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
- }
- }
- else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
-{
- LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
-
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
- UpdateAutoTunnelHostRecord(m, info);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
-{
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
- {
- LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result);
- DeregisterAutoTunnelServiceRecords(m, info);
- }
- else
- {
- if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- // 1. Set up our address record for the external tunnel address
- // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
- mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
- AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
- info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
- info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
- if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
- else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
- }
- else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
-
- if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
- mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
- AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
- info->AutoTunnelService.resrec.rdata->u.srv.priority = 0;
- info->AutoTunnelService.resrec.rdata->u.srv.weight = 0;
- info->AutoTunnelService.resrec.rdata->u.srv.port = m->AutoTunnelNAT.ExternalPort;
- AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
- info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
- if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
- else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
- }
- else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
-
- UpdateAutoTunnelHostRecord(m, info);
-
- LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
- info->AutoTunnelTarget.namestorage.c, &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
- info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
-
- }
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
-{
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
-{
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
- DeregisterAutoTunnelDeviceInfoRecord(m, info);
- else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
-
- info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
- info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
- if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
- else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
- }
- else
- LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
-{
- LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
-
- DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
- UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelDomainStatus(info);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
-{
- mDNS_CheckLock(m);
-
- if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
- DeregisterAutoTunnel6Record(m, info);
- else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
- {
- mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
- kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
- AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
- AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
- AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
- info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
- info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
- mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
- if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
- else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
-
- UpdateAutoTunnelHostRecord(m, info);
-
- LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
- info->AutoTunnel6Record.namestorage.c, &m->AutoTunnelRelayAddr,
- info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
-
- }
- else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
-}
-
-mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
- if (result == mStatus_MemFree)
- {
- LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
-
- mDNS_Lock(m);
-
- // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
- if (rr == &info->AutoTunnelHostRecord)
- {
- rr->namestorage.c[0] = 0;
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
- }
- if (m->ShutdownTime)
- {
- LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
- mDNS_Unlock(m);
- return;
- }
- if (rr == &info->AutoTunnelHostRecord)
- {
- LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
- UpdateAutoTunnelHostRecord(m,info);
- }
- else if (rr == &info->AutoTunnelDeviceInfo)
- {
- LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
- UpdateAutoTunnelDeviceInfoRecord(m,info);
- }
- else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
- {
- LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
- UpdateAutoTunnelServiceRecords(m,info);
- }
- else if (rr == &info->AutoTunnel6Record)
- {
- LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
- UpdateAutoTunnel6Record(m,info);
- }
-
- mDNS_Unlock(m);
- }
-}
-
-mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
-{
- DomainAuthInfo *info;
-
- LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
- n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
-
- mDNS_Lock(m);
-
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
-
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel)
- UpdateAutoTunnelServiceRecords(m, info);
-
- UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
-
- UpdateAutoTunnelDomainStatuses(m);
-
- mDNS_Unlock(m);
-}
-
-mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
-{
- LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
-
- mDNS_Lock(m);
- // We forcibly deregister the records that are based on the hostname.
- // When deregistration of each completes, the MemFree callback will make the
- // appropriate Update* call to use the new name to reregister.
- DeregisterAutoTunnelHostRecord(m, info);
- DeregisterAutoTunnelDeviceInfoRecord(m, info);
- DeregisterAutoTunnelServiceRecords(m, info);
- DeregisterAutoTunnel6Record(m, info);
- m->NextSRVUpdate = NonZeroTime(m->timenow);
- mDNS_Unlock(m);
-}
-
-// Must be called with the lock held
-mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
-{
- mDNS *const m = &mDNSStorage;
- if (info->deltime) return;
-
- if (info->AutoTunnelServiceStarted)
- {
- // On wake from sleep, this function will be called when determining SRV targets,
- // and needs to re-register the host record for the target to be set correctly
- UpdateAutoTunnelHostRecord(m, info);
- return;
- }
-
- info->AutoTunnelServiceStarted = mDNStrue;
-
- // Now that we have a service in this domain, we need to try to register the
- // AutoTunnel records, because the relay connection & NAT-T may have already been
- // started for another domain. If the relay connection is not up or the NAT-T has not
- // yet succeeded, the Update* functions are smart enough to not register the records.
- // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
- // decide whether to register the AutoTunnel records in the calls below.
- UpdateAutoTunnelServiceRecords(m, info);
- UpdateAutoTunnel6Record(m, info);
- UpdateAutoTunnelDeviceInfoRecord(m, info);
- UpdateAutoTunnelHostRecord(m, info);
-
- // If the global AutoTunnel NAT-T is not yet started, start it.
- if (!m->AutoTunnelNAT.clientContext)
- {
- m->AutoTunnelNAT.clientCallback = AutoTunnelNATCallback;
- m->AutoTunnelNAT.clientContext = (void*)1; // Means AutoTunnelNAT Traversal is active;
- m->AutoTunnelNAT.Protocol = NATOp_MapUDP;
- m->AutoTunnelNAT.IntPort = IPSECPort;
- m->AutoTunnelNAT.RequestedPort = IPSECPort;
- m->AutoTunnelNAT.NATLease = 0;
- mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
- if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
- }
-}
-
-mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
-{
- mDNSv6Addr loc_outer6;
- mDNSv6Addr rmt_outer6;
-
- // When we are tunneling over IPv6 Relay address, the port number is zero
- if (mDNSIPPortIsZero(tun->rmt_outer_port))
- {
- loc_outer6 = tun->loc_outer6;
- rmt_outer6 = tun->rmt_outer6;
- }
- else
- {
- loc_outer6 = zerov6Addr;
- loc_outer6.b[0] = tun->loc_outer.b[0];
- loc_outer6.b[1] = tun->loc_outer.b[1];
- loc_outer6.b[2] = tun->loc_outer.b[2];
- loc_outer6.b[3] = tun->loc_outer.b[3];
-
- rmt_outer6 = zerov6Addr;
- rmt_outer6.b[0] = tun->rmt_outer.b[0];
- rmt_outer6.b[1] = tun->rmt_outer.b[1];
- rmt_outer6.b[2] = tun->rmt_outer.b[2];
- rmt_outer6.b[3] = tun->rmt_outer.b[3];
- }
-
- return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), btmmprefix, SkipLeadingLabels(&tun->dstname, 1)));
-}
-
-// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
-#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
-
-mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
-{
- mDNS *const m = &mDNSStorage;
- DNSQuestion *q = m->Questions;
- while (q)
- {
- if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
- {
- LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- mDNSQuestionCallback *tmp = q->QuestionCallback;
- q->QuestionCallback = AutoTunnelCallback; // Set QuestionCallback to suppress another call back to AddNewClientTunnel
- mDNS_StopQuery(m, q);
- mDNS_StartQuery(m, q);
- q->QuestionCallback = tmp; // Restore QuestionCallback back to the real value
- if (!success) q->NoAnswer = NoAnswer_Fail;
- // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
- // In general we have to assume that the question list might have changed in arbitrary ways.
- // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
- // already in use. The safest solution is just to go back to the start of the list and start again.
- // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
- // just one suspended question, so it's really a 2n algorithm.
- q = m->Questions;
- }
- else
- q = q->next;
- }
-}
-
-mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
-{
- // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
- // a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
- // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
- // even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
- // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
- ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
- ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
-}
-
-mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
-{
- mDNS *const m = &mDNSStorage;
- ClientTunnel **p = &m->TunnelClients;
- while (*p != tun && *p) p = &(*p)->next;
- if (*p) *p = tun->next;
- ReissueBlockedQuestions(&tun->dstname, success);
- LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
- freeL("ClientTunnel", tun);
-}
-
-mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
-{
- mDNS *const m = &mDNSStorage;
- ClientTunnel **p;
- mDNSBool needSetKeys = mDNStrue;
-
- p = &tun->next;
- while (*p)
- {
- // Is this a tunnel to the same host that we are trying to setup now?
- if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
- else
- {
- ClientTunnel *old = *p;
- if (v6Tunnel)
- {
- if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
- LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- if (old->q.ThisQInterval >= 0)
- {
- LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- mDNS_StopQuery(m, &old->q);
- }
- else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
- !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
- !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
- !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
- {
- // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
- // the other parameters of the tunnel are different
- LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- AutoTunnelSetKeys(old, mDNSfalse);
- }
- else
- {
- // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
- // as "tun" and "old" are identical
- LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
- &old->rmt_inner);
- needSetKeys = mDNSfalse;
- }
- }
- else
- {
- if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
- LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- if (old->q.ThisQInterval >= 0)
- {
- LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- mDNS_StopQuery(m, &old->q);
- }
- else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
- !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
- !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
- !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
- !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
- {
- // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
- // the other parameters of the tunnel are different
- LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- AutoTunnelSetKeys(old, mDNSfalse);
- }
- else
- {
- // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
- // as "tun" and "old" are identical
- LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
- &old->rmt_inner);
- needSetKeys = mDNSfalse;
- }
- }
-
- *p = old->next;
- LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
- freeL("ClientTunnel", old);
- }
- }
- return needSetKeys;
-}
-
-// v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
-// tunnel will be deleted
-mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
-{
- ClientTunnel **p;
-
- p = &tun->next;
- while (*p)
- {
- // If there is more than one client tunnel to the same host, delete all of them.
- // We do this by just checking against the EUI64 rather than the full address
- if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
- else
- {
- ClientTunnel *old = *p;
- if (v6Tunnel)
- {
- if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
- LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- }
- else
- {
- if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
- LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- }
- if (old->q.ThisQInterval >= 0)
- {
- LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- mDNS_StopQuery(&mDNSStorage, &old->q);
- }
- else
- {
- LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
- AutoTunnelSetKeys(old, mDNSfalse);
- }
- *p = old->next;
- LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
- freeL("ClientTunnel", old);
- }
- }
-}
-
-mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
-{
- mDNS *const m = &mDNSStorage;
- mDNSBool needSetKeys = mDNStrue;
- ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
- mDNSBool v6Tunnel = mDNSfalse;
- DomainAuthInfo *info;
-
- // If the port is zero, then we have a relay address of the peer
- if (mDNSIPPortIsZero(tun->rmt_outer_port))
- v6Tunnel = mDNStrue;
-
- if (v6Tunnel)
- {
- LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
- tun->rmt_outer6 = answer->rdata->u.ipv6;
- tun->loc_outer6 = m->AutoTunnelRelayAddr;
- }
- else
- {
- LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
- tun->rmt_outer = answer->rdata->u.ipv4;
- mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
- tmpDst.ip.v4 = tun->rmt_outer;
- mDNSAddr tmpSrc = zeroAddr;
- mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
- if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
- else tun->loc_outer = m->AdvertisedV4.ip.v4;
- }
-
- question->ThisQInterval = -1; // So we know this tunnel setup has completed
-
- info = GetAuthInfoForName(m, &tun->dstname);
- if (!info)
- {
- LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
- ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
- return;
- }
-
- tun->loc_inner = info->AutoTunnelInnerAddress;
-
- // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
- // look for existing tunnels to see whether they have the same information for our peer.
- // If not, delete them and need to create a new tunnel. If they are same, just use the
- // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
- TunnelClientDeleteAny(tun, !v6Tunnel);
- needSetKeys = TunnelClientDeleteMatching(tun, v6Tunnel);
-
- if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
- else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
-
- mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
- LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
- // Kick off any questions that were held pending this tunnel setup
- ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
-}
-
-mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
- DomainAuthInfo *info;
-
- LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
-
- if (!AddRecord) return;
- mDNS_StopQuery(m, question);
-
- // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
- // The code below will look for _autotunnel._udp SRV record followed by A record
- if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
+ if (eflags & IFEF_AWDL)
{
- LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
- return;
+ // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
+ // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
+ // Bonjour requests over the AWDL interface.
+ i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
+ AWDLInterfaceID = i->ifinfo.InterfaceID;
+ LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
}
-
- switch (tun->tc_state)
+ else
{
- case TC_STATE_AAAA_PEER:
- if (question->qtype != kDNSType_AAAA)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
- }
- info = GetAuthInfoForName(m, &tun->dstname);
- if (!info)
- {
- LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
- UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
- return;
- }
- if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
- {
- LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
- UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
- return;
- }
- if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
- {
- LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
- UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
- return;
- }
- tun->rmt_inner = answer->rdata->u.ipv6;
- LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
- if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
- {
- LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
- tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
- question->qtype = kDNSType_AAAA;
- AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
- }
- else
- {
- LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
- tun->tc_state = TC_STATE_SRV_PEER;
- question->qtype = kDNSType_SRV;
- AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
- }
- AppendDomainName(&question->qname, &tun->dstname);
- mDNS_StartQuery(m, &tun->q);
- return;
- case TC_STATE_AAAA_PEER_RELAY:
- if (question->qtype != kDNSType_AAAA)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
- }
- // If it failed, look for the SRV record.
- if (!answer->rdlength)
- {
- LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
- tun->tc_state = TC_STATE_SRV_PEER;
- AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
- AppendDomainName(&question->qname, &tun->dstname);
- question->qtype = kDNSType_SRV;
- mDNS_StartQuery(m, &tun->q);
- return;
- }
- TunnelClientFinish(question, answer);
- return;
- case TC_STATE_SRV_PEER:
- if (question->qtype != kDNSType_SRV)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
- }
- LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
- tun->tc_state = TC_STATE_ADDR_PEER;
- AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
- tun->rmt_outer_port = answer->rdata->u.srv.port;
- question->qtype = kDNSType_A;
- mDNS_StartQuery(m, &tun->q);
- return;
- case TC_STATE_ADDR_PEER:
- if (question->qtype != kDNSType_A)
- {
- LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
- }
- TunnelClientFinish(question, answer);
- return;
- default:
- LogMsg("AutoTunnelCallback: Unknown question %p", question);
+ i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
}
-}
+ i->AppearanceTime = utc; // Brand new interface; AppearanceTime is now
+ i->LastSeen = utc;
+ i->ifa_flags = ifa->ifa_flags;
+ i->scope_id = scope_id;
+ i->BSSID = bssid;
+ i->sa_family = ifa->ifa_addr->sa_family;
+ i->BPF_fd = -1;
+ i->BPF_mcfd = -1;
+ i->BPF_len = 0;
+ i->Registered = mDNSNULL;
-// Must be called with the lock held
-mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
-{
- mDNS *const m = &mDNSStorage;
- ClientTunnel *p = mallocL("ClientTunnel", sizeof(ClientTunnel));
- if (!p) return;
- AssignDomainName(&p->dstname, &q->qname);
- p->MarkedForDeletion = mDNSfalse;
- p->loc_inner = zerov6Addr;
- p->loc_outer = zerov4Addr;
- p->loc_outer6 = zerov6Addr;
- p->rmt_inner = zerov6Addr;
- p->rmt_outer = zerov4Addr;
- p->rmt_outer6 = zerov6Addr;
- p->rmt_outer_port = zeroIPPort;
- p->tc_state = TC_STATE_AAAA_PEER;
- p->next = m->TunnelClients;
- m->TunnelClients = p; // We intentionally build list in reverse order
-
- p->q.InterfaceID = mDNSInterface_Any;
- p->q.flags = 0;
- p->q.Target = zeroAddr;
- AssignDomainName(&p->q.qname, &q->qname);
- p->q.qtype = kDNSType_AAAA;
- p->q.qclass = kDNSClass_IN;
- p->q.LongLived = mDNSfalse;
- p->q.ExpectUnique = mDNStrue;
- p->q.ForceMCast = mDNSfalse;
- p->q.ReturnIntermed = mDNStrue;
- p->q.SuppressUnusable = mDNSfalse;
- p->q.SearchListIndex = 0;
- p->q.AppendSearchDomains = 0;
- p->q.RetryWithSearchDomains = mDNSfalse;
- p->q.TimeoutQuestion = 0;
- p->q.WakeOnResolve = 0;
- p->q.UseBackgroundTrafficClass = mDNSfalse;
- p->q.ValidationRequired = 0;
- p->q.ValidatingResponse = 0;
- p->q.ProxyQuestion = 0;
- p->q.qnameOrig = mDNSNULL;
- p->q.AnonInfo = mDNSNULL;
- p->q.pid = mDNSPlatformGetPID();
- p->q.euid = 0;
- p->q.QuestionCallback = AutoTunnelCallback;
- p->q.QuestionContext = p;
-
- LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
- mDNS_StartQuery_internal(m, &p->q);
-}
+ // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
+ i->ifinfo.McastTxRx = MulticastInterface(i);
+ // Do this AFTER i->BSSID has been set up
+ i->ifinfo.NetWake = (eflags & IFEF_EXPENSIVE)? mDNSfalse : 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);
-#endif // APPLE_OSX_mDNSResponder
+ *p = i;
+ return(i);
+}
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
mDNSlocal mStatus ReorderInterfaceList()
{
// Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
- return (mStatus_NoError);
-
+#ifdef PR_30071012_FIXED
mDNS *const m = &mDNSStorage;
nwi_state_t state = nwi_state_copy();
m->HostInterfaces = newList;
nwi_state_release(state);
+#endif // PR_30071012_FIXED
return (mStatus_NoError);
}
mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
{
mDNS *const m = &mDNSStorage;
- mDNSBool foundav4 = mDNSfalse;
- mDNSBool foundav6 = mDNSfalse;
- struct ifaddrs *ifa = myGetIfAddrs(0);
- struct ifaddrs *v4Loopback = NULL;
- struct ifaddrs *v6Loopback = NULL;
+ struct ifaddrs *ifa = myGetIfAddrs(0);
char defaultname[64];
- int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
+ 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));
mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
}
- if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isCoprocessorInterface(InfoSocket, ifa->ifa_name))
+ if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isExcludedInterface(InfoSocket, ifa->ifa_name))
if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
{
if (!ifa->ifa_netmask)
if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
{
- if (ifa->ifa_flags & IFF_LOOPBACK)
- {
- if (ifa->ifa_addr->sa_family == AF_INET)
- v4Loopback = ifa;
- else if (sin6->sin6_addr.s6_addr[0] != 0xFD)
- v6Loopback = ifa;
- }
- else
- {
- NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
- if (i && MulticastInterface(i) && i->ifinfo.Advertise)
- {
- if (ifa->ifa_addr->sa_family == AF_INET)
- foundav4 = mDNStrue;
- else
- foundav6 = mDNStrue;
- }
- }
+ AddInterfaceToList(ifa, utc);
}
}
}
ifa = ifa->ifa_next;
}
- // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
- if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
- if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
-
if (InfoSocket >= 0)
close(InfoSocket);
MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
}
- mDNSBool namechange = mDNSfalse;
-
// We use a case-sensitive comparison here because even though changing the capitalization
// of the name alone is not significant to DNS, it's still a change from the user's point of view
if (SameDomainLabelCS(m->p->usernicelabel.c, nicelabel.c))
if (m->p->usernicelabel.c[0]) // Don't show message first time through, when we first read name from prefs on boot
LogMsg("User updated Computer Name from “%#s” to “%#s”", m->p->usernicelabel.c, nicelabel.c);
m->p->usernicelabel = m->nicelabel = nicelabel;
- namechange = mDNStrue;
}
if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
m->p->userhostlabel = m->hostlabel = hostlabel;
mDNS_SetFQDN(m);
- namechange = mDNStrue;
- }
-
- if (namechange) // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
- {
-#if APPLE_OSX_mDNSResponder
- DomainAuthInfo *info;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
-#endif // APPLE_OSX_mDNSResponder
}
return(mStatus_NoError);
{
NetworkInterfaceInfo *const n = &i->ifinfo;
NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
- if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
if (i->Registered && i->Registered != primary) // Sanity check
{
activationSpeed = FastActivation;
LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
else if (i->Flashing && i->Occulting)
{
activationSpeed = SlowActivation;
}
+#endif
else
{
activationSpeed = NormalActivation;
mDNS_RegisterInterface(m, n, activationSpeed);
if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
- LogInfo("SetupActiveInterfaces: Registered %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "SetupActiveInterfaces: Registered " PUB_S " (%u) BSSID " PRI_MAC_ADDR " Struct addr %p, primary %p,"
+ " " PRI_IP_ADDR "/%d" PUB_S PUB_S PUB_S,
i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
i->Flashing ? " (Flashing)" : "",
i->Occulting ? " (Occulting)" : "",
if (!n->McastTxRx)
{
debugf("SetupActiveInterfaces: No Tx/Rx on %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
// We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
// so we leave the multicast group here to clear any residual group membership.
if (i->sa_family == AF_INET)
LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
}
}
-#endif // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_IPHONE
}
else
{
activationSpeed = FastActivation;
LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
else if (i->Flashing && i->Occulting)
{
activationSpeed = SlowActivation;
}
+#endif
else
{
activationSpeed = NormalActivation;
if (!i->Exists)
{
if (i->LastSeen == utc) i->LastSeen = utc - 1;
- const mDNSBool delete = (i->isAWDL || (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0)) && (utc - i->LastSeen >= 60);
+ const mDNSBool delete = ((utc - i->LastSeen) >= 60) ? mDNStrue : mDNSfalse;
LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
&i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
{
- DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
+ DNameListElem *dnle = (DNameListElem*) callocL("DNameListElem/AppendDNameListElem", sizeof(*dnle));
if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
else
{
else { LogInfo("FinalizeSearchDomains: The hash is same"); }
}
-mDNSexport const char *DNSScopeToString(mDNSu32 scope)
-{
- switch (scope)
- {
- case kScopeNone:
- return "Unscoped";
- case kScopeInterfaceID:
- return "InterfaceScoped";
- case kScopeServiceID:
- return "ServiceScoped";
- default:
- return "Unknown";
- }
-}
-
mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope, MD5_CTX *sdc, uint64_t generation)
{
const char *scopeString = DNSScopeToString(scope);
}
}
-#if !defined(NWI_IFSTATE_FLAGS_HAS_CLAT46)
-#define NWI_IFSTATE_FLAGS_HAS_CLAT46 0x0040
-#endif
-
-mDNSlocal mDNSBool NWIInterfaceHasCLAT46(nwi_state_t state, uint32_t ifIndex)
-{
- char ifNameBuf[IFNAMSIZ + 1];
- const char *ifNamePtr = if_indextoname(ifIndex, ifNameBuf);
- if (!ifNamePtr) return(mDNSfalse);
-
- const nwi_ifstate_t ifState = nwi_state_get_ifstate(state, ifNamePtr);
- if (!ifState) return(mDNSfalse);
-
- const nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifState);
- return((flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) ? mDNStrue : mDNSfalse);
-}
-
-mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu32 resGroupID)
+mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interfaceID, mDNSu32 scope, mDNSu32 resGroupID)
{
- int n;
- domainname d;
- int serviceID = 0;
- mDNSBool cellIntf = mDNSfalse;
- mDNSBool reqA, reqAAAA;
- NetworkInterfaceInfoOSX *info;
- mDNSBool isExpensive;
- mDNSBool isCLAT46;
-
- if (!r->domain || !*r->domain)
+ domainname domain;
+ if (!r->domain || (*r->domain == '\0'))
{
- d.c[0] = 0;
+ domain.c[0] = 0;
}
- else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
+ else if (!MakeDomainNameFromDNSNameString(&domain, r->domain))
{
LogMsg("ConfigDNSServers: bad domain %s", r->domain);
return;
}
// Parse the resolver specific attributes that affects all the DNS servers.
- if (scope == kScopeServiceID)
- {
- serviceID = r->service_identifier;
- }
-
+ const int32_t serviceID = (scope == kScopeServiceID) ? r->service_identifier : 0;
+
+ const mdns_interface_monitor_t monitor = GetInterfaceMonitorForIndex((uint32_t)((uintptr_t)interfaceID));
+ const mDNSBool isExpensive = (monitor && mdns_interface_monitor_is_expensive(monitor)) ? mDNStrue : mDNSfalse;
+ const mDNSBool isConstrained = (monitor && mdns_interface_monitor_is_constrained(monitor)) ? mDNStrue : mDNSfalse;
+ const mDNSBool isCLAT46 = (monitor && mdns_interface_monitor_is_clat46(monitor)) ? mDNStrue : mDNSfalse;
+ const mDNSBool usableA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS) ? mDNStrue : mDNSfalse;
+ const mDNSBool usableAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) ? mDNStrue : mDNSfalse;
#if TARGET_OS_IPHONE
- cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
+ const mDNSBool isCell = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
+#else
+ const mDNSBool isCell = mDNSfalse;
#endif
- reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
- reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
- info = IfindexToInterfaceInfoOSX(interface);
- isExpensive = (info && info->isExpensive) ? mDNStrue : mDNSfalse;
- if (mDNSStorage.p->NWIState && interface)
- {
- const uint32_t ifIndex = (uint32_t)((uintptr_t)interface);
- isCLAT46 = NWIInterfaceHasCLAT46(mDNSStorage.p->NWIState, ifIndex);
- }
- else
- {
- isCLAT46 = mDNSfalse;
- }
- for (n = 0; n < r->n_nameserver; n++)
+ const mDNSIPPort port = (r->port != 0) ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort;
+ for (int32_t i = 0; i < r->n_nameserver; i++)
{
- mDNSAddr saddr;
- DNSServer *s;
+ const int family = r->nameserver[i]->sa_family;
+ if ((family != AF_INET) && (family != AF_INET6)) continue;
- if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
- continue;
-
- if (SetupAddr(&saddr, r->nameserver[n]))
+ mDNSAddr saddr;
+ if (SetupAddr(&saddr, r->nameserver[i]))
{
LogMsg("ConfigDNSServers: Bad address");
continue;
}
-
+
// The timeout value is for all the DNS servers in a given resolver, hence we pass
// the timeout value only for the first DNSServer. If we don't have a value in the
// resolver, then use the core's default value
// Note: this assumes that when the core picks a list of DNSServers for a question,
// it takes the sum of all the timeout values for all DNS servers. By doing this, it
// tries all the DNS servers in a specified timeout
- s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
- (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, isCLAT46,
- resGroupID, reqA, reqAAAA, mDNStrue);
+ DNSServer *s = mDNS_AddDNSServer(&mDNSStorage, &domain, interfaceID, serviceID, &saddr, port, scope,
+ (i == 0) ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0, isCell, isExpensive, isConstrained, isCLAT46,
+ resGroupID, usableA, usableAAAA, mDNStrue);
if (s)
{
- LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
+ LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s",
+ DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), domain.c);
}
}
}
}
}
-#if APPLE_OSX_mDNSResponder
-mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+mDNSlocal mDNSBool QuestionValidForDNSTrigger(const DNSQuestion *q)
{
- if (QuerySuppressed(q))
+ if (q->Suppressed)
{
debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
return mDNSfalse;
}
return mDNStrue;
}
-#endif
// This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
// We set our state appropriately so that if we start receiving answers, trigger the
// upper layer to retry DNS questions.
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
+mDNSexport void mDNSPlatformUpdateDNSStatus(const DNSQuestion *q)
{
mDNS *const m = &mDNSStorage;
if (!QuestionValidForDNSTrigger(q))
DNSTypeName(q->qtype));
}
}
-#endif
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
mDNSlocal void AckConfigd(dns_config_t *config)
{
_dns_configuration_ack(config, "com.apple.mDNSResponder");
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
// If v4q is non-NULL, it means we have received some answers for "A" type questions
// If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
+mDNSexport void mDNSPlatformTriggerDNSRetry(const DNSQuestion *v4q, const DNSQuestion *v6q)
{
mDNS *const m = &mDNSStorage;
mDNSBool trigger = mDNSfalse;
}
}
}
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
{
// Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
}
else
{
- AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
+ AssignConstStringDomainName(&ActiveDirectoryPrimaryDomain, "");
ActiveDirectoryPrimaryDomainLabelCount = 0;
ActiveDirectoryPrimaryDomainServer = zeroAddr;
}
}
CFRelease(ddnsdict);
}
-#if MDNSRESPONDER_BTMM_SUPPORT
- if (RegDomains)
- {
- CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
- if (btmm)
- {
- CFIndex size = CFDictionaryGetCount(btmm);
- const void *key[size];
- const void *val[size];
- CFDictionaryGetKeysAndValues(btmm, key, val);
- for (i = 0; i < size; i++)
- {
- LogInfo("BackToMyMac %d", i);
- if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("Can't read BackToMyMac %d key %s", i, buf);
- else
- {
- mDNSu32 uid = atoi(buf);
- if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("Can't read BackToMyMac %d val %s", i, buf);
- else if (MakeDomainNameFromDNSNameString(&d, buf) && d.c[0])
- {
- LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
- AppendDNameListElem(&RegDomains, uid, &d);
- }
- }
- }
- CFRelease(btmm);
- }
- }
-#endif
}
// Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
- DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
+ DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
{
mDNS *const m = &mDNSStorage;
MD5_CTX sdc; // search domain context
// on every update; and only updating when the generation number changes.
// If this is a DNS server update and the configuration hasn't changed, then skip update
- if (setservers && m->p->LastConfigGeneration == config->generation)
+ if (setservers && !m->p->if_interface_changed && m->p->LastConfigGeneration == config->generation)
{
LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
dns_configuration_free(config);
SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
return mDNSfalse;
}
-#if APPLE_OSX_mDNSResponder
+ if (setservers) {
+ // Must check if setservers is true, because mDNSPlatformSetDNSConfig can be called for multiple times
+ // with setservers equals to false. If setservers is false, we will end up with clearing if_interface_changed
+ // without really updating the server.
+ m->p->if_interface_changed = mDNSfalse;
+ }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
SetupActiveDirectoryDomain(config);
#endif
-
ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc);
ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc);
ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc);
+ const CFIndex n = m->p->InterfaceMonitors ? CFArrayGetCount(m->p->InterfaceMonitors) : 0;
+ for (CFIndex i = n - 1; i >= 0; i--)
+ {
+ mdns_interface_monitor_t monitor;
+ monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, i);
+ const uint32_t ifIndex = mdns_interface_monitor_get_interface_index(monitor);
+ DNSServer *server;
+ for (server = m->DNSServers; server; server = server->next)
+ {
+ if ((((uintptr_t)server->interface) == ifIndex) && !(server->flags & DNSServerFlag_Delete))
+ {
+ break;
+ }
+ }
+ if (!server)
+ {
+ mdns_retain(monitor);
+ CFArrayRemoveValueAtIndex(m->p->InterfaceMonitors, i);
+ mdns_interface_monitor_invalidate(monitor);
+ mdns_release(monitor);
+ }
+ }
+
// Acking provides a hint to other processes that the current DNS configuration has completed
// its update. When configd receives the ack, it publishes a notification.
// Applications monitoring the notification then know when to re-issue their DNS queries
else
{
const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
- if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
+ if (StatusVals[0] == NULL) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
else
{
const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
}
}
-#if MDNSRESPONDER_BTMM_SUPPORT
-#if !NO_AWACS
-
-// checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
-// keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
-// help catch it
-mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
-{
- SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
- if (!store)
- {
- LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
- return mDNSfalse;
- }
- CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
- if (btmm)
- {
- CFIndex size = CFDictionaryGetCount(btmm);
- char buf[MAX_ESCAPED_DOMAIN_NAME]; // Max legal C-string name, including terminating NUL
- const void *key[size];
- const void *val[size];
- domainname dom;
- int i;
- CFDictionaryGetKeysAndValues(btmm, key, val);
- for (i = 0; i < size; i++)
- {
- LogInfo("BackToMyMac %d", i);
- if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
- else
- {
- mDNSu32 uid = atoi(buf);
- if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
- LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
- else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
- {
- if (SameDomainName(&dom, d))
- {
- LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
- CFRelease(btmm);
- CFRelease(store);
- return mDNStrue;
- }
- }
- }
- }
- CFRelease(btmm);
- }
- CFRelease(store);
- LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
- return mDNSfalse;
-}
-
-// Appends data to the buffer
-mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
-{
- int len;
-
- len = strlcpy(buf + *currlen, data, bufsz - *currlen);
- if (len >= (bufsz - *currlen))
- {
- // if we have exceeded the space in buf, it has already been NULL terminated
- // and we have nothing more to do. Set currlen to the last byte so that the caller
- // knows to do the right thing
- LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
- *currlen = bufsz - 1;
- return -1;
- }
- else { (*currlen) += len; }
-
- buf[*currlen] = ',';
- if (*currlen >= bufsz)
- {
- LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
- *currlen = bufsz - 1;
- buf[*currlen] = 0;
- return -1;
- }
- // if we have filled up the buffer exactly, then there is no more work to do
- if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
- (*currlen)++;
- return *currlen;
-}
-
-// If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
-// BTMM domains, then bring down the connection to the relay.
-mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
-{
- DomainAuthInfo *BTMMDomain = mDNSNULL;
- DomainAuthInfo *FoundInList;
- static mDNSBool AWACSDConnected = mDNSfalse;
- char AllUsers[1024]; // maximum size of mach message
- char AllPass[1024]; // maximum size of mach message
- char username[MAX_DOMAIN_LABEL + 1];
- int currulen = 0;
- int currplen = 0;
-
- // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
- // we may not be able to send the dns queries over the relay connection which may be needed
- // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
- // need to make sure that we send the disconnect before attempting the next connect as the
- // awacs connections are redirected based on usernames.
- //
- // For now we send a disconnect immediately. When we start sending dns queries over the relay
- // connection, we will need to fix this.
-
- for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
- if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
- {
- // We need the passwd from the first domain.
- BTMMDomain = FoundInList;
- ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
- LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
- if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
- if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
- }
-
- if (BTMMDomain)
- {
- // In the normal case (where we neither exceed the buffer size nor write bytes that
- // fit exactly into the buffer), currulen/currplen should be a different size than
- // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
-
- if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
- if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
-
- LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
- AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
- AWACSDConnected = mDNStrue;
- }
- else
- {
- // Disconnect only if we connected previously
- if (AWACSDConnected)
- {
- LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
- AWACS_Disconnect();
- AWACSDConnected = mDNSfalse;
- }
- else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
- }
-}
-#else
-mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
-{
- (void) m; // Unused
- LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
-}
-#endif // ! NO_AWACS
-
-mDNSlocal void ProcessConndConfigChanges(void);
-
-#endif // MDNSRESPONDER_BTMM_SUPPORT
-
// MUST be called holding the lock
mDNSlocal void SetDomainSecrets_internal(mDNS *m)
{
(void) m;
LogMsg("Note: SetDomainSecrets: no keychain support");
#else
- mDNSBool haveAutoTunnels = mDNSfalse;
LogInfo("SetDomainSecrets");
for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
-#if APPLE_OSX_mDNSResponder
- {
- // Mark all TunnelClients for deletion
- ClientTunnel *client;
- for (client = m->TunnelClients; client; client = client->next)
- {
- LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
- client->MarkedForDeletion = mDNStrue;
- }
- }
-#endif // APPLE_OSX_mDNSResponder
-
// String Array used to write list of private domains to Dynamic Store
CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
// Iterate through the secrets
for (i = 0; i < ArrayCount; ++i)
{
- mDNSBool AutoTunnel;
int j, offset;
CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
// The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
- // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
+ // Max legal domainname as C-string, including space for dnsprefix and terminating NUL
// Get DNS domain this key is for (kmDNSKcWhere)
- char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
+ char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(dnsprefix)];
data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
{ LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
stringbuf[CFDataGetLength(data)] = '\0';
- AutoTunnel = mDNSfalse;
offset = 0;
if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
offset = strlen(dnsprefix);
-#if MDNSRESPONDER_BTMM_SUPPORT
- else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
- {
- AutoTunnel = mDNStrue;
- offset = strlen(btmmprefix);
- }
-#endif
+
domainname domain;
if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
if (SameDomainName(&FoundInList->domain, &domain)) break;
-#if APPLE_OSX_mDNSResponder
- if (FoundInList)
- {
- // If any client tunnel destination is in this domain, set deletion flag to false
- ClientTunnel *client;
- for (client = m->TunnelClients; client; client = client->next)
- if (FoundInList == GetAuthInfoForName_internal(m, &client->dstname))
- {
- LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
- client->MarkedForDeletion = mDNSfalse;
- }
- }
-
-#endif // APPLE_OSX_mDNSResponder
-
// Uncomment the line below to view the keys as they're read out of the system keychain
// DO NOT SHIP CODE THIS WAY OR YOU'LL LEAK SECRET DATA INTO A PUBLICLY READABLE FILE!
//LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
// If didn't find desired domain in the list, make a new entry
ptr = FoundInList;
- if (FoundInList && FoundInList->AutoTunnel && haveAutoTunnels == mDNSfalse) haveAutoTunnels = mDNStrue;
if (!FoundInList)
{
- ptr = (DomainAuthInfo*)mallocL("DomainAuthInfo", sizeof(*ptr));
+ ptr = (DomainAuthInfo*) callocL("DomainAuthInfo", sizeof(*ptr));
if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
}
- //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
-
- // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
- if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
+ if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port) == mStatus_BadParamErr)
{
if (!FoundInList) mDNSPlatformMemFree(ptr); // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
continue;
}
CFRelease(sa);
-#if APPLE_OSX_mDNSResponder
- {
- // clean up ClientTunnels
- ClientTunnel **pp = &m->TunnelClients;
- while (*pp)
- {
- if ((*pp)->MarkedForDeletion)
- {
- ClientTunnel *cur = *pp;
- LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
- if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
- AutoTunnelSetKeys(cur, mDNSfalse);
- *pp = cur->next;
- freeL("ClientTunnel", cur);
- }
- else
- pp = &(*pp)->next;
- }
-
- mDNSBool needAutoTunnelNAT = mDNSfalse;
- DomainAuthInfo *info;
- for (info = m->AuthInfoList; info; info = info->next)
- {
- if (info->AutoTunnel)
- {
- UpdateAutoTunnelDeviceInfoRecord(m, info);
- UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelServiceRecords(m, info);
- UpdateAutoTunnel6Record(m, info);
- if (info->deltime)
- {
- if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
- }
- else if (info->AutoTunnelServiceStarted)
- needAutoTunnelNAT = true;
-
- UpdateAutoTunnelDomainStatus(info);
- }
- }
-
- // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
- if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
- {
- // stop the NAT operation, reset port, cleanup state
- mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
- m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
- m->AutoTunnelNAT.NewAddress = zerov4Addr;
- m->AutoTunnelNAT.ExternalPort = zeroIPPort;
- m->AutoTunnelNAT.RequestedPort = zeroIPPort;
- m->AutoTunnelNAT.Lifetime = 0;
- m->AutoTunnelNAT.Result = mStatus_NoError;
- m->AutoTunnelNAT.clientContext = mDNSNULL;
- }
-
- UpdateAnonymousRacoonConfig(m); // Determine whether we need racoon to accept incoming connections
-#if MDNSRESPONDER_BTMM_SUPPORT
- ProcessConndConfigChanges(); // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
-#endif
- }
-#endif // APPLE_OSX_mDNSResponder
-
CheckSuppressUnusableQuestions(m);
#endif /* NO_SECURITYFRAMEWORK */
mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
{
-
+
CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
if (!dict)
{
else
{
CFNumberRef number = CFDictionaryGetValue(dict, name);
- if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
+ if ((number == NULL) || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
*val = 0;
CFRelease(dict);
}
-
+
}
#if APPLE_OSX_mDNSResponder
{
mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
- if (!num)
+ if (num == NULL)
LogMsg("SPSStatusPutNumber: Could not create CFNumber");
else
{
mDNSu32 tmp = SPSMetric(ptr);
CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
- if (!num)
+ if (num == NULL)
LogMsg("SPSCreateDict: Could not create CFNumber");
else
{
if (dict)
{
CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
- if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
+ if (number != NULL) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
CFRelease(dict);
}
CFRelease(store);
// Add it into the port list only if it not already present in the list
if (i >= count)
- portarray[count++] = rr->resrec.rdata->u.srv.port;
- }
- }
- }
-
- // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
- if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
- {
- LogSPS("GetPortArray Back to My Mac at %u", count);
- if (portarray) portarray[count] = IPSECPort;
- count++;
+ portarray[count++] = rr->resrec.rdata->u.srv.port;
+ }
+ }
}
return(count);
}
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
mDNSlocal mDNSBool SupportsTCPKeepAlive()
{
IOReturn ret = kIOReturnSuccess;
LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
return result;
}
-
-#endif // !TARGET_OS_EMBEDDED
+#endif
#define TfrRecordToNIC(RR) \
((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
{
if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
{
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
// Skip over all other records if we are registering TCP KeepAlive records only
// Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
{
if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
{
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
const mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
// Skip over all other records if we are registering TCP KeepAlive records only
// Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
+ // supportsTCPKA is set to true if both policy and interface allow TCP Keepalive
if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
continue;
(void) intf; // unused
(void) TCPKAOnly; // unused
(void) supportsTCPKA; // unused
-#endif // APPLE_OSX_mDNSResponder
-
+#endif
if (TfrRecordToNIC(rr))
{
records[count].sixtyfourbits = zeroOpaque64;
mDNSBool supportsTCPKA = mDNSfalse;
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
// Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive()) ? mDNStrue : mDNSfalse;
if (!offloadKeepAlivesOnly)
cmd.numRRRecords = CountProxyRecords(&cmd.rrBufferSize, TCPKAOnly, supportsTCPKA);
cmd.compression = sizeof(DNSMessageHeader);
- DNSMessage *msg = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
- cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL;
- cmd.udpPorts.ptr = cmd.numUDPPorts ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL;
- cmd.tcpPorts.ptr = cmd.numTCPPorts ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL;
+ DNSMessage *msg = (DNSMessage *) callocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
+ cmd.rrRecords.ptr = cmd.numRRRecords ? callocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr)) : NULL;
+ cmd.udpPorts.ptr = cmd.numUDPPorts ? callocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts * sizeof(mDNSIPPort)) : NULL;
+ cmd.tcpPorts.ptr = cmd.numTCPPorts ? callocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts * sizeof(mDNSIPPort)) : NULL;
LogSPS("ActivateLocalProxy: msg %p %u RR %p %u, UDP %p %u, TCP %p %u",
msg, cmd.rrBufferSize,
mDNSu8 ret = (mDNSu8)mDNS_NoWake;
#if TARGET_OS_IOS
- LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
+ LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client always disabled on TARGET_OS_IOS");
return ret;
#endif
ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
// If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
// Further policy decisions on whether to offload the records is handled during sleep processing.
if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
return val != 0 ? mDNStrue : mDNSfalse;
}
-
-#if APPLE_OSX_mDNSResponder
-// When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
-// gets deregistered, so that older peers are forced to connect over direct UDP instead of
-// the RR relay.
-//
-// When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
-// service records are deregistered, so they do not appear in peers' Finder sidebars.
-// We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
-// depend on their associated SRV record and therefore will be deregistered together in a
-// single update with the SRV record.
-//
-// Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
-// its presence shouldn't delay sleep.
-//
-// Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
-// relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
-//
-// Also note that returning false here will not delay sleep past the maximum of 10 seconds.
-mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
-{
- mDNS *const m = &mDNSStorage;
- if (!AuthRecord_uDNS(rr)) return mDNStrue;
-
- if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
- {
- LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
- return mDNSfalse;
- }
-
- if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
- {
- if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
- && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
- {
- DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
- if (info && info->AutoTunnel)
- {
- LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
- return mDNSfalse;
- }
- }
- }
-
- return mDNStrue;
-}
-
-// Caller must hold the lock
-mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
-{
- DomainAuthInfo *info;
- // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
- // deregister the record, and the MemFree callback won't re-register.
- m->AutoTunnelRelayAddr = zerov6Addr;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel)
- UpdateAutoTunnel6Record(m, info);
-}
-#endif /* APPLE_OSX_mDNSResponder */
-
-#if MDNSRESPONDER_BTMM_SUPPORT
-mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
-{
- struct ifaddrs *ifa;
- struct ifaddrs *ifaddrs;
- mDNSAddr addr;
-
- if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
-
- if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
-
- for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
- {
- if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
- continue;
- if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
- continue;
- if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
- {
- LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
- continue;
- }
- if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
- {
- LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
- break;
- }
- }
- freeifaddrs(ifaddrs);
- return ifa != NULL;
-}
-
-mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
-{
- mDNSv6Addr retVal;
- struct addrinfo hints;
- struct addrinfo *res0;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET6;
- hints.ai_flags = AI_NUMERICHOST;
-
- int err = getaddrinfo(buf, NULL, &hints, &res0);
- if (err)
- return zerov6Addr;
-
- retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
-
- freeaddrinfo(res0);
-
- return retVal;
-}
-
-mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
-{
- CFDictionaryRef connd = NULL;
- CFDictionaryRef BTMMDict = NULL;
-
- connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
- if (!connd)
- {
- LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
- goto end;
- }
-
- BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
- if (!BTMMDict)
- {
- LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
- goto end;
- }
-
- // Non-dictionary is treated as non-existent dictionary
- if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
- {
- BTMMDict = NULL;
- LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
- goto end;
- }
-
- CFRetain(BTMMDict);
-
-end:
- if (connd) CFRelease(connd);
-
- return BTMMDict;
-}
-
-#define MAX_IPV6_TEXTUAL 40
-
-mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
-{
- mDNSv6Addr retVal = zerov6Addr;
- CFTypeRef string = NULL;
- char ifname[IFNAMSIZ];
- char address[MAX_IPV6_TEXTUAL];
-
- if (!BTMMDict)
- return zerov6Addr;
-
- if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
- {
- LogInfo("ParseBackToMyMacAddr: interface key does not exist");
- return zerov6Addr;
- }
-
- if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
- {
- LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
- return zerov6Addr;
- }
-
- if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
- {
- LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
- return zerov6Addr;
- }
-
- if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
- {
- LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
- return zerov6Addr;
- }
-
- retVal = IPv6AddressFromString(address);
- LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
-
- if (mDNSIPv6AddressIsZero(retVal))
- return zerov6Addr;
-
- if (!IPv6AddressIsOnInterface(retVal, ifname))
- {
- LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
- return zerov6Addr;
- }
-
- return retVal;
-}
-
-mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
-{
- CFTypeRef zones = NULL;
-
- if (!BTMMDict)
- return NULL;
-
- if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
- {
- LogInfo("CopyBTMMZones: Zones key does not exist");
- return NULL;
- }
-
- return zones;
-}
-
-mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
-{
- mDNSv6Addr addr = zerov6Addr;
- char buffer[MAX_ESCAPED_DOMAIN_NAME];
- CFStringRef domain = NULL;
- CFTypeRef theZone = NULL;
-
- if (!zones)
- return addr;
-
- ConvertDomainNameToCString(&info->domain, buffer);
- domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
- if (!domain)
- return addr;
-
- if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
- addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
-
- CFRelease(domain);
-
- return addr;
-}
-
-mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
-{
- mDNS *const m = &mDNSStorage;
- DomainAuthInfo* info;
- CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
- mDNSv6Addr newAddr;
-
- for (info = m->AuthInfoList; info; info = info->next)
- {
- if (!info->AutoTunnel)
- continue;
-
- newAddr = ParseBackToMyMacZone(zones, info);
-
- if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
- continue;
-
- info->AutoTunnelInnerAddress = newAddr;
- DeregisterAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelHostRecord(m, info);
- UpdateAutoTunnelDomainStatus(info);
- }
-}
-
-// MUST be called holding the lock
-mDNSlocal void ProcessConndConfigChanges(void)
-{
- mDNS *const m = &mDNSStorage;
- CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
- if (!dict)
- LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
- mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
-
- LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
-
- SetupBackToMyMacInnerAddresses(dict);
-
- if (dict) CFRelease(dict);
-
- if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
- {
- m->AutoTunnelRelayAddr = relayAddr;
-
- DomainAuthInfo* info;
- for (info = m->AuthInfoList; info; info = info->next)
- if (info->AutoTunnel)
- {
- DeregisterAutoTunnel6Record(m, info);
- UpdateAutoTunnel6Record(m, info);
- UpdateAutoTunnelDomainStatus(info);
- }
-
- // Determine whether we need racoon to accept incoming connections
- UpdateAnonymousRacoonConfig(m);
- }
-
- // If awacsd crashes or exits for some reason, restart it
- UpdateBTMMRelayConnection(m);
-}
-#endif // MDNSRESPONDER_BTMM_SUPPORT
-
mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
{
DNSServer *s;
if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
{
m->NetworkChanged = NonZeroTime(m->timenow + delay);
- LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "SetNetworkChanged: Scheduling in %d ticks", delay);
}
else
- LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
+ }
}
// Called with KQueueLock & mDNS lock
mDNSexport void mDNSMacOSXNetworkChanged(void)
{
mDNS *const m = &mDNSStorage;
- LogInfo("*** Network Configuration Change *** %d ticks late%s",
- m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
- m->NetworkChanged ? "" : " (no scheduled configuration change)");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "*** Network Configuration Change *** %d ticks late" PUB_S,
+ m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
+ m->NetworkChanged ? "" : " (no scheduled configuration change)");
m->NetworkChanged = 0; // If we received a network change event and deferred processing, we're now dealing with it
// If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
{
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
{
- LogInfo("*** Network Configuration Change *** IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "*** Network Configuration Change *** IPv6 address " PRI_IPv6_ADDR " TENTATIVE, will retry",
+ &ifr6.ifr_addr.sin6_addr);
tentative = mDNStrue;
// no need to check other interfaces if we already found out that one interface is TENTATIVE
break;
mDNS_Unlock(m);
return;
}
- LogInfo("*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "*** Network Configuration Change *** No IPv6 address TENTATIVE, will continue");
}
mDNSs32 utc = mDNSPlatformUTC();
ReorderInterfaceList();
#if APPLE_OSX_mDNSResponder
-#if !TARGET_OS_EMBEDDED
-#if MDNSRESPONDER_BTMM_SUPPORT
- mDNS_Lock(m);
- ProcessConndConfigChanges();
- mDNS_Unlock(m);
-#endif
-
- // Scan to find client tunnels whose questions have completed,
- // but whose local inner/outer addresses have changed since the tunnel was set up
- ClientTunnel *p;
- for (p = m->TunnelClients; p; p = p->next)
- if (p->q.ThisQInterval < 0)
- {
- DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
- if (!info)
- {
- LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
- AutoTunnelSetKeys(p, mDNSfalse);
- }
- else
- {
- mDNSv6Addr inner = info->AutoTunnelInnerAddress;
-
- if (!mDNSIPPortIsZero(p->rmt_outer_port))
- {
- mDNSAddr tmpSrc = zeroAddr;
- mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
- tmpDst.ip.v4 = p->rmt_outer;
- mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
- if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
- !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
- {
- AutoTunnelSetKeys(p, mDNSfalse);
- p->loc_inner = inner;
- p->loc_outer = tmpSrc.ip.v4;
- AutoTunnelSetKeys(p, mDNStrue);
- }
- }
- else
- {
- if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
- !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
- {
- AutoTunnelSetKeys(p, mDNSfalse);
- p->loc_inner = inner;
- p->loc_outer6 = m->AutoTunnelRelayAddr;
- AutoTunnelSetKeys(p, mDNStrue);
- }
- }
- }
- }
-#endif //!TARGET_OS_EMBEDDED
-
SetSPS(m);
NetworkInterfaceInfoOSX *i;
}
ic = CFDictionaryGetCount(dict);
- vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
- keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
+ vals = (const void **) mDNSPlatformMemAllocate(sizeof(void *) * ic);
+ keys = (const void **) mDNSPlatformMemAllocate(sizeof(void *) * ic);
CFDictionaryGetKeysAndValues(dict, keys, vals);
// For each key we were given...
mDNS_Lock(m);
//mDNSs32 delay = mDNSPlatformOneSecond * 2; // Start off assuming a two-second delay
- const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
+ const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40; // 25 ms delay
const int c = CFArrayGetCount(changedKeys); // Count changes
CFRange range = { 0, c };
const int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
const int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS ) != 0);
const int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS ) != 0);
-#if MDNSRESPONDER_BTMM_SUPPORT
- const int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
-#else
- const int c_btmm = 0;
-#endif
const int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
int c_fast = 0;
}
}
- //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
+ //if (c && c - c_host - c_comp - c_udns - c_ddns - c_v4ll - c_fast == 0)
// delay = mDNSPlatformOneSecond/10; // If these were the only changes, shorten delay
if (mDNS_LoggingEnabled)
{
char buf[256];
if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
- LogInfo("*** Network Configuration Change *** SC key: %s", buf);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "*** Network Configuration Change *** SC key: " PUB_S, buf);
}
- LogInfo("*** Network Configuration Change *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
- c, c>1 ? "s" : "",
- c_host ? "(Local Hostname) " : "",
- c_comp ? "(Computer Name) " : "",
- c_udns ? "(DNS) " : "",
- c_ddns ? "(DynamicDNS) " : "",
- c_btmm ? "(BTMM) " : "",
- c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
- c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
- delay,
- (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "*** Network Configuration Change *** %d change" PUB_S " " PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S "delay %d" PUB_S,
+ c, c>1 ? "s" : "",
+ c_host ? "(Local Hostname) " : "",
+ c_comp ? "(Computer Name) " : "",
+ c_udns ? "(DNS) " : "",
+ c_ddns ? "(DynamicDNS) " : "",
+ c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
+ c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) " : "",
+ delay,
+ c_ddns ? " + SetKeyChainTimer" : "");
}
SetNetworkChanged(delay);
// setup the DomainAuthInfo before handing the network change.
// If we don't, then we will first try to register services in the clear, then later setup the
// DomainAuthInfo, which is incorrect.
- if (c_ddns || c_btmm)
+ if (c_ddns)
SetKeyChainTimer(delay);
// Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
#if APPLE_OSX_mDNSResponder
- // State:/Network/BackToMyMac
- UpdateAutoTunnelDomainStatuses(m);
-
// State:/Network/Interface/en0/SleepProxyServers
if (spsStatusDict)
CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
CFArrayAppendValue(keys, NetworkChangedKey_DNS);
CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
-#if MDNSRESPONDER_BTMM_SUPPORT
- CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
- CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
-#endif
CFArrayAppendValue(patterns, pattern1);
CFArrayAppendValue(patterns, pattern2);
CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
return(err);
}
-#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
-
+#if TARGET_OS_OSX
mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
{
mDNS *const m = &mDNSStorage;
intf = GetFirstActiveInterface(intf->next);
}
}
-
-#else // !TARGET_OS_EMBEDDED
-
+#else // !TARGET_OS_OSX
// Currently no packet filter setup required on embedded platforms.
mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
{
(void) excludeRecord; // unused
}
-
-#endif // !TARGET_OS_EMBEDDED
+#endif
// AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
mDNSlocal void newMasterElected(struct net_event_data * ptr)
if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
SetNetworkChanged(mDNSPlatformOneSecond * 2);
-#if !TARGET_OS_EMBEDDED // don't setup packet filter rules on embedded
-
+#if TARGET_OS_OSX
// For p2p interfaces, need to open the advertised service port in the firewall.
if (msg.k.event_code == KEV_DL_IF_ATTACHED)
{
mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
}
}
-#endif // !TARGET_OS_EMBEDDED
-
+#endif
}
mDNS_Unlock(m);
{
relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
(a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))));
-#if MDNSRESPONDER_BTMM_SUPPORT
- if (!relevant && (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix)) && !strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))
- {
- relevant = mDNStrue;
- }
-#endif
SecKeychainItemFreeAttributesAndData(a, NULL);
}
}
}
}
- // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
- // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
- // We will clear this assertion as soon as we think the mainenance activities are done.
- mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
+ // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
+ // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
+ // We will clear this assertion as soon as we think the mainenance activities are done.
+ mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
}
// iPhone OS doesn't currently have SnowLeopard's IO Power Management
// but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
-#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
+#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && TARGET_OS_OSX
mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
{
mDNS *const m = (mDNS *const)refcon;
// CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
if (m->SleepState != SleepState_Awake)
{
- PowerOn(m);
- // If the network notifications have already come before we got the wakeup, we ignored them and
- // in case we get no more, we need to trigger one.
- mDNS_Lock(m);
- SetNetworkChanged(mDNSPlatformOneSecond * 2);
- mDNS_Unlock(m);
+ PowerOn(m);
+ // If the network notifications have already come before we got the wakeup, we ignored them and
+ // in case we get no more, we need to trigger one.
+ mDNS_Lock(m);
+ SetNetworkChanged(mDNSPlatformOneSecond * 2);
+ mDNS_Unlock(m);
}
IOPMConnectionAcknowledgeEvent(connection, token);
}
{
mDNSv4Addr ip;
ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
- if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
+ if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip) && InterfaceID == rr->resrec.InterfaceID)
{
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID));
return mDNSfalse;
}
}
ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
- if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
+ if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6) && InterfaceID == rr->resrec.InterfaceID)
{
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID));
return mDNSfalse;
}
}
rr = rr->next;
}
}
- rr= mallocL("etchosts", sizeof(*rr));
+ rr = (AuthRecord *) callocL("etchosts", sizeof(*rr));
if (rr == NULL) return mDNSfalse;
- mDNSPlatformMemZero(rr, sizeof(*rr));
mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
AssignDomainName(&rr->namestorage, domain);
}
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
- LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
+ LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s ID %d", ARDisplayString(&mDNSStorage, rr), IIDPrintable(rr->resrec.InterfaceID));
InsertAuthRecord(&mDNSStorage, auth, rr);
return mDNStrue;
}
// this is a common case. To fix this, we also need to modify
// mDNS_Register_internal in how it handles duplicates. If it becomes a
// common case, we will fix it then.
- if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
+ if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec) && rr1->resrec.InterfaceID == rr->resrec.InterfaceID)
{
LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
found = mDNStrue;
// if there is no primary, point to self
rr->RRSet = (primary ? primary : rr);
rr->next = NULL;
- LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
+ LogInfo("EtcHostsAddNewEntries: Adding %s ID %d", ARDisplayString(m, rr), IIDPrintable(rr->resrec.InterfaceID));
if (mDNS_Register_internal(m, rr) != mStatus_NoError)
LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
}
AuthRecord *rr;
const domainname *pname = (domainname *)"\x9" "localhost";
- rr= mallocL("localhosts", sizeof(*rr));
+ rr = (AuthRecord *) callocL("localhosts", sizeof(*rr));
if (rr == NULL) return;
- mDNSPlatformMemZero(rr, sizeof(*rr));
mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
AssignDomainName(&rr->namestorage, domain);
// 6) client calls to enumerate domains now go over LocalOnly interface
// (!!!KRS may add outgoing interface in addition)
-#if TARGET_OS_IPHONE
-mDNSlocal mDNSBool IsAppleInternalBuild(void)
-{
- return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
-}
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, mDNSu16 type, const void *rdata, mDNSu16 rdlength)
{
switch(type)
return (mStatus_BadParamErr);
}
- AuthRecord *rr = mallocL("etchosts", sizeof(*rr));
+ AuthRecord *rr = (AuthRecord *) callocL("etchosts", sizeof(*rr));
if (!rr) return (mStatus_NoMemoryErr);
- mDNSPlatformMemZero(rr, sizeof(*rr));
mDNS_SetupResourceRecord(rr, NULL, mDNSInterface_LocalOnly, type, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
AssignDomainName(&rr->namestorage, name);
{
RegisterLocalOnlyAddressRecord(name, kDNSType_AAAA, addr->b, (mDNSu16)sizeof(mDNSv6Addr));
}
-#endif
-
-mDNSlocal void NWIEventHandler(void)
-{
- mDNS * const m = &mDNSStorage;
- nwi_state_t newState = nwi_state_copy();
-
- KQueueLock();
- const nwi_state_t oldState = m->p->NWIState;
- m->p->NWIState = newState;
- if (m->p->NWIState)
- {
- uint32_t lastIfIndex = 0;
- mDNSBool lastCLAT46 = mDNSfalse;
- for (DNSServer *server = m->DNSServers; server; server = server->next)
- {
- const uint32_t ifIndex = (uint32_t)((uintptr_t)server->interface);
- if (ifIndex == 0) continue;
- if (ifIndex == lastIfIndex)
- {
- server->isCLAT46 = lastCLAT46;
- continue;
- }
- server->isCLAT46 = NWIInterfaceHasCLAT46(m->p->NWIState, ifIndex);
- lastIfIndex = ifIndex;
- lastCLAT46 = server->isCLAT46;
- }
- }
- KQueueUnlock("NWIEventHandler");
- if (oldState) nwi_state_release(oldState);
-}
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
{
m->hostlabel.c[0] = 0;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ GetRandomUUIDLocalHostname(&m->RandomizedHostname);
+#endif
int get_model[2] = { CTL_HW, HW_MODEL };
size_t len_model = sizeof(HINFO_HWstring_buffer);
// internal code names are strings containing no commas, e.g. "N88AP".
// We used to ignore internal code names, but Apple now uses these internal code names
// even in released shipping products, so we no longer ignore strings containing no commas.
-// if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
+// if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
HINFO_HWstring = HINFO_HWstring_buffer;
else m->UnicastPort6.NotAnInteger = s6.sin6_port;
}
- m->p->InterfaceList = mDNSNULL;
- m->p->userhostlabel.c[0] = 0;
- m->p->usernicelabel.c[0] = 0;
+ m->p->InterfaceList = mDNSNULL;
+ m->p->InterfaceMonitors = NULL;
+ m->p->userhostlabel.c[0] = 0;
+ m->p->usernicelabel.c[0] = 0;
m->p->prevoldnicelabel.c[0] = 0;
m->p->prevnewnicelabel.c[0] = 0;
m->p->prevoldhostlabel.c[0] = 0;
m->p->v6answers = 1;
m->p->DNSTrigger = 0;
m->p->LastConfigGeneration = 0;
-
- m->AutoTunnelRelayAddr = zerov6Addr;
+ m->p->if_interface_changed = mDNSfalse;
NetworkChangedKey_IPv4 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
NetworkChangedKey_IPv6 = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
err = WatchForSysEvents(m);
if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
- m->p->NWIState = nwi_state_copy();
- uint32_t status = notify_register_dispatch(nwi_state_get_notify_key(), &m->p->NWINotifyToken, dispatch_get_main_queue(),
- ^(__unused int token) { NWIEventHandler(); });
- if (status == NOTIFY_STATUS_OK)
- {
- m->p->NWINotifyRegistered = mDNStrue;
- }
- else
- {
- LogMsg("mDNSPlatformInit_setup: notify_register_dispatch failed %u", status);
- }
-
mDNSs32 utc = mDNSPlatformUTC();
m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
myGetIfAddrs(1);
if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
#endif
-#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
+#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_IPHONE
LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
#else
IOPMConnection c;
#endif
if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
// On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
// file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
// standard /etc/hosts file:
mDNSMacOSXUpdateEtcHosts(m);
}
SetupLocalHostRecords();
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+ dso_transport_init();
+#endif
return(mStatus_NoError);
}
}
if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
- if (m->p->NWINotifyRegistered)
- {
- notify_cancel(m->p->NWINotifyToken);
- m->p->NWINotifyRegistered = mDNSfalse;
- }
terminateD2DPlugins();
mDNSs32 utc = mDNSPlatformUTC();
ClearInactiveInterfaces(utc);
CloseSocketSet(&m->p->permanentsockets);
-#if APPLE_OSX_mDNSResponder
- // clean up tunnels
- while (m->TunnelClients)
- {
- ClientTunnel *cur = m->TunnelClients;
- LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
- if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
- AutoTunnelSetKeys(cur, mDNSfalse);
- m->TunnelClients = cur->next;
- freeL("ClientTunnel", cur);
- }
-
- if (AnonymousRacoonConfig)
+ if (m->p->InterfaceMonitors)
{
- AnonymousRacoonConfig = mDNSNULL;
- LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
+ CFArrayRef monitors = m->p->InterfaceMonitors;
+ m->p->InterfaceMonitors = NULL;
+ const CFIndex n = CFArrayGetCount(monitors);
+ for (CFIndex i = 0; i < n; i++)
+ {
+ mdns_interface_monitor_invalidate((mdns_interface_monitor_t) CFArrayGetValueAtIndex(monitors, i));
+ }
+ CFRelease(monitors);
}
-#endif // APPLE_OSX_mDNSResponder
}
#if COMPILER_LIKES_PRAGMA_MARK
if (mDNSPlatformClockDivisor == 0) { LogMsg("mDNSPlatformRawTime called before mDNSPlatformTimeInit"); return(0); }
static uint64_t last_mach_absolute_time = 0;
- //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
+ //static uint64_t last_mach_absolute_time = 0x8000000000000000LL; // Use this value for testing the alert display
uint64_t this_mach_absolute_time = mach_absolute_time();
if ((int64_t)this_mach_absolute_time - (int64_t)last_mach_absolute_time < 0)
{
// Locking is a no-op here, because we're single-threaded with a CFRunLoop, so we can never interrupt ourselves
mDNSexport void mDNSPlatformLock (const mDNS *const m) { (void)m; }
mDNSexport void mDNSPlatformUnlock (const mDNS *const m) { (void)m; }
-mDNSexport void mDNSPlatformStrCopy( void *dst, const void *src) { strcpy((char *)dst, (const char *)src); }
mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
mDNSexport mDNSu32 mDNSPlatformStrLen ( const void *src) { return(strlen((const char*)src)); }
mDNSexport void mDNSPlatformMemCopy( void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
{
return (qsort(base, nel, width, compar));
}
-#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
-mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
-mDNSexport void * mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
+#if !MDNS_MALLOC_DEBUGGING
+mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
+mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
#endif
-mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
{
mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
{
- mDNS *const m = &mDNSStorage;
+ mDNS *const m = &mDNSStorage;
if (m->p->IOPMAssertion)
- {
- LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
+ {
+ LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
return;
- }
+ }
#ifdef kIOPMAssertionTypeNoIdleSleep
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
if (!IsAppleTV())
return; // No need for maintenance wakes on non-AppleTV embedded devices.
#endif
- double timeoutVal = (double)timeout;
+ double timeoutVal = (double)timeout;
CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
- CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
- CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
+ CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
+ CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
if (IsAppleTV())
CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
else
if ( (InterfaceID == mDNSInterface_Any)
|| (InterfaceID == mDNSInterfaceMark)
- || (InterfaceID == mDNSInterface_LocalOnly)
- || (InterfaceID == mDNSInterface_Unicast))
+ || (InterfaceID == mDNSInterface_LocalOnly))
return mDNSfalse;
// Compare to cached AWDL interface ID.
return (mDNSBool) info->D2DInterface;
}
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSexport mDNSBool mDNSPlatformInterfaceIsAWDL(const mDNSInterfaceID interfaceID)
+{
+ return ((AWDLInterfaceID && (interfaceID == AWDLInterfaceID)) ? mDNStrue : mDNSfalse);
+}
+#endif
+
// Filter records send over P2P (D2D) type interfaces
// Note that the terms P2P and D2D are used synonymously in the current code and comments.
mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
mDNSlocal mDNSu8 getModelIconColors(char *color)
{
- mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
+ mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
-#if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
- mDNSu8 red = 0;
- mDNSu8 green = 0;
- mDNSu8 blue = 0;
+#if TARGET_OS_OSX && defined(kIOPlatformDeviceEnclosureColorKey)
+ mDNSu8 red = 0;
+ mDNSu8 green = 0;
+ mDNSu8 blue = 0;
- IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
- &red, &green, &blue);
- if (kIOReturnSuccess == rGetDeviceColor)
- {
- // IOKit was able to get enclosure color for the current device.
- return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
- }
-#endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
+ IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
+ &red, &green, &blue);
+ if (kIOReturnSuccess == rGetDeviceColor)
+ {
+ // IOKit was able to get enclosure color for the current device.
+ return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
+ }
+#endif
- return 0;
+ return 0;
}
mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
ptr += VER_NUM_LEN;
- char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
- len = getModelIconColors(rgb);
- if (len)
- {
- *ptr = MODEL_COLOR_LEN + len; // length byte
- ptr++;
+ char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
+ len = getModelIconColors(rgb);
+ if (len)
+ {
+ *ptr = MODEL_COLOR_LEN + len; // length byte
+ ptr++;
- mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
- ptr += MODEL_COLOR_LEN;
+ mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
+ ptr += MODEL_COLOR_LEN;
- mDNSPlatformMemCopy(ptr, rgb, len);
- ptr += len;
- }
+ mDNSPlatformMemCopy(ptr, rgb, len);
+ ptr += len;
+ }
}
return (ptr - bufferStart);
#include <System/machine/cpu_capabilities.h>
#define _cpu_capabilities ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
-#if TARGET_OS_EMBEDDED
-
+#if TARGET_OS_IPHONE
#include <arm_neon.h>
// Cache line aligned table that returns 32 for the upper case letters.
else
LogMsg("setSameDomainLabelPointer: using scalar code");
}
+#endif // TARGET_OS_IPHONE
-#else // TARGET_OS_EMBEDDED
-
+#if TARGET_OS_OSX
#include <smmintrin.h>
// Cache line aligned table that returns 32 for the upper case letters.
else
LogMsg("setSameDomainLabelPointer: using scalar code");
}
-
-#endif // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_OSX
// Original SameDomainLabel() implementation.
mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
#endif // APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSexport void GetRandomUUIDLabel(domainlabel *label)
+{
+ uuid_t uuid;
+ uuid_string_t uuidStr;
+ uuid_generate_random(uuid);
+ uuid_unparse_lower(uuid, uuidStr);
+ MakeDomainLabelFromLiteralString(label, uuidStr);
+}
+
+mDNSexport void GetRandomUUIDLocalHostname(domainname *hostname)
+{
+ domainlabel uuidLabel;
+ GetRandomUUIDLabel(&uuidLabel);
+ hostname->c[0] = 0;
+ AppendDomainLabel(hostname, &uuidLabel);
+ AppendLiteralLabelString(hostname, "local");
+}
+#endif
#ifdef UNIT_TEST
#include "../unittests/mdns_macosx_ut.c"
#endif
-
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2018 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.
#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
#include <sys/socket.h>
#include <netinet/in.h>
-#include <network_information.h> // for nwi_state
#include "mDNSEmbeddedAPI.h" // for domain name structure
+#include "mdns_private.h" // for mdns_interface_monitor_t struct
#include <net/if.h>
#include <os/log.h>
#include <dispatch/private.h>
#endif
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
#define NO_SECURITYFRAMEWORK 1
#define NO_CFUSERNOTIFICATION 1
-#include <MobileGestalt.h> // for IsAppleTV()
#endif
#ifndef NO_SECURITYFRAMEWORK
struct TCPSocket_struct
{
- TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+ mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with mDNSIPPort
+ TCPSocketFlags flags; // MUST BE SECOND FIELD -- mDNSCore expects every TCPSocket_struct have TCPSocketFlags flags after mDNSIPPort
TCPConnectionCallback callback;
int fd;
- KQueueEntry *kqEntry;
- KQSocketSet ss;
+ KQueueEntry kqEntry;
#ifndef NO_SECURITYFRAMEWORK
SSLContextRef tlsContext;
pthread_t handshake_thread;
#endif /* NO_SECURITYFRAMEWORK */
- domainname hostname;
+ domainname *hostname;
void *context;
mDNSBool setup;
mDNSBool connected;
mStatus err;
};
+struct TCPListener_struct
+{
+ TCPAcceptedCallback callback;
+ int fd;
+ KQueueEntry kqEntry;
+ void *context;
+ mDNSAddr_Type addressType;
+ TCPSocketFlags socketFlags;
+ mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
+};
+
// Value assiged to 'Exists' to indicate the multicast state of the interface has changed.
#define MulticastStateChanged 2
int BPF_fd; // -1 uninitialized; -2 requested BPF; -3 failed
int BPF_mcfd; // Socket for our IPv6 ND group membership
u_int BPF_len;
- mDNSBool isExpensive; // True if this interface has the IFEF_EXPENSIVE flag set.
mDNSBool isAWDL; // True if this interface has the IFEF_AWDL flag set.
#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
dispatch_source_t BPF_source;
struct mDNS_PlatformSupport_struct
{
NetworkInterfaceInfoOSX *InterfaceList;
+ CFMutableArrayRef InterfaceMonitors;
KQSocketSet permanentsockets;
int num_mcasts; // Number of multicasts received during this CPU scheduling period (used for CPU limiting)
domainlabel userhostlabel; // The hostlabel as it was set in System Preferences the last time we looked
SCDynamicStoreRef Store;
CFRunLoopSourceRef StoreRLS;
CFRunLoopSourceRef PMRLS;
- nwi_state_t NWIState;
- int NWINotifyToken;
- mDNSBool NWINotifyRegistered;
int SysEventNotifier;
KQueueEntry SysEventKQueue;
IONotificationPortRef PowerPortRef;
mDNSu8 v6answers; // for A/AAAA from external DNS servers
mDNSs32 DNSTrigger; // Time the DNSTrigger was given
uint64_t LastConfigGeneration; // DNS configuration generation number
+ mDNSBool if_interface_changed; // There are some changes that we do not know from LastConfigGeneration, such as
+ // if the interface is expensive/constrained or not. Therefore, we need an additional
+ // field to determine if the interface has changed.
UDPSocket UDPProxy;
- TCPSocket TCPProxy;
+ TCPSocket TCPProxyV4;
+ TCPSocket TCPProxyV6;
ProxyCallback *UDPProxyCallback;
ProxyCallback *TCPProxyCallback;
};
extern void KQueueLock(void);
extern void KQueueUnlock(const char* task);
extern void mDNSPlatformCloseFD(KQueueEntry *kq, int fd);
+extern ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
+ struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char *ifname, mDNSu8 *ttl);
extern mDNSBool DictionaryIsEnabled(CFDictionaryRef dict);
-extern const char *DNSScopeToString(mDNSu32 scope);
-
// If any event takes more than WatchDogReportingThreshold milliseconds to be processed, we log a warning message
// General event categories are:
// o Mach client request initiated / terminated
void initializeD2DPlugins(mDNS *const m);
void terminateD2DPlugins(void);
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+extern void mDNSPlatformUpdateDNSStatus(const DNSQuestion *q);
+extern void mDNSPlatformTriggerDNSRetry(const DNSQuestion *v4q, const DNSQuestion *v6q);
+#endif
+
+extern mdns_interface_monitor_t GetInterfaceMonitorForIndex(uint32_t ifIndex);
+
#ifdef __cplusplus
}
#endif
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
- <key>com.apple.wifi.manager-access</key>
- <true/>
- <key>com.apple.SystemConfiguration.trailing-edge-agent</key>
- <true/>
- <key>com.apple.private.network.socket-delegate</key>
- <true/>
- <key>com.apple.private.SCNetworkConnection-proxy-user</key>
- <true/>
- <key>com.apple.mDNSResponder_Helper</key>
- <true/>
- <key>com.apple.private.network.reserved-port</key>
- <true/>
- <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
- <true/>
- <key>com.apple.private.snhelper</key>
- <true/>
- <key>com.apple.private.necp.match</key>
- <true/>
- <key>com.apple.security.network.server</key>
- <true/>
- <key>com.apple.security.network.client</key>
- <true/>
- <key>com.apple.private.network.awdl.restricted</key>
- <true/>
- <key>com.apple.BTServer.allowRestrictedServices</key>
- <true/>
- <key>com.apple.BTServer.appleMfgDataAdvertising</key>
- <true/>
- <key>com.apple.BTServer.appleMfgDataScanner</key>
- <true/>
- <key>com.apple.BTServer.le.att</key>
- <true/>
- <key>com.apple.private.network.delegation-whitelist</key>
- <true/>
+ <key>com.apple.BTServer.allowRestrictedServices</key>
+ <true/>
+ <key>com.apple.BTServer.appleMfgDataAdvertising</key>
+ <true/>
+ <key>com.apple.BTServer.appleMfgDataScanner</key>
+ <true/>
+ <key>com.apple.BTServer.le.att</key>
+ <true/>
+ <key>com.apple.mDNSResponder_Helper</key>
+ <true/>
+ <key>com.apple.networkd_privileged</key>
+ <true/>
+ <key>com.apple.private.necp.match</key>
+ <true/>
+ <key>com.apple.private.network.awdl.restricted</key>
+ <true/>
+ <key>com.apple.private.network.delegation-whitelist</key>
+ <true/>
+ <key>com.apple.private.network.reserved-port</key>
+ <true/>
+ <key>com.apple.private.network.socket-delegate</key>
+ <true/>
+ <key>com.apple.private.SCNetworkConnection-proxy-user</key>
+ <true/>
+ <key>com.apple.private.snhelper</key>
+ <true/>
+ <key>com.apple.private.validated-resolver</key>
+ <true/>
+ <key>com.apple.security.network.client</key>
+ <true/>
+ <key>com.apple.security.network.server</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+ <true/>
+ <key>com.apple.SystemConfiguration.trailing-edge-agent</key>
+ <true/>
+ <key>com.apple.wifi.manager-access</key>
+ <true/>
+ <key>com.apple.wifip2pd</key>
+ <true/>
</dict>
</plist>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<array>
-<dict>
- <key>OpenSourceProject</key>
- <string>libipsec</string>
- <key>OpenSourceVersion</key>
- <string>Original version number unavailable, possibly RELENG_4_9_0_RELEASE</string>
- <key>OpenSourceWebsiteURL</key>
- <string>http://www.freebsd.org</string>
- <key>OpenSourceSCM</key>
- <string>svn export http://svn.freebsd.org/base/release/4.9.0/lib/libipsec</string>
- <key>OpenSourceImportDate</key>
- <string>2007-07-31</string>
- <key>OpenSourceModifications</key>
- <array>
- <string>Removed all files except ipsec_strerror.h libpfkey.h pfkey.c</string>
- <string>Added Apple Computer copyright and Apache license</string>
- <string>Removed unused include netkey/key_var.h</string>
- <string>Fixed compiler warnings such as "unused function parameter" and "signed/unsigned comparison"</string>
- <string>Added code to conditionally compile only on OSX</string>
- <string>Whitespace changes</string>
- </array>
- <key>OpenSourceLicense</key>
- <string>bsd</string>
- <key>OpenSourceLicenseFile</key>
- <string>mDNSResponder.txt</string>
-</dict>
-</array>
-</plist>
-; -*- Mode: Scheme; tab-width: 4 -*-
;
-; Copyright (c) 2012-2018 Apple Inc. All rights reserved.
+; Copyright (c) 2012-2019 Apple Inc. All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
(global-name "com.apple.SystemConfiguration.NetworkInformation")
(global-name "com.apple.system.notification_center")
(global-name "com.apple.system.logger")
+ (global-name "com.apple.trustd")
(global-name "com.apple.usymptomsd")
(global-name "com.apple.webcontentfilter.dns")
(global-name "com.apple.server.bluetooth")
(global-name "com.apple.networkd")
(global-name "com.apple.securityd")
(global-name "com.apple.wifi.manager")
+ (global-name "com.apple.wifip2pd")
; "com.apple.blued" is the name used in pre Lobo builds,
; leave it in place while still running roots on pre Lobo targets
(global-name "com.apple.blued")
(global-name "com.apple.bluetoothd")
(global-name "com.apple.mobilegestalt.xpc")
(global-name "com.apple.ReportCrash.SimulateCrash")
- (global-name "com.apple.snhelper"))
+ (global-name "com.apple.snhelper")
+ (global-name "com.apple.networkd_privileged"))
(allow mach-register
(global-name "com.apple.d2d.ipc"))
(allow sysctl-read sysctl-write
(sysctl-name "vm.footprint_suspend"))) ; dyld performance reporting
+; Used to dump internal state
+; Allows directory lookup, and creating, reading and writing files under /private/var/log/mDNSResponder
+; We know that this sandbox rule seems to give the broader access to mDNSResponder, but given the fact that the directory
+; "/private/var/log/mDNSResponder" is owned by user "_mdnsresponder" who is in "wheel" group, no one else would have the
+; access to this directory, so there is not much security concern.
+(allow file-read* file-write* (subpath "/private/var/log/mDNSResponder"))
+++ /dev/null
-1)
- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
-
-2)
- * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
objects = {
/* Begin PBXAggregateTarget section */
- 00AD62BB032D7A0C0CCA2C71 /* Build More */ = {
+ 03067D640C83A3700022BE1F /* Build Core */ = {
isa = PBXAggregateTarget;
- buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */;
- buildPhases = (
- );
- dependencies = (
- 03067D860C849CC30022BE1F /* PBXTargetDependency */,
- D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
- D284BF300ADD81630027CCDF /* PBXTargetDependency */,
- 0C52E92F1E96AD74006EFE7B /* PBXTargetDependency */,
- 0C4F36B41E206711005A536B /* PBXTargetDependency */,
- );
- name = "Build More";
- productName = "Build All";
- };
- 03067D640C83A3700022BE1F /* Build Some */ = {
- isa = PBXAggregateTarget;
- buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
+ buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Core" */;
buildPhases = (
);
dependencies = (
03067D680C83A3830022BE1F /* PBXTargetDependency */,
03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
- 03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
- BD7833F01ABA5E3500EC51ED /* PBXTargetDependency */,
- 0C1596C71D7751AD00E09998 /* PBXTargetDependency */,
- 84C5B3411665544B00C324A8 /* PBXTargetDependency */,
- 217A4C49138EE14C000A5BA8 /* PBXTargetDependency */,
- BD9BA7721EAFA3D500658CCF /* PBXTargetDependency */,
- );
- name = "Build Some";
+ B7237FE62194D99200B113B1 /* PBXTargetDependency */,
+ D4528FFE21F91263004D61BF /* PBXTargetDependency */,
+ );
+ name = "Build Core";
productName = "Build Some";
};
2141DCF8123FFB5D0086D23E /* SystemLibraries */ = {
isa = PBXAggregateTarget;
buildConfigurationList = 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
buildPhases = (
- B7E2951A1E259AA000C42F6D /* ShellScript */,
+ B7E2951A1E259AA000C42F6D /* Copy Sandbox Profile */,
);
dependencies = (
2141DD0E123FFC960086D23E /* PBXTargetDependency */,
name = SystemLibrariesStatic;
productName = SystemLibrariesStatic;
};
- B7C4B7251E71BD5000136C7A /* Build Some iOS */ = {
+ B70F38A5217AA6CE00612D3A /* Build Extras */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = B70F38B0217AA6CE00612D3A /* Build configuration list for PBXAggregateTarget "Build Extras" */;
+ buildPhases = (
+ );
+ dependencies = (
+ B70F38A6217AA6CE00612D3A /* PBXTargetDependency */,
+ B70F38AE217AA6CE00612D3A /* PBXTargetDependency */,
+ B70F38A8217AA6CE00612D3A /* PBXTargetDependency */,
+ B7237FDA2194D0EF00B113B1 /* PBXTargetDependency */,
+ );
+ name = "Build Extras";
+ productName = "Build Extras";
+ };
+ B718416921F8D0A600CA42AD /* Build Services */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = B718417221F8D0A600CA42AD /* Build configuration list for PBXAggregateTarget "Build Services" */;
+ buildPhases = (
+ );
+ dependencies = (
+ B718416E21F8D0A600CA42AD /* PBXTargetDependency */,
+ );
+ name = "Build Services";
+ productName = "Build Some";
+ };
+ B7DB5895215EB4DD0054CD46 /* Build Extras-iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = B7DB5898215EB4DD0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-iOS" */;
+ buildPhases = (
+ );
+ dependencies = (
+ B7237FDE2194D16E00B113B1 /* PBXTargetDependency */,
+ B7DB589A215EB4F70054CD46 /* PBXTargetDependency */,
+ );
+ name = "Build Extras-iOS";
+ productName = "Build UI";
+ };
+ B7DB589D215EB61C0054CD46 /* Build Extras-macOS */ = {
isa = PBXAggregateTarget;
- buildConfigurationList = B7C4B7281E71BD5000136C7A /* Build configuration list for PBXAggregateTarget "Build Some iOS" */;
+ buildConfigurationList = B7DB58A2215EB61C0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-macOS" */;
buildPhases = (
);
dependencies = (
- B7C4B72E1E71BE3500136C7A /* PBXTargetDependency */,
- B7C4B72C1E71BD6000136C7A /* PBXTargetDependency */,
+ B7237FDC2194D16900B113B1 /* PBXTargetDependency */,
+ B7DB58C2215F04490054CD46 /* PBXTargetDependency */,
+ B7DB58A0215EB61C0054CD46 /* PBXTargetDependency */,
+ B7DB58A6215ED26D0054CD46 /* PBXTargetDependency */,
);
- name = "Build Some iOS";
- productName = "Build More iOS";
+ name = "Build Extras-macOS";
+ productName = "Build UI";
};
FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */ = {
isa = PBXAggregateTarget;
buildPhases = (
);
dependencies = (
- FFB7657D0AEED97F00583A2C /* PBXTargetDependency */,
2141DCFD123FFB7D0086D23E /* PBXTargetDependency */,
);
name = "Build All";
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
- 0C10EC281DDB956E00D7A0E3 /* LocalOnlyTimeoutTests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */; };
0C1596B51D7740B500E09998 /* mDNSPosix.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B31D7740B500E09998 /* mDNSPosix.c */; };
0C1596B61D7740B500E09998 /* NetMonitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B41D7740B500E09998 /* NetMonitor.c */; };
0C1596B81D7740C100E09998 /* mDNSUNP.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B71D7740C100E09998 /* mDNSUNP.c */; };
- 0C1596B91D7740CD00E09998 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
0C1596BA1D7740D200E09998 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
0C1596BB1D7740D700E09998 /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
0C1596BC1D7740DC00E09998 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
0C1596BE1D7740E900E09998 /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
0C1596BF1D7740EF00E09998 /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
0C1596C01D77410A00E09998 /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
- 0C5674B41DA2BF8600AF3367 /* mDNSCoreReceiveTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */; };
0C635A891E9418D90026C796 /* bjIPAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */; };
0C635A8A1E9418D90026C796 /* bjMACAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */; };
0C635A8B1E9418D90026C796 /* bjsocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7F1E9418D90026C796 /* bjsocket.cpp */; };
0C635A931E9418D90026C796 /* LLRBTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A871E9418D90026C796 /* LLRBTree.cpp */; };
0C635A941E9418D90026C796 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A881E9418D90026C796 /* main.cpp */; };
0C6FB90F1D77767300DF6F51 /* mDNSNetMonitor.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */; };
- 0C7C00501DD553640078BA89 /* unittest_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C00491DD553490078BA89 /* unittest_common.c */; };
- 0C7C00511DD5536E0078BA89 /* CNameRecordTests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */; };
- 0CB1C7FC1D9C5C1100A5939F /* D2D.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C7633D1D777B8C0077AFCA /* D2D.c */; };
21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
2124FA2C1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
- 21B830A21D8A63A300AE2001 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.dylib */; };
- 21B830A31D8A63AE00AE2001 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
- 21B830A41D8A63BB00AE2001 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- 21B830A51D8A63CB00AE2001 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
- 21B830A61D8A63E400AE2001 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
21B830A71D8A641F00AE2001 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
21B830A81D8A642200AE2001 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
- 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
- 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
21F51DC11B3541940070B05C /* com.apple.mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */; };
21F51DC31B3541F50070B05C /* com.apple.mDNSResponderHelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */; };
2E35529E0C3A9E7600CA1CB7 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
2E35529F0C3A9E7600CA1CB7 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
2E4D9B050C38C19500480551 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
- 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202520C56C36500DDFD48 /* libpfkey.h */; };
- 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */ = {isa = PBXBuildFile; fileRef = 4A8202530C56C36600DDFD48 /* pfkey.c */; };
- 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */; };
2E8165F90C59838100485EB2 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E8165F60C59835F00485EB2 /* libipsec.dylib */; };
2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0406CA0C31E9AD00F13B59 /* helper-main.c */; };
2E96A5260C39BE480087C4D2 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
2EDC5E730C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
- 371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */; };
- 371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */; };
- 373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 3732020F1BAB4349007DE806 /* DNSMessageTest.c */; };
- 37538DFC1D7A424500226BE4 /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
- 37538DFD1D7A425700226BE4 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
- 37538DFE1D7A427B00226BE4 /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
- 37538DFF1D7A428500226BE4 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
- 37538E001D7A429900226BE4 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
- 37538E011D7A429900226BE4 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
- 37538E021D7A42B000226BE4 /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
- 37538E031D7A42B000226BE4 /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
- 37538E041D7A42BE00226BE4 /* BLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA21C90A7B5004F25CC /* BLE.h */; };
- 37538E051D7A42D000226BE4 /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */; };
- 37538E061D7A42DA00226BE4 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
- 37538E071D7A42E200226BE4 /* coreBLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA51C90A82D004F25CC /* coreBLE.h */; };
- 37538E081D7A42F000226BE4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
- 37538E091D7A42FC00226BE4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
- 37538E0A1D7A430600226BE4 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
- 37538E0B1D7A432200226BE4 /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; };
- 37538E0C1D7A435200226BE4 /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
- 37538E0D1D7A437300226BE4 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
- 37538E141D7A43B600226BE4 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
- 37538E1B1D7A442300226BE4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
- 37538E1C1D7A449000226BE4 /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; };
- 37538E1D1D7A449D00226BE4 /* coreBLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA61C90A82D004F25CC /* coreBLE.m */; };
- 37538E1E1D7A4F9D00226BE4 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
- 37538E1F1D7A504F00226BE4 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
- 3771F67D1BA387DD0072355E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9351BA386E70092AC61 /* main.c */; };
- 37812CD41D7A307200F34505 /* BLE.c in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA11C90A7B5004F25CC /* BLE.c */; };
- 37812CD71D7A307200F34505 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
- 37812CD81D7A307200F34505 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
- 37812CD91D7A307200F34505 /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
- 37812CDA1D7A307200F34505 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
- 37812CDB1D7A307200F34505 /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
- 37812CDE1D7A307200F34505 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
- 37812CDF1D7A307200F34505 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
- 37812CE01D7A307200F34505 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
- 37812CE11D7A307300F34505 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
- 37812CE21D7A307300F34505 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
- 37812CE31D7A307300F34505 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
- 37812CE41D7A307300F34505 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
- 37812CE51D7A307300F34505 /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
- 37812CE91D7A307300F34505 /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
- 37812CEA1D7A307300F34505 /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
- 37812CEB1D7A307300F34505 /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
- 37812CEC1D7A307300F34505 /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
- 37812CED1D7A307300F34505 /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
- 37812CEE1D7A307300F34505 /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
- 37812CEF1D7A307300F34505 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
- 37812CF11D7A307300F34505 /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
- 37812CF21D7A307300F34505 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
- 37812CF31D7A307300F34505 /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
- 37812CF41D7A307300F34505 /* uDNSPathEvalulation.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */; };
- 37812CF51D7A307300F34505 /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
- 37812CF61D7A307300F34505 /* dnsctl_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */; };
- 37812CF71D7A307300F34505 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
- 37DDE9331BA383D30092AC61 /* unittest.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9271BA3825C0092AC61 /* unittest.c */; };
- 37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
- 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */; };
- 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */; };
4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; };
4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */; };
- 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FB545A166D5F960090B2D9 /* dnsctl.c */; };
789036921F7AC1FA0077A962 /* libnetwork.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 789036911F7AC1F90077A962 /* libnetwork.tbd */; };
- 789036931F7AC2050077A962 /* libnetwork.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 789036911F7AC1F90077A962 /* libnetwork.tbd */; };
- 8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8415A6561897109000BDBA26 /* libdns_services.dylib */; };
- 8417375C1B967D37000CD5C2 /* dnsctl_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */; };
- 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
- 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
- 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
+ 848DA5D616547F7200D2E8B4 /* xpc_clients.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* xpc_clients.h */; };
84C5B33C166553F100C324A8 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
84F4C090188F050200D1E1DE /* dns_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F4C08F188F04CF00D1E1DE /* dns_services.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 894A55D722C438AF008CDEA1 /* bats_test_proxy.sh in Resources */ = {isa = PBXBuildFile; fileRef = 894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */; };
+ 897729B22202A5370018FAEB /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
+ 897729B32202A5370018FAEB /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+ 897729B42202A5370018FAEB /* dso-transport.h in Headers */ = {isa = PBXBuildFile; fileRef = 897729B02202A5370018FAEB /* dso-transport.h */; };
+ 897729B52202A5370018FAEB /* dso.h in Headers */ = {isa = PBXBuildFile; fileRef = 897729B12202A5370018FAEB /* dso.h */; };
+ 897729B72202A5480018FAEB /* dnssd_clientshim.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729B62202A5480018FAEB /* dnssd_clientshim.c */; };
+ 898E98342203619800812DC6 /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+ 898E98352203619800812DC6 /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
+ 898E98362203621200812DC6 /* dnssd_clientshim.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729B62202A5480018FAEB /* dnssd_clientshim.c */; };
+ 898E98372203621200812DC6 /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+ 898E98382203621200812DC6 /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
+ 898E98392203633800812DC6 /* dnssd_clientshim.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729B62202A5480018FAEB /* dnssd_clientshim.c */; };
+ 898E983A2203633800812DC6 /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+ 898E983B2203633800812DC6 /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
B7016F521D5D0D2900107E7C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F511D5D0D2900107E7C /* Localizable.strings */; };
B701E7041D9DD811008F3022 /* BonjourSCStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B701E7031D9DD811008F3022 /* BonjourSCStore.m */; };
B7024D171E82FA9500312DEF /* com.apple.preference.bonjour.tool.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
B71C8B091E79F2CD00E99939 /* BonjourSCStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B701E7031D9DD811008F3022 /* BonjourSCStore.m */; };
+ B72D38B41ECB96ED00B10E39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B72D38B31ECB96ED00B10E39 /* Localizable.strings */; };
B7325FE81DA4737400663834 /* CNBrowseDomainsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */; };
B7325FF71DA47F9100663834 /* CNDomainBrowserViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */; };
B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
B7325FFD1DA4809400663834 /* DomainBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = B74EC1271D494C5800A1D155 /* DomainBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; };
B7325FFF1DA480A500663834 /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; };
+ B7473E671EC3954400D31B9D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E661EC3954400D31B9D /* AppDelegate.m */; };
+ B7473E691EC3954400D31B9D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E681EC3954400D31B9D /* main.m */; };
+ B7473E6C1EC3954400D31B9D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E6B1EC3954400D31B9D /* ViewController.m */; };
+ B7473E6E1EC3954400D31B9D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B7473E6D1EC3954400D31B9D /* Assets.xcassets */; };
+ B7473E711EC3954400D31B9D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7473E6F1EC3954400D31B9D /* Main.storyboard */; };
+ B7473E831EC395C300D31B9D /* SafariExtensionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E821EC395C300D31B9D /* SafariExtensionHandler.m */; };
+ B7473E861EC395C300D31B9D /* SafariExtensionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E851EC395C300D31B9D /* SafariExtensionViewController.m */; };
+ B7473E891EC395C300D31B9D /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B7473E871EC395C300D31B9D /* SafariExtensionViewController.xib */; };
+ B7473E911EC395C300D31B9D /* Bonjour Safari Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ B7473E961EC3C77800D31B9D /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; };
+ B7473E971EC3C77D00D31B9D /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
+ B7473E981EC3C78300D31B9D /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
+ B7473E991EC3C86600D31B9D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
B74A96261DD4EDE60084A8C5 /* Preferences.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B74A96251DD4EDE60084A8C5 /* Preferences.framework */; };
+ B74F16F4211BA55400BEBE84 /* DNSMessageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */; };
B74F2B461E82FEAE0084960E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
B74F2B471E82FEFE0084960E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
B75700241E8347A6005CD56C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B75700231E8347A6005CD56C /* InfoPlist.strings */; };
+ B76373761ECA25DE00B9404A /* CNServiceBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B76373751ECA25DE00B9404A /* CNServiceBrowserView.m */; };
B764319F1DB0423800DB376D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
B76431A01DB0423900DB376D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
B76783C11E82D8F500DA271E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B76783BC1E82D8F500DA271E /* main.m */; };
B7706AAF1DBA9C1800593FD5 /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
B778EE4D1D51113800C814A2 /* HostnameController.m in Sources */ = {isa = PBXBuildFile; fileRef = B778EE4B1D51113800C814A2 /* HostnameController.m */; };
B778EE501D51287100C814A2 /* BonjourSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */; };
+ B78A9C30223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib in Resources */ = {isa = PBXBuildFile; fileRef = B78A9C2E223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib */; };
B79568351D53F693005E3BED /* DomainBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = B74EC12B1D494C7200A1D155 /* DomainBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; };
B79568361D53F69B005E3BED /* CNDomainBrowserView.h in Headers */ = {isa = PBXBuildFile; fileRef = B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */; settings = {ATTRIBUTES = (Public, ); }; };
B799209F1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
B79920A21DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
B79920A41DA6C49700C6E02B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B79920A31DA6C49700C6E02B /* Assets.xcassets */; };
+ B79FA14B211CE8CA00B7861E /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+ B7A8618921274BFC00E81CC3 /* ResourceRecordTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */; };
+ B7A8618B21274FA200E81CC3 /* mDNSCoreReceiveTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */; };
+ B7A861952127806600E81CC3 /* unittest_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C00491DD553490078BA89 /* unittest_common.c */; };
+ B7A861972127845800E81CC3 /* CNameRecordTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A861962127845700E81CC3 /* CNameRecordTest.m */; };
+ B7A86199212B074500E81CC3 /* LocalOnlyTimeoutTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */; };
+ B7A8619B212B34CF00E81CC3 /* unittest.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A8619A212B34CF00E81CC3 /* unittest.h */; };
+ B7A861A1212B3FF400E81CC3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; };
+ B7A861A2212B408D00E81CC3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+ B7A861A3212B409200E81CC3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+ B7A861A7212B410D00E81CC3 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A4212B40BC00E81CC3 /* libxml2.tbd */; };
+ B7A861A8212B411200E81CC3 /* libicucore.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A6212B40BC00E81CC3 /* libicucore.tbd */; };
+ B7A861A9212B411600E81CC3 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A5212B40BC00E81CC3 /* Network.framework */; };
+ B7CEF6131F6354AA008B08D3 /* ToolbarItemIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = B7CEF6121F635404008B08D3 /* ToolbarItemIcon.png */; };
B7D566C91E81DA0000E43008 /* com.apple.preference.bonjour.remoteservice.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = B7D566BA1E81D8FD00E43008 /* com.apple.preference.bonjour.remoteservice.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
B7D566CD1E81DDB600E43008 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
B7D566CE1E81DDB600E43008 /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
B7D6CA7A1D107714005E24CF /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; };
B7E06B0D1DBA9DFE00E4580C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
B7E06B0E1DBA9E9700E4580C /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; };
+ B7EEF7C1212601460093828F /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+ B7EEF7C2212602EC0093828F /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+ B7EEF7C4212603B20093828F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */; };
+ B7EEF7C5212603D50093828F /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+ B7EEF7CA2126046A0093828F /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+ B7EEF7CB2126048F0093828F /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
+ B7EEF7CC212604A80093828F /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+ B7EEF7CD212604CB0093828F /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+ B7EEF7D0212605170093828F /* D2D.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C7633D1D777B8C0077AFCA /* D2D.c */; };
+ B7EEF7D6212606F50093828F /* uDNSPathEvalulation.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */; };
+ B7EEF7D7212607520093828F /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+ B7EEF7D82126076F0093828F /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
+ B7EEF7D9212607C40093828F /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
+ B7EEF7DA212608F50093828F /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
+ B7EEF7DB2126090D0093828F /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
+ B7EEF7E021260A1F0093828F /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+ B7EEF7E221260A610093828F /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+ B7EEF7E421260DC90093828F /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+ B7EEF7E521260DE80093828F /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+ B7EEF7E921260E4C0093828F /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
+ B7EEF7EA212613260093828F /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+ B7EEF7EC212613D10093828F /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
+ B7EEF7ED212613D50093828F /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
BD03E88D1AD31278005E8A81 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
+ BD11267121DB1B25006115E6 /* dnssd_server.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11267021DB1AFE006115E6 /* dnssd_server.h */; };
+ BD11267221DB1B29006115E6 /* dnssd_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */; };
+ BD11267321DB1B34006115E6 /* dnssd_server.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11266F21DB1AFE006115E6 /* dnssd_server.c */; };
+ BD11267421DB1B4D006115E6 /* dnssd_xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */; };
+ BD11267821DB2A9B006115E6 /* dnssd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11267521DB2A9A006115E6 /* dnssd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ BD11267921DB2A9B006115E6 /* dnssd_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD11267621DB2A9A006115E6 /* dnssd_object.m */; };
+ BD11267A21DB2A9B006115E6 /* dnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11267721DB2A9A006115E6 /* dnssd.c */; };
+ BD11267C21DB2C7C006115E6 /* dnssd_object.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11267B21DB2C7C006115E6 /* dnssd_object.h */; };
+ BD11267E21DB3019006115E6 /* dnssd_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */; };
+ BD11267F21DB303F006115E6 /* dnssd_xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */; };
+ BD1628CF2168B02700020528 /* ClientRequests.h in Headers */ = {isa = PBXBuildFile; fileRef = BD1628CD2168B02600020528 /* ClientRequests.h */; };
+ BD1628D02168B02700020528 /* ClientRequests.c in Sources */ = {isa = PBXBuildFile; fileRef = BD1628CE2168B02700020528 /* ClientRequests.c */; };
BD28AE8F207B892D00F0B257 /* bonjour-mcast-diagnose in Copy diagnose scripts */ = {isa = PBXBuildFile; fileRef = BD28AE8E207B88F600F0B257 /* bonjour-mcast-diagnose */; };
+ BD2A15B9225ED30C00BEA50A /* mdns_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD2A15B8225ED2E500BEA50A /* mdns_private.h */; };
+ BD2A15BA225ED31C00BEA50A /* mdns.c in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B7225ED2E500BEA50A /* mdns.c */; };
+ BD2A15BB225ED33C00BEA50A /* mdns_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B5225ED2E500BEA50A /* mdns_object.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+ BD2A15BC225ED38600BEA50A /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A5212B40BC00E81CC3 /* Network.framework */; };
BD41B27D203EBE6100A53629 /* dns_sd.h in Headers */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; settings = {ATTRIBUTES = (Public, ); }; };
BD41F9C4209B60AC0077F8B6 /* libpcap.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BD41F9C3209B60AC0077F8B6 /* libpcap.tbd */; };
+ BD42EE2021DB41970053A651 /* libobjc.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BD42EE1F21DB41970053A651 /* libobjc.tbd */; };
BD691B2A1ED2F47100E6F317 /* DNS64.c in Sources */ = {isa = PBXBuildFile; fileRef = BD691B281ED2F43200E6F317 /* DNS64.c */; };
BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */ = {isa = PBXBuildFile; fileRef = BD691B291ED2F43200E6F317 /* DNS64.h */; };
BD75E940206ADEF400656ED3 /* com.apple.mDNSResponder.plist in Copy AppleInternal Logging Profile */ = {isa = PBXBuildFile; fileRef = BDB61846206ADDDF00AFF600 /* com.apple.mDNSResponder.plist */; };
BD893CE5206C0D980055F9E7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */; };
BD893CE7206C0EAF0055F9E7 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE6206C0EAF0055F9E7 /* CoreFoundation.framework */; };
- BD9BA7551EAF91FB00658CCF /* dnssdutil.c in Sources */ = {isa = PBXBuildFile; fileRef = BD9BA7541EAF91E700658CCF /* dnssdutil.c */; };
+ BD93516E21E369B90078582E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
+ BD97754C221D643600F68FFC /* dnssdutil.c in Sources */ = {isa = PBXBuildFile; fileRef = BD97754B221D643500F68FFC /* dnssdutil.c */; };
+ BD97754F221D64BF00F68FFC /* DNSMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = BD97754D221D64BF00F68FFC /* DNSMessage.c */; };
+ BD977550221D64BF00F68FFC /* DNSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = BD97754E221D64BF00F68FFC /* DNSMessage.h */; };
+ BD98A798213A417C0002EC47 /* mDNSResponder.plist in Copy BATS test plist */ = {isa = PBXBuildFile; fileRef = BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */; };
BD9BA7581EAF929C00658CCF /* CoreUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD9BA7571EAF929C00658CCF /* CoreUtils.framework */; };
BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; };
BDA3F08F1C48DCA50054FB4B /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; };
+ BDA82B8A22BF8A7000A31CBE /* libdns_services.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA82B8922BF8A7000A31CBE /* libdns_services.tbd */; };
BDA9A7881B3A924C00523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
- BDA9A7891B3A92A500523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
BDAF4BC020B52D3D0062219E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDAF4BBF20B52D3D0062219E /* CFNetwork.framework */; };
- BDB04221203FEF4C00419961 /* dns_sd.h in Headers */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; settings = {ATTRIBUTES = (Public, ); }; };
- BDB04222203FEF4D00419961 /* dns_sd.h in Headers */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; settings = {ATTRIBUTES = (Public, ); }; };
- BDB04223203FF18000419961 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
- BDB04224203FF18000419961 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
BDB61845206ADB9D00AFF600 /* com.apple.mDNSResponder.plist in Copy Base Logging Profile */ = {isa = PBXBuildFile; fileRef = BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */; };
BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */ = {isa = PBXBuildFile; fileRef = BDBF9B931ED74B8C001498A8 /* DNS64State.h */; };
- BDE5BCCA226D7181009C723C /* DNSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE5BCC9226D7181009C723C /* DNSCommon.h */; };
- BDE5BCCC226D7198009C723C /* uDNS.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE5BCCB226D7197009C723C /* uDNS.h */; };
- BDF8BB902208E2A800419B62 /* mDNSResponder.plist in Copy BATS test plist */ = {isa = PBXBuildFile; fileRef = BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */; };
+ BDF2D02A2169961900D0DBF5 /* ClientRequests.c in Sources */ = {isa = PBXBuildFile; fileRef = BD1628CE2168B02700020528 /* ClientRequests.c */; };
+ BDF2D02C2169B77C00D0DBF5 /* SymptomReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF2D02B2169B77B00D0DBF5 /* SymptomReporter.h */; };
+ BDF2D02E216A25E800D0DBF5 /* ApplePlatformFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF2D02D216A25E800D0DBF5 /* ApplePlatformFeatures.h */; };
D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A2A07B4464B00CE10E5 /* failure.tiff */; };
D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3207B4466900CE10E5 /* BonjourPref.icns */; };
D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF260A3307B4466900CE10E5 /* BonjourPref.tiff */; };
- D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */; };
D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */; };
D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */ = {isa = PBXBuildFile; fileRef = FF08480607CEB8E800AE6769 /* inprogress.tiff */; };
D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; };
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 */; };
+ D401238B227284FE006C9BBE /* mdns.c in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B7225ED2E500BEA50A /* mdns.c */; };
+ D401238D22728506006C9BBE /* mdns_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD2A15B8225ED2E500BEA50A /* mdns_private.h */; };
+ D401238F227286BE006C9BBE /* mdns_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B5225ED2E500BEA50A /* mdns_object.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+ D40123912272B6E3006C9BBE /* mdns_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B5225ED2E500BEA50A /* mdns_object.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+ D40123922272B7A7006C9BBE /* mdns.c in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B7225ED2E500BEA50A /* mdns.c */; };
+ D421B3DF22178BE700D35C20 /* system_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = D421B3DD22178BE700D35C20 /* system_utilities.h */; };
+ D421B3E022178BE700D35C20 /* system_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D421B3DE22178BE700D35C20 /* system_utilities.c */; };
+ D448F7A8222DAB8E0069E1D2 /* bats_test_state_dump.sh in Copy script-based unit tests */ = {isa = PBXBuildFile; fileRef = D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */; };
+ D448F7A8222DAB8E0069E1D3 /* bats_test_proxy.sh in Copy script-based unit tests */ = {isa = PBXBuildFile; fileRef = 894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */; };
+ D448F7AC222DCB5C0069E1D2 /* libarchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D448F7AB222DCB5B0069E1D2 /* libarchive.tbd */; };
+ D448F7AF222DCC8F0069E1D2 /* system_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D421B3DE22178BE700D35C20 /* system_utilities.c */; };
+ D459F0D4222862BA0056AC5B /* HelperFunctionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */; };
+ D461F94A2203A6B400A88910 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = D461F9482203A6B400A88910 /* xpc_services.h */; };
+ D461F94B2203A6B400A88910 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F9492203A6B400A88910 /* xpc_services.c */; };
+ D461F94C2203A6B400A88910 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F9492203A6B400A88910 /* xpc_services.c */; };
+ D461F94F2203A8AA00A88910 /* xpc_service_dns_proxy.h in Headers */ = {isa = PBXBuildFile; fileRef = D461F94D2203A8AA00A88910 /* xpc_service_dns_proxy.h */; };
+ D461F9502203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */; };
+ D461F9512203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */; };
+ D470807322123E44006BAB32 /* libarchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D470807222123E44006BAB32 /* libarchive.tbd */; };
+ D4A1591622E27D43002F6278 /* DNSMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = BD97754D221D64BF00F68FFC /* DNSMessage.c */; };
+ D4A1591822E27F61002F6278 /* DNSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = BD97754E221D64BF00F68FFC /* DNSMessage.h */; };
+ D4A9F60521FA797F0079D0C6 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; };
+ D4BFF8DB22B1C52100A0BA86 /* posix_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */; };
+ D4BFF8DC22B1C52100A0BA86 /* posix_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = D4BFF8DA22B1C52100A0BA86 /* posix_utilities.h */; };
+ D4C2AED62203E4F900B35685 /* xpc_service_log_utility.c in Sources */ = {isa = PBXBuildFile; fileRef = D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */; };
+ D4C2AED72203E4F900B35685 /* xpc_service_log_utility.c in Sources */ = {isa = PBXBuildFile; fileRef = D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */; };
+ D4C2AED922050E8800B35685 /* xpc_client_dns_proxy.h in Headers */ = {isa = PBXBuildFile; fileRef = D4C2AED822050E8800B35685 /* xpc_client_dns_proxy.h */; };
+ D4C2AEDB22050F4E00B35685 /* xpc_client_log_utility.h in Headers */ = {isa = PBXBuildFile; fileRef = D4C2AEDA22050F4E00B35685 /* xpc_client_log_utility.h */; };
+ D4C2AEDD22052A3400B35685 /* xpc_clients.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* xpc_clients.h */; };
+ D4CFA7D121E7BA0E00F5AD0E /* liblog_mdnsresponder.m in Sources */ = {isa = PBXBuildFile; fileRef = D4CFA7D021E7BA0E00F5AD0E /* liblog_mdnsresponder.m */; };
+ D4CFA7D421E7BA9700F5AD0E /* mDNSFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = D4CFA7D221E7BA8F00F5AD0E /* mDNSFeatures.h */; };
+ D4E219202268E09F00F06AA5 /* bats_test_state_dump.sh in Resources */ = {isa = PBXBuildFile; fileRef = D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */; };
+ D4F2BB2822CD21CB00234A38 /* posix_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */; };
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 */; };
isa = PBXBuildRule;
compilerSpec = com.apple.compilers.proxy.script;
fileType = sourcecode.yacc;
+ inputFiles = (
+ );
isEditable = 1;
outputFiles = (
- "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).h",
"$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
);
- script = "echo NOOP yacc ${INPUT_FILE_PATH}";
+ script = "/usr/bin/bison -o \"${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c\" \"${INPUT_FILE_PATH}\"\n";
};
D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = {
isa = PBXBuildRule;
compilerSpec = com.apple.compilers.proxy.script;
fileType = sourcecode.lex;
+ inputFiles = (
+ );
isEditable = 1;
outputFiles = (
"$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
);
- script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}";
+ script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}\n";
};
/* End PBXBuildRule section */
remoteGlobalIDString = D284BE500ADD80740027CCDF;
remoteInfo = mDNSResponder;
};
- 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = D284BEA50ADD80920027CCDF;
- remoteInfo = "dns-sd tool";
- };
03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
remoteGlobalIDString = 2E0405EF0C31955500F13B59;
remoteInfo = mDNSResponderHelper;
};
- 03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 03067D640C83A3700022BE1F;
- remoteInfo = "Build Some";
- };
- 0C1596C61D7751AD00E09998 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 0C1596AB1D773FE300E09998;
- remoteInfo = mDNSNetMonitor;
- };
- 0C2AAB311B6929F300113637 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 84C5B3341665529800C324A8;
- remoteInfo = dns_services;
- };
- 0C4F36B31E206711005A536B /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 37DDE92C1BA383610092AC61;
- remoteInfo = unittests;
- };
- 0C52E92E1E96AD74006EFE7B /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 0C635A751E9418A60026C796;
- remoteInfo = BonjourTop;
- };
2130257012400E9300AC839F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
remoteGlobalIDString = 2141DD29123FFD2C0086D23E;
remoteInfo = libdns_sd_profile_static;
};
- 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */ = {
+ 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 213FB21712028A7A002B3A08;
- remoteInfo = BonjourEvents;
+ remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
+ remoteInfo = dns_sd.jar;
};
- 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
+ B70F38A7217AA6CE00612D3A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
- remoteInfo = dns_sd.jar;
+ remoteGlobalIDString = B74F16EA2114E49C00BEBE84;
+ remoteInfo = Tests;
+ };
+ B70F38A9217AA6CE00612D3A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BD9BA7481EAF90E400658CCF;
+ remoteInfo = dnssdutil;
+ };
+ B70F38AF217AA6CE00612D3A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D284BEA50ADD80920027CCDF;
+ remoteInfo = "dns-sd tool";
};
- 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */ = {
+ B718416F21F8D0A600CA42AD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 84C5B3341665529800C324A8;
remoteInfo = dns_services;
};
- B76783B81E82D83800DA271E /* PBXContainerItemProxy */ = {
+ B7237FD92194D0EF00B113B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = B76783AB1E82D65900DA271E;
- remoteInfo = ddnsWriteTool;
+ remoteGlobalIDString = 0C1596AB1D773FE300E09998;
+ remoteInfo = mDNSNetMonitor;
};
- B7C4B72B1E71BD6000136C7A /* PBXContainerItemProxy */ = {
+ B7237FDB2194D16900B113B1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = B74EC1151D47FC7700A1D155;
- remoteInfo = BonjourSettings;
+ remoteGlobalIDString = B70F38A5217AA6CE00612D3A;
+ remoteInfo = "Build Extras";
+ };
+ B7237FDD2194D16E00B113B1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B70F38A5217AA6CE00612D3A;
+ remoteInfo = "Build Extras";
+ };
+ B7237FE52194D99200B113B1 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 213FB21712028A7A002B3A08;
+ remoteInfo = BonjourEvents;
+ };
+ B7473E8F1EC395C300D31B9D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B7473E791EC395C300D31B9D;
+ remoteInfo = "Bonjour Extension";
};
- B7C4B72D1E71BE3500136C7A /* PBXContainerItemProxy */ = {
+ B76783B81E82D83800DA271E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 03067D640C83A3700022BE1F;
- remoteInfo = "Build Some";
+ remoteGlobalIDString = B76783AB1E82D65900DA271E;
+ remoteInfo = ddnsWriteTool;
};
B7D566C71E81D9E700E43008 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
remoteGlobalIDString = B7D566B91E81D8FD00E43008;
remoteInfo = RemoteViewService;
};
- BD7833EF1ABA5E3500EC51ED /* PBXContainerItemProxy */ = {
+ B7DB5899215EB4F70054CD46 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 72FB545E166D5FB00090B2D9;
- remoteInfo = dnsctl;
+ remoteGlobalIDString = B74EC1151D47FC7700A1D155;
+ remoteInfo = BonjourSettings;
};
- BD9BA7711EAFA3D500658CCF /* PBXContainerItemProxy */ = {
+ B7DB58A1215EB61C0054CD46 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = BD9BA7481EAF90E400658CCF;
- remoteInfo = dnssdutil;
+ remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
+ remoteInfo = PreferencePane;
};
- D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
+ B7DB58A5215ED26D0054CD46 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
- remoteInfo = dnsextd;
+ remoteGlobalIDString = B7473E601EC3954400D31B9D;
+ remoteInfo = "Bonjour Safari Menu";
};
- D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
+ B7DB58C1215F04490054CD46 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
proxyType = 1;
- remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
- remoteInfo = PreferencePane;
+ remoteGlobalIDString = 0C635A751E9418A60026C796;
+ remoteInfo = BonjourTop;
+ };
+ D4528FFD21F91263004D61BF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = D4CFA7CB21E7B95E00F5AD0E;
+ remoteInfo = liblog_mdnsresponder;
};
FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
remoteGlobalIDString = FFA5723C0AF18F450055A0F1;
remoteInfo = "libdns_sd profile";
};
- FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71;
- remoteInfo = "Build Main";
- };
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
);
runOnlyForDeploymentPostprocessing = 1;
};
- 4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/local/OpenSourceVersions;
- dstSubfolderSpec = 0;
- files = (
- 4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
- 4A7B9E8114FDA25500B84CC1 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 8;
- dstPath = /usr/local/OpenSourceLicenses;
- dstSubfolderSpec = 0;
- files = (
- 4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */,
- );
- runOnlyForDeploymentPostprocessing = 1;
- };
4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
);
runOnlyForDeploymentPostprocessing = 1;
};
- 72FB545D166D5FB00090B2D9 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 12;
- dstPath = /usr/share/man/man1/;
- dstSubfolderSpec = 0;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
8418673D15AB8BFF00BB7F70 /* Copy Base Logging Profile */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
name = "Copy Base Logging Profile";
runOnlyForDeploymentPostprocessing = 1;
};
+ B7473E951EC395C300D31B9D /* Embed App Extensions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 13;
+ files = (
+ B7473E911EC395C300D31B9D /* Bonjour Safari Extension.appex in Embed App Extensions */,
+ );
+ name = "Embed App Extensions";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
B7D566C61E81D9B600E43008 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
name = "Copy AppleInternal Logging Profile";
runOnlyForDeploymentPostprocessing = 1;
};
- BDF8BB8A2208E09D00419B62 /* Copy BATS test plist */ = {
+ BD98A797213A41240002EC47 /* Copy BATS test plist */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
dstSubfolderSpec = 0;
files = (
- BDF8BB902208E2A800419B62 /* mDNSResponder.plist in Copy BATS test plist */,
+ BD98A798213A417C0002EC47 /* mDNSResponder.plist in Copy BATS test plist */,
);
name = "Copy BATS test plist";
runOnlyForDeploymentPostprocessing = 1;
);
runOnlyForDeploymentPostprocessing = 1;
};
+ D448F7A5222DA8E20069E1D2 /* Copy script-based unit tests */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /AppleInternal/Tests/mDNSResponder;
+ dstSubfolderSpec = 0;
+ files = (
+ D448F7A8222DAB8E0069E1D2 /* bats_test_state_dump.sh in Copy script-based unit tests */,
+ D448F7A8222DAB8E0069E1D3 /* bats_test_proxy.sh in Copy script-based unit tests */,
+ );
+ name = "Copy script-based unit tests";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
FFFF8F770C32F0FD00722979 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 8;
000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
- 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = LocalOnlyTimeoutTests.c; path = ../unittests/LocalOnlyTimeoutTests.c; sourceTree = "<group>"; };
- 0C10EC271DDB956000D7A0E3 /* LocalOnlyTimeoutTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalOnlyTimeoutTests.h; path = ../unittests/LocalOnlyTimeoutTests.h; sourceTree = "<group>"; };
0C1596AC1D773FE300E09998 /* mDNSNetMonitor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSNetMonitor; sourceTree = BUILT_PRODUCTS_DIR; };
0C1596B31D7740B500E09998 /* mDNSPosix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSPosix.c; path = ../../mDNSPosix/mDNSPosix.c; sourceTree = "<group>"; };
0C1596B41D7740B500E09998 /* NetMonitor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = NetMonitor.c; path = ../../mDNSPosix/NetMonitor.c; sourceTree = "<group>"; };
0C1596B71D7740C100E09998 /* mDNSUNP.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSUNP.c; path = ../../mDNSPosix/mDNSUNP.c; sourceTree = "<group>"; };
- 0C5674B11DA2BF6300AF3367 /* mDNSCoreReceiveTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSCoreReceiveTest.h; path = ../unittests/mDNSCoreReceiveTest.h; sourceTree = "<group>"; };
- 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSCoreReceiveTest.c; path = ../unittests/mDNSCoreReceiveTest.c; sourceTree = "<group>"; };
0C635A761E9418A60026C796 /* bonjourtop */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bonjourtop; sourceTree = BUILT_PRODUCTS_DIR; };
0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjIPAddr.cpp; path = source/bjIPAddr.cpp; sourceTree = "<group>"; };
0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjMACAddr.cpp; path = source/bjMACAddr.cpp; sourceTree = "<group>"; };
0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSNetMonitor.8; sourceTree = "<group>"; };
0C7C00491DD553490078BA89 /* unittest_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest_common.c; path = ../unittests/unittest_common.c; sourceTree = "<group>"; };
0C7C004A1DD553490078BA89 /* unittest_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest_common.h; path = ../unittests/unittest_common.h; sourceTree = "<group>"; };
- 0C7C004B1DD553490078BA89 /* mdns_macosx_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mdns_macosx_ut.c; path = ../unittests/mdns_macosx_ut.c; sourceTree = "<group>"; };
- 0C7C004C1DD553490078BA89 /* mdns_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mdns_ut.c; path = ../unittests/mdns_ut.c; sourceTree = "<group>"; };
- 0C7C004D1DD553490078BA89 /* uds_daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon_ut.c; path = ../unittests/uds_daemon_ut.c; sourceTree = "<group>"; };
- 0C7C004E1DD553490078BA89 /* CNameRecordTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CNameRecordTests.h; path = ../unittests/CNameRecordTests.h; sourceTree = "<group>"; };
- 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CNameRecordTests.c; path = ../unittests/CNameRecordTests.c; sourceTree = "<group>"; };
- 0C84A2911E786AFF00E8B4C7 /* daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daemon_ut.c; path = ../unittests/daemon_ut.c; sourceTree = "<group>"; };
21070E5D16486B9000A69507 /* DNSSECSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSSECSupport.c; sourceTree = "<group>"; };
21070E5E16486B9000A69507 /* DNSSECSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSSECSupport.h; sourceTree = "<group>"; };
2124FA2B1471E98C0021D7BB /* nsec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec.h; path = ../mDNSCore/nsec.h; sourceTree = "<group>"; };
21A57F4B145B2AE100939099 /* CryptoAlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoAlg.h; path = ../mDNSCore/CryptoAlg.h; sourceTree = "<group>"; };
21A57F51145B2B1400939099 /* CryptoSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CryptoSupport.c; sourceTree = "<group>"; };
21A57F52145B2B1400939099 /* CryptoSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoSupport.h; sourceTree = "<group>"; };
- 21DD8FBD161E9A250033C8F8 /* anonymous.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = anonymous.c; path = ../mDNSCore/anonymous.c; sourceTree = "<group>"; };
- 21DD8FBE161E9A250033C8F8 /* anonymous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = anonymous.h; path = ../mDNSCore/anonymous.h; sourceTree = "<group>"; };
21DED43415702C0F0060B6B9 /* DNSProxySupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSProxySupport.c; sourceTree = "<group>"; };
- 21F432971134AA6800581B69 /* WebFilterDNS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebFilterDNS.framework; path = /System/Library/PrivateFrameworks/WebFilterDNS.framework; sourceTree = "<absolute>"; };
21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.dnsextd.plist; sourceTree = "<group>"; };
21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponderHelper.plist; sourceTree = "<group>"; };
21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = "<group>"; };
2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = "<group>"; };
2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = "<group>"; };
- 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = InterfaceTest.c; path = ../unittests/InterfaceTest.c; sourceTree = "<group>"; };
- 371D0FBB1BF545FA00E5DB26 /* InterfaceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InterfaceTest.h; path = ../unittests/InterfaceTest.h; sourceTree = "<group>"; };
- 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ResourceRecordTest.c; path = ../unittests/ResourceRecordTest.c; sourceTree = "<group>"; };
- 371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResourceRecordTest.h; path = ../unittests/ResourceRecordTest.h; sourceTree = "<group>"; };
- 3732020F1BAB4349007DE806 /* DNSMessageTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSMessageTest.c; path = ../unittests/DNSMessageTest.c; sourceTree = "<group>"; };
- 373202111BAB63E8007DE806 /* DNSMessageTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSMessageTest.h; path = ../unittests/DNSMessageTest.h; sourceTree = "<group>"; };
37538E131D7A43B600226BE4 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
- 37AF802A1BF699AF00D657F6 /* DomainNameTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DomainNameTest.c; path = ../unittests/DomainNameTest.c; sourceTree = "<group>"; };
- 37AF802B1BF699AF00D657F6 /* DomainNameTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DomainNameTest.h; path = ../unittests/DomainNameTest.h; sourceTree = "<group>"; };
- 37DDE9271BA3825C0092AC61 /* unittest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest.c; path = ../unittests/unittest.c; sourceTree = "<group>"; };
- 37DDE9281BA382670092AC61 /* unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest.h; path = ../unittests/unittest.h; sourceTree = "<group>"; };
- 37DDE92D1BA383610092AC61 /* unittests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unittests; sourceTree = BUILT_PRODUCTS_DIR; };
- 37DDE9351BA386E70092AC61 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../unittests/main.c; sourceTree = "<group>"; };
4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uds_daemon.h; path = ../mDNSShared/uds_daemon.h; sourceTree = SOURCE_ROOT; };
4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceToDeviceManager.framework; path = /System/Library/PrivateFrameworks/DeviceToDeviceManager.framework; sourceTree = "<absolute>"; };
- 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = mDNSResponder.txt; sourceTree = "<group>"; };
- 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
- 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = "<group>"; };
- 4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = "<group>"; };
- 4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = "<group>"; };
4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; };
4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "helper-entitlements.plist"; sourceTree = "<group>"; };
4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = P2PPacketFilter.c; sourceTree = "<group>"; };
6575FBE9022EAF5A00000109 /* mDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; name = mDNS.c; path = ../mDNSCore/mDNS.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
- 72FB545A166D5F960090B2D9 /* dnsctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dnsctl.c; path = ../Clients/dnsctl.c; sourceTree = "<group>"; };
- 72FB545F166D5FB00090B2D9 /* dnsctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsctl; sourceTree = BUILT_PRODUCTS_DIR; };
789036911F7AC1F90077A962 /* libnetwork.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libnetwork.tbd; path = usr/lib/libnetwork.tbd; sourceTree = SDKROOT; };
7F18A9F60587CEF6001880B3 /* DNSCommon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSCommon.c; path = ../mDNSCore/DNSCommon.c; sourceTree = SOURCE_ROOT; };
7F18A9F70587CEF6001880B3 /* uDNS.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uDNS.c; path = ../mDNSCore/uDNS.c; sourceTree = SOURCE_ROOT; };
7F869685066EE02400D2A2DC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = "<absolute>"; };
7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = LegacyNATTraversal.c; sourceTree = SOURCE_ROOT; };
8415A6561897109000BDBA26 /* libdns_services.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libdns_services.dylib; path = /usr/lib/libdns_services.dylib; sourceTree = "<absolute>"; };
- 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsctl_server.c; path = Private/dnsctl_server.c; sourceTree = "<group>"; };
- 848DA5C6165477E000D2E8B4 /* xpc_services.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xpc_services.c; path = Private/xpc_services.c; sourceTree = "<group>"; };
- 848DA5C9165477EB00D2E8B4 /* xpc_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xpc_services.h; path = Private/xpc_services.h; sourceTree = "<group>"; };
- 848DA5D516547F7200D2E8B4 /* dns_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_xpc.h; path = Private/dns_xpc.h; sourceTree = "<group>"; };
+ 848DA5D516547F7200D2E8B4 /* xpc_clients.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpc_clients.h; sourceTree = "<group>"; };
84C5B3351665529800C324A8 /* libdns_services.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdns_services.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
84C5B339166553AF00C324A8 /* dns_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dns_services.c; path = Private/dns_services.c; sourceTree = "<group>"; };
84F4C08F188F04CF00D1E1DE /* dns_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_services.h; path = Private/dns_services.h; sourceTree = "<group>"; };
+ 894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = bats_test_proxy.sh; sourceTree = "<group>"; };
+ 897729AE2202A5370018FAEB /* dso.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dso.c; path = ../DSO/dso.c; sourceTree = "<group>"; };
+ 897729AF2202A5370018FAEB /* dso-transport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dso-transport.c"; path = "../DSO/dso-transport.c"; sourceTree = "<group>"; };
+ 897729B02202A5370018FAEB /* dso-transport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dso-transport.h"; path = "../DSO/dso-transport.h"; sourceTree = "<group>"; };
+ 897729B12202A5370018FAEB /* dso.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dso.h; path = ../DSO/dso.h; sourceTree = "<group>"; };
+ 897729B62202A5480018FAEB /* dnssd_clientshim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientshim.c; path = ../mDNSShared/dnssd_clientshim.c; sourceTree = "<group>"; };
B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = DomainBrowser.strings; sourceTree = "<group>"; };
B7016F511D5D0D2900107E7C /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Localizable.strings; path = ../SettingsBundle/Localizable.strings; sourceTree = "<group>"; };
B701E7031D9DD811008F3022 /* BonjourSCStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BonjourSCStore.m; path = ../SettingsBundle/BonjourSCStore.m; sourceTree = "<group>"; };
B716801A1E8330B400459A35 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
B72C96091D6236A500AD682A /* BonjourSCStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BonjourSCStore.h; path = ../SettingsBundle/BonjourSCStore.h; sourceTree = "<group>"; };
+ B72D38B31ECB96ED00B10E39 /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
B7325FE61DA4737400663834 /* CNBrowseDomainsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CNBrowseDomainsController.h; path = ../SettingsBundle/CNBrowseDomainsController.h; sourceTree = "<group>"; };
B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CNBrowseDomainsController.m; path = ../SettingsBundle/CNBrowseDomainsController.m; sourceTree = "<group>"; };
B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ B735A2EE21B8293900025BB0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ B7473E611EC3954400D31B9D /* Bonjour Safari Menu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Bonjour Safari Menu.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ B7473E641EC3954400D31B9D /* BonjourSafariMenu.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BonjourSafariMenu.entitlements; sourceTree = "<group>"; };
+ B7473E651EC3954400D31B9D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ B7473E661EC3954400D31B9D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ B7473E681EC3954400D31B9D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ B7473E6A1EC3954400D31B9D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ B7473E6B1EC3954400D31B9D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ B7473E6D1EC3954400D31B9D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ B7473E701EC3954400D31B9D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ B7473E721EC3954400D31B9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Bonjour Safari Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
+ B7473E801EC395C300D31B9D /* BonjourSafariExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BonjourSafariExtension.entitlements; sourceTree = "<group>"; };
+ B7473E811EC395C300D31B9D /* SafariExtensionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SafariExtensionHandler.h; sourceTree = "<group>"; };
+ B7473E821EC395C300D31B9D /* SafariExtensionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SafariExtensionHandler.m; sourceTree = "<group>"; };
+ B7473E841EC395C300D31B9D /* SafariExtensionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SafariExtensionViewController.h; sourceTree = "<group>"; };
+ B7473E851EC395C300D31B9D /* SafariExtensionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SafariExtensionViewController.m; sourceTree = "<group>"; };
+ B7473E881EC395C300D31B9D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SafariExtensionViewController.xib; sourceTree = "<group>"; };
+ B7473E8A1EC395C300D31B9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ B7473E8B1EC395C300D31B9D /* script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = script.js; sourceTree = "<group>"; };
B74A96251DD4EDE60084A8C5 /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/PrivateFrameworks/Preferences.framework; sourceTree = DEVELOPER_DIR; };
B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BonjourSettings.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
B74EC11B1D47FC7800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../SettingsBundle/Info.plist; sourceTree = "<group>"; };
B74EC1281D494C5800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B74EC1291D494C6700A1D155 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B74EC12B1D494C7200A1D155 /* DomainBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainBrowser.h; sourceTree = "<group>"; };
+ B74F16EB2114E49C00BEBE84 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ B74F16EF2114E49D00BEBE84 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSMessageTest.m; sourceTree = "<group>"; };
B75700231E8347A6005CD56C /* InfoPlist.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = InfoPlist.strings; sourceTree = "<group>"; };
+ B76373741ECA25DE00B9404A /* CNServiceBrowserView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNServiceBrowserView.h; sourceTree = "<group>"; };
+ B76373751ECA25DE00B9404A /* CNServiceBrowserView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNServiceBrowserView.m; sourceTree = "<group>"; };
B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = com.apple.preference.bonjour.tool.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
B76783BB1E82D8F500DA271E /* BonjourPrefTool-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourPrefTool-Info.plist"; sourceTree = "<group>"; };
B76783BC1E82D8F500DA271E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
B778EE4B1D51113800C814A2 /* HostnameController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HostnameController.m; path = ../SettingsBundle/HostnameController.m; sourceTree = "<group>"; };
B778EE4E1D51287100C814A2 /* BonjourSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BonjourSettingsController.h; path = ../SettingsBundle/BonjourSettingsController.h; sourceTree = "<group>"; };
B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BonjourSettingsController.m; path = ../SettingsBundle/BonjourSettingsController.m; sourceTree = "<group>"; };
+ B78A9C2F223941A900BFB0C6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/DNSServiceDiscoveryPref.xib; sourceTree = "<group>"; };
+ B78A9C322239485E00BFB0C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserPathUtils.h; sourceTree = "<group>"; };
B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserPathUtils.m; sourceTree = "<group>"; };
B79920A31DA6C49700C6E02B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../SettingsBundle/Assets.xcassets; sourceTree = "<group>"; };
+ B79FA153211CF0AF00B7861E /* dnsproxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dnsproxy.h; sourceTree = "<group>"; };
+ B79FA154211CF0AF00B7861E /* uDNS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = uDNS.h; sourceTree = "<group>"; };
+ B79FA155211CF0AF00B7861E /* nsec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nsec.h; sourceTree = "<group>"; };
+ B79FA156211CF0AF00B7861E /* DNSCommon.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DNSCommon.c; sourceTree = "<group>"; };
+ B79FA157211CF0AF00B7861E /* mDNSDebug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mDNSDebug.h; sourceTree = "<group>"; };
+ B79FA158211CF0AF00B7861E /* dnssec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dnssec.c; sourceTree = "<group>"; };
+ B79FA159211CF0AF00B7861E /* CryptoAlg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoAlg.h; sourceTree = "<group>"; };
+ B79FA15A211CF0AF00B7861E /* nsec3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nsec3.h; sourceTree = "<group>"; };
+ B79FA15B211CF0AF00B7861E /* Implementer Notes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Implementer Notes.txt"; sourceTree = "<group>"; };
+ B79FA15C211CF0AF00B7861E /* nsec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nsec.c; sourceTree = "<group>"; };
+ B79FA15D211CF0AF00B7861E /* uDNS.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = uDNS.c; sourceTree = "<group>"; };
+ B79FA15E211CF0AF00B7861E /* dnsproxy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dnsproxy.c; sourceTree = "<group>"; };
+ B79FA15F211CF0AF00B7861E /* dnssec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dnssec.h; sourceTree = "<group>"; };
+ B79FA160211CF0AF00B7861E /* mDNS.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mDNS.c; sourceTree = "<group>"; };
+ B79FA162211CF0AF00B7861E /* DNSCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DNSCommon.h; sourceTree = "<group>"; };
+ B79FA163211CF0AF00B7861E /* CryptoAlg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = CryptoAlg.c; sourceTree = "<group>"; };
+ B79FA164211CF0AF00B7861E /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mDNSEmbeddedAPI.h; sourceTree = "<group>"; };
+ B79FA165211CF0AF00B7861E /* nsec3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nsec3.c; sourceTree = "<group>"; };
+ B79FA166211CF0AF00B7861E /* DNSDigest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DNSDigest.c; sourceTree = "<group>"; };
B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserViewController.h; sourceTree = "<group>"; };
B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserViewController.m; sourceTree = "<group>"; };
+ B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResourceRecordTest.m; sourceTree = "<group>"; };
+ B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = mDNSCoreReceiveTest.m; sourceTree = "<group>"; };
+ B7A861962127845700E81CC3 /* CNameRecordTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNameRecordTest.m; sourceTree = "<group>"; };
+ B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalOnlyTimeoutTest.m; sourceTree = "<group>"; };
+ B7A8619A212B34CF00E81CC3 /* unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest.h; path = ../unittests/unittest.h; sourceTree = "<group>"; };
+ B7A8619E212B368700E81CC3 /* daemon_ut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = daemon_ut.c; path = ../unittests/daemon_ut.c; sourceTree = "<group>"; };
+ B7A8619F212B36EC00E81CC3 /* mdns_macosx_ut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdns_macosx_ut.c; path = ../unittests/mdns_macosx_ut.c; sourceTree = "<group>"; };
+ B7A861A0212B370700E81CC3 /* mdns_ut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdns_ut.c; path = ../unittests/mdns_ut.c; sourceTree = "<group>"; };
+ B7A861A4212B40BC00E81CC3 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = usr/lib/libxml2.tbd; sourceTree = SDKROOT; };
+ B7A861A5212B40BC00E81CC3 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };
+ B7A861A6212B40BC00E81CC3 /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; };
+ B7CEF6121F635404008B08D3 /* ToolbarItemIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ToolbarItemIcon.png; sourceTree = "<group>"; };
B7D566A51E81D6A900E43008 /* BonjourPrefRemoteViewService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourPrefRemoteViewService-Info.plist"; sourceTree = "<group>"; };
B7D566A71E81D6A900E43008 /* BonjourPrefRemoteViewService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BonjourPrefRemoteViewService.h; sourceTree = "<group>"; };
B7D566A81E81D6A900E43008 /* BonjourPrefRemoteViewService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BonjourPrefRemoteViewService.m; sourceTree = "<group>"; };
B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserView.h; sourceTree = "<group>"; };
B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserView.m; sourceTree = "<group>"; };
B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- B7E5920F1DB687A700A38085 /* Base */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = Base; path = Base.lproj/DNSServiceDiscoveryPref.nib; sourceTree = "<group>"; };
BD03E88C1AD31278005E8A81 /* SymptomReporter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SymptomReporter.c; sourceTree = "<group>"; };
+ BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_xpc.h; sourceTree = "<group>"; };
+ BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd_xpc.c; sourceTree = "<group>"; };
+ BD11266F21DB1AFE006115E6 /* dnssd_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd_server.c; sourceTree = "<group>"; };
+ BD11267021DB1AFE006115E6 /* dnssd_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_server.h; sourceTree = "<group>"; };
+ BD11267521DB2A9A006115E6 /* dnssd_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_private.h; sourceTree = "<group>"; };
+ BD11267621DB2A9A006115E6 /* dnssd_object.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = dnssd_object.m; sourceTree = "<group>"; };
+ BD11267721DB2A9A006115E6 /* dnssd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd.c; sourceTree = "<group>"; };
+ BD11267B21DB2C7C006115E6 /* dnssd_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_object.h; sourceTree = "<group>"; };
+ BD1628CD2168B02600020528 /* ClientRequests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClientRequests.h; path = ../mDNSShared/ClientRequests.h; sourceTree = "<group>"; };
+ BD1628CE2168B02700020528 /* ClientRequests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ClientRequests.c; path = ../mDNSShared/ClientRequests.c; sourceTree = "<group>"; };
BD28AE8E207B88F600F0B257 /* bonjour-mcast-diagnose */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "bonjour-mcast-diagnose"; sourceTree = "<group>"; };
+ BD2A15B5225ED2E500BEA50A /* mdns_object.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = mdns_object.m; sourceTree = "<group>"; };
+ BD2A15B6225ED2E500BEA50A /* mdns_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mdns_object.h; sourceTree = "<group>"; };
+ BD2A15B7225ED2E500BEA50A /* mdns.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mdns.c; sourceTree = "<group>"; };
+ BD2A15B8225ED2E500BEA50A /* mdns_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mdns_private.h; sourceTree = "<group>"; };
BD41F9C3209B60AC0077F8B6 /* libpcap.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpcap.tbd; path = usr/lib/libpcap.tbd; sourceTree = SDKROOT; };
+ BD42EE1F21DB41970053A651 /* libobjc.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libobjc.tbd; path = usr/lib/libobjc.tbd; sourceTree = SDKROOT; };
BD691B281ED2F43200E6F317 /* DNS64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNS64.c; sourceTree = "<group>"; };
BD691B291ED2F43200E6F317 /* DNS64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64.h; sourceTree = "<group>"; };
BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
BD893CE6206C0EAF0055F9E7 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ BD97754B221D643500F68FFC /* dnssdutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssdutil.c; sourceTree = "<group>"; };
+ BD97754D221D64BF00F68FFC /* DNSMessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSMessage.c; sourceTree = "<group>"; usesTabs = 1; };
+ BD97754E221D64BF00F68FFC /* DNSMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSMessage.h; sourceTree = "<group>"; };
+ BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
BD9BA7531EAF90E400658CCF /* dnssdutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnssdutil; sourceTree = BUILT_PRODUCTS_DIR; };
- BD9BA7541EAF91E700658CCF /* dnssdutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssdutil.c; path = ../Clients/dnssdutil.c; sourceTree = "<group>"; };
BD9BA7571EAF929C00658CCF /* CoreUtils.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreUtils.framework; path = System/Library/PrivateFrameworks/CoreUtils.framework; sourceTree = SDKROOT; };
BDA3F0871C48DB6D0054FB4B /* Metrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metrics.h; sourceTree = "<group>"; };
BDA3F0881C48DB6D0054FB4B /* Metrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Metrics.m; sourceTree = "<group>"; };
BDA3F0891C48DB910054FB4B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ BDA82B8922BF8A7000A31CBE /* libdns_services.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libdns_services.tbd; path = usr/lib/libdns_services.tbd; sourceTree = SDKROOT; };
BDA9A7871B3A923600523835 /* dns_sd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dns_sd_private.h; path = ../mDNSShared/dns_sd_private.h; sourceTree = "<group>"; };
BDAF4BBF20B52D3D0062219E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
BDB61846206ADDDF00AFF600 /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
BDBF9B931ED74B8C001498A8 /* DNS64State.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64State.h; sourceTree = "<group>"; };
BDE238C11DF69D8300B9F696 /* dns_sd_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd_internal.h; path = ../mDNSShared/dns_sd_internal.h; sourceTree = "<group>"; };
- BDE5BCC9226D7181009C723C /* DNSCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSCommon.h; path = ../mDNSCore/DNSCommon.h; sourceTree = "<group>"; };
- BDE5BCCB226D7197009C723C /* uDNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uDNS.h; path = ../mDNSCore/uDNS.h; sourceTree = "<group>"; };
- BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
+ BDF2D02B2169B77B00D0DBF5 /* SymptomReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymptomReporter.h; sourceTree = "<group>"; };
+ BDF2D02D216A25E800D0DBF5 /* ApplePlatformFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePlatformFeatures.h; sourceTree = "<group>"; };
D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; sourceTree = BUILT_PRODUCTS_DIR; };
D284BEB00ADD80920027CCDF /* dns-sd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "dns-sd"; sourceTree = BUILT_PRODUCTS_DIR; };
D284BEBE0ADD809A0027CCDF /* libjdns_sd.jnilib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjdns_sd.jnilib; sourceTree = BUILT_PRODUCTS_DIR; };
D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; };
D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
+ D408BAAF221243DA00139EDA /* libarchive.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.2.tbd; path = usr/lib/libarchive.2.tbd; sourceTree = SDKROOT; };
+ D421B3DD22178BE700D35C20 /* system_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = system_utilities.h; sourceTree = "<group>"; };
+ D421B3DE22178BE700D35C20 /* system_utilities.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = system_utilities.c; sourceTree = "<group>"; };
+ D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = bats_test_state_dump.sh; sourceTree = "<group>"; };
+ D448F7AB222DCB5B0069E1D2 /* libarchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/lib/libarchive.tbd; sourceTree = DEVELOPER_DIR; };
+ D448F7AD222DCC0A0069E1D2 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ D448F7B0222E035A0069E1D2 /* uds_daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon_ut.c; path = ../unittests/uds_daemon_ut.c; sourceTree = "<group>"; };
+ D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelperFunctionTest.m; sourceTree = "<group>"; };
+ D461F9482203A6B400A88910 /* xpc_services.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_services.h; sourceTree = "<group>"; };
+ D461F9492203A6B400A88910 /* xpc_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xpc_services.c; sourceTree = "<group>"; };
+ D461F94D2203A8AA00A88910 /* xpc_service_dns_proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_service_dns_proxy.h; sourceTree = "<group>"; };
+ D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xpc_service_dns_proxy.c; sourceTree = "<group>"; };
+ D470807222123E44006BAB32 /* libarchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.tbd; path = usr/lib/libarchive.tbd; sourceTree = SDKROOT; };
+ D49ECA17220BBAC400655887 /* dns-sd-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dns-sd-entitlements.plist"; sourceTree = "<group>"; };
+ D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = posix_utilities.c; path = ../mDNSPosix/posix_utilities.c; sourceTree = "<group>"; };
+ D4BFF8DA22B1C52100A0BA86 /* posix_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = posix_utilities.h; path = ../mDNSPosix/posix_utilities.h; sourceTree = "<group>"; };
+ D4C2AED32203E4F900B35685 /* xpc_service_log_utility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_service_log_utility.h; sourceTree = "<group>"; };
+ D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xpc_service_log_utility.c; sourceTree = "<group>"; };
+ D4C2AED822050E8800B35685 /* xpc_client_dns_proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_client_dns_proxy.h; sourceTree = "<group>"; };
+ D4C2AEDA22050F4E00B35685 /* xpc_client_log_utility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_client_log_utility.h; sourceTree = "<group>"; };
+ D4CFA7CC21E7B95E00F5AD0E /* liblog_mdnsresponder.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = liblog_mdnsresponder.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ D4CFA7D021E7BA0E00F5AD0E /* liblog_mdnsresponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = liblog_mdnsresponder.m; sourceTree = "<group>"; };
+ D4CFA7D221E7BA8F00F5AD0E /* mDNSFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSFeatures.h; path = ../mDNSShared/mDNSFeatures.h; sourceTree = "<group>"; };
DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; };
DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; };
DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; };
FF260A2A07B4464B00CE10E5 /* failure.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = failure.tiff; path = PreferencePane/Artwork/failure.tiff; sourceTree = SOURCE_ROOT; };
FF260A3207B4466900CE10E5 /* BonjourPref.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BonjourPref.icns; path = PreferencePane/BonjourPref.icns; sourceTree = SOURCE_ROOT; };
FF260A3307B4466900CE10E5 /* BonjourPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = BonjourPref.tiff; path = PreferencePane/BonjourPref.tiff; sourceTree = SOURCE_ROOT; };
- FF260A4C07B4477F00CE10E5 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = PreferencePane/English.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; };
FF2C5FB00A48B8680066DA11 /* DNSSDRecordRegistrar.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSSDRecordRegistrar.java; path = ../mDNSShared/Java/DNSSDRecordRegistrar.java; sourceTree = SOURCE_ROOT; };
FF2C5FB20A48B86E0066DA11 /* RegisterRecordListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = RegisterRecordListener.java; path = ../mDNSShared/Java/RegisterRecordListener.java; sourceTree = SOURCE_ROOT; };
FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; };
);
runOnlyForDeploymentPostprocessing = 0;
};
- 37DDE92A1BA383610092AC61 /* Frameworks */ = {
+ 84C5B3321665529800C324A8 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 37538E1B1D7A442300226BE4 /* Foundation.framework in Frameworks */,
- 21B830A31D8A63AE00AE2001 /* SystemConfiguration.framework in Frameworks */,
- 21B830A61D8A63E400AE2001 /* CoreFoundation.framework in Frameworks */,
- 21B830A21D8A63A300AE2001 /* libxml2.dylib in Frameworks */,
- 37538E141D7A43B600226BE4 /* libicucore.dylib in Frameworks */,
- 789036931F7AC2050077A962 /* libnetwork.tbd in Frameworks */,
- 21B830A41D8A63BB00AE2001 /* Security.framework in Frameworks */,
- 21B830A51D8A63CB00AE2001 /* IOKit.framework in Frameworks */,
+ BD42EE2021DB41970053A651 /* libobjc.tbd in Frameworks */,
+ BD93516E21E369B90078582E /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 72FB545C166D5FB00090B2D9 /* Frameworks */ = {
+ B7325FEA1DA47EBA00663834 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 84C5B3321665529800C324A8 /* Frameworks */ = {
+ B7473E5E1EC3954400D31B9D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
- B7325FEA1DA47EBA00663834 /* Frameworks */ = {
+ B7473E771EC395C300D31B9D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ B7A861A1212B3FF400E81CC3 /* Cocoa.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B74F16E82114E49C00BEBE84 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D448F7AC222DCB5C0069E1D2 /* libarchive.tbd in Frameworks */,
+ B7A861A3212B409200E81CC3 /* IOKit.framework in Frameworks */,
+ B7A861A8212B411200E81CC3 /* libicucore.tbd in Frameworks */,
+ B7A861A7212B410D00E81CC3 /* libxml2.tbd in Frameworks */,
+ B7A861A2212B408D00E81CC3 /* Security.framework in Frameworks */,
+ B7EEF7C4212603B20093828F /* SystemConfiguration.framework in Frameworks */,
+ B7A861A9212B411600E81CC3 /* Network.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
B76783A91E82D65900DA271E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ BDA82B8A22BF8A7000A31CBE /* libdns_services.tbd in Frameworks */,
BD41F9C4209B60AC0077F8B6 /* libpcap.tbd in Frameworks */,
BDAF4BC020B52D3D0062219E /* CFNetwork.framework in Frameworks */,
BD893CE7206C0EAF0055F9E7 /* CoreFoundation.framework in Frameworks */,
BD9BA7581EAF929C00658CCF /* CoreUtils.framework in Frameworks */,
+ BD2A15BC225ED38600BEA50A /* Network.framework in Frameworks */,
BD893CE5206C0D980055F9E7 /* SystemConfiguration.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ D470807322123E44006BAB32 /* libarchive.tbd in Frameworks */,
D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */,
D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+ D4CFA7CA21E7B95E00F5AD0E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
isa = PBXGroup;
children = (
+ B79FA152211CF0AF00B7861E /* mDNSCore */,
+ BD11266C21DB1AB3006115E6 /* mDNSMacOSX */,
+ D4BFF8D822B1C29E00A0BA86 /* mDNSPosix */,
08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
6575FC1F022EB78C00000109 /* Command-Line Clients */,
213FB20912028902002B3A08 /* Bonjour Events Plugin */,
B7D6CA511D107573005E24CF /* DomainBrowser */,
B74EC11A1D47FC7800A1D155 /* SettingsBundle */,
FFFB0DA407B43BED00B88D48 /* PreferencePane */,
+ B7473E621EC3954400D31B9D /* Bonjour Safari Menu */,
+ B7473E7E1EC395C300D31B9D /* Bonjour Safari Extension */,
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
0C1596AD1D773FE300E09998 /* mDNSNetMonitor */,
0C635A771E9418A60026C796 /* BonjourTop */,
+ B74F16EC2114E49D00BEBE84 /* Tests */,
19C28FBDFE9D53C911CA2CBB /* Products */,
- 37DDE9241BA382280092AC61 /* Unit Tests */,
BD9BA7561EAF929C00658CCF /* Frameworks */,
BDB61842206ADB7700AFF600 /* LoggingProfiles */,
BD28AE8D207B88F600F0B257 /* Scripts */,
- BDF8BB8E2208E26E00419B62 /* BATS */,
);
name = mDNSResponder;
sourceTree = "<group>";
08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
isa = PBXGroup;
children = (
+ 897729B62202A5480018FAEB /* dnssd_clientshim.c */,
+ 897729AF2202A5370018FAEB /* dso-transport.c */,
+ 897729B02202A5370018FAEB /* dso-transport.h */,
+ 897729AE2202A5370018FAEB /* dso.c */,
+ 897729B12202A5370018FAEB /* dso.h */,
+ D461F9472203A59200A88910 /* xpc_services */,
+ D4CFA7D221E7BA8F00F5AD0E /* mDNSFeatures.h */,
+ BD1628CE2168B02700020528 /* ClientRequests.c */,
+ BD1628CD2168B02600020528 /* ClientRequests.h */,
220ABBF11D78F102008423A7 /* D2D.h */,
22C7633D1D777B8C0077AFCA /* D2D.c */,
22448EA51C90A82D004F25CC /* coreBLE.h */,
222A3C571C1B743B003A6FFD /* DNSServiceDiscovery.h */,
222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */,
222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */,
- 21DD8FBD161E9A250033C8F8 /* anonymous.c */,
- 21DD8FBE161E9A250033C8F8 /* anonymous.h */,
21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */,
21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */,
21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */,
BDA9A7871B3A923600523835 /* dns_sd_private.h */,
84C5B339166553AF00C324A8 /* dns_services.c */,
84F4C08F188F04CF00D1E1DE /* dns_services.h */,
- 848DA5D516547F7200D2E8B4 /* dns_xpc.h */,
7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
- BDE5BCC9226D7181009C723C /* DNSCommon.h */,
7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
2E0405F40C3195F700F13B59 /* helper.c */,
2E96A5250C39BE480087C4D2 /* helper.h */,
2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
- 4A8202510C56C36500DDFD48 /* ipsec_strerror.h */,
7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */,
- 4A8202520C56C36500DDFD48 /* libpfkey.h */,
6575FBE9022EAF5A00000109 /* mDNS.c */,
DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */,
654BE65002B63B93000001D1 /* mDNSDebug.h */,
6575FBEB022EAF7200000109 /* mDNSMacOSX.c */,
000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */,
FF485D5105632E0000130380 /* mDNSResponder.8 */,
- 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */,
FF85880B0BD599F40080D89F /* mDNSResponder.sb */,
- 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */,
4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
BDA3F0871C48DB6D0054FB4B /* Metrics.h */,
BDA3F0881C48DB6D0054FB4B /* Metrics.m */,
2127A47615C3C7B900A857FC /* nsec3.h */,
4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */,
4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */,
- 4A8202530C56C36600DDFD48 /* pfkey.c */,
FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
BD03E88C1AD31278005E8A81 /* SymptomReporter.c */,
+ BDF2D02B2169B77B00D0DBF5 /* SymptomReporter.h */,
7F18A9F70587CEF6001880B3 /* uDNS.c */,
- BDE5BCCB226D7197009C723C /* uDNS.h */,
216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */,
F525E72804AA167501F1CF4D /* uds_daemon.c */,
4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */,
- 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */,
- 848DA5C6165477E000D2E8B4 /* xpc_services.c */,
- 848DA5C9165477EB00D2E8B4 /* xpc_services.h */,
);
name = "mDNS Server Sources";
sourceTree = "<group>";
8415A6561897109000BDBA26 /* libdns_services.dylib */,
37538E131D7A43B600226BE4 /* libicucore.dylib */,
2E8165F60C59835F00485EB2 /* libipsec.dylib */,
+ B7A861A6212B40BC00E81CC3 /* libicucore.tbd */,
+ B7A861A4212B40BC00E81CC3 /* libxml2.tbd */,
219D5541149ED645004464AE /* libxml2.dylib */,
+ B7A861A5212B40BC00E81CC3 /* Network.framework */,
B74A96251DD4EDE60084A8C5 /* Preferences.framework */,
FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
B7D566D41E81E14E00E43008 /* ViewBridge.framework */,
7F869685066EE02400D2A2DC /* Security.framework */,
65713D46025A293200000109 /* SystemConfiguration.framework */,
- 21F432971134AA6800581B69 /* WebFilterDNS.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
213FB21812028A7A002B3A08 /* BonjourEvents.plugin */,
D284BEB00ADD80920027CCDF /* dns-sd */,
- 72FB545F166D5FB00090B2D9 /* dnsctl */,
D284BED90ADD80A20027CCDF /* dnsextd */,
2141DD1D123FFCDB0086D23E /* libdns_sd.a */,
2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */,
FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */,
D284BE730ADD80740027CCDF /* mDNSResponder */,
2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
- 37DDE92D1BA383610092AC61 /* unittests */,
0C1596AC1D773FE300E09998 /* mDNSNetMonitor */,
B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */,
B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */,
B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */,
0C635A761E9418A60026C796 /* bonjourtop */,
BD9BA7531EAF90E400658CCF /* dnssdutil */,
+ B7473E611EC3954400D31B9D /* Bonjour Safari Menu.app */,
+ B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */,
+ B74F16EB2114E49C00BEBE84 /* Tests.xctest */,
+ D4CFA7CC21E7B95E00F5AD0E /* liblog_mdnsresponder.dylib */,
);
name = Products;
sourceTree = "<group>";
name = "Bonjour Events Plugin";
sourceTree = "<group>";
};
- 37DDE9241BA382280092AC61 /* Unit Tests */ = {
+ 37DDE9241BA382280092AC61 /* Unit Test Utilities */ = {
isa = PBXGroup;
children = (
- 0C84A2911E786AFF00E8B4C7 /* daemon_ut.c */,
- 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */,
- 0C10EC271DDB956000D7A0E3 /* LocalOnlyTimeoutTests.h */,
- 0C7C00491DD553490078BA89 /* unittest_common.c */,
+ B7A8619A212B34CF00E81CC3 /* unittest.h */,
+ D448F7B0222E035A0069E1D2 /* uds_daemon_ut.c */,
+ B7A8619E212B368700E81CC3 /* daemon_ut.c */,
+ B7A8619F212B36EC00E81CC3 /* mdns_macosx_ut.c */,
+ B7A861A0212B370700E81CC3 /* mdns_ut.c */,
0C7C004A1DD553490078BA89 /* unittest_common.h */,
- 0C7C004B1DD553490078BA89 /* mdns_macosx_ut.c */,
- 0C7C004C1DD553490078BA89 /* mdns_ut.c */,
- 0C7C004D1DD553490078BA89 /* uds_daemon_ut.c */,
- 0C7C004E1DD553490078BA89 /* CNameRecordTests.h */,
- 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */,
- 0C5674B11DA2BF6300AF3367 /* mDNSCoreReceiveTest.h */,
- 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */,
- 37AF802A1BF699AF00D657F6 /* DomainNameTest.c */,
- 37AF802B1BF699AF00D657F6 /* DomainNameTest.h */,
- 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */,
- 371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */,
- 373202111BAB63E8007DE806 /* DNSMessageTest.h */,
- 3732020F1BAB4349007DE806 /* DNSMessageTest.c */,
- 37DDE9351BA386E70092AC61 /* main.c */,
- 37DDE9271BA3825C0092AC61 /* unittest.c */,
- 37DDE9281BA382670092AC61 /* unittest.h */,
- 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */,
- 371D0FBB1BF545FA00E5DB26 /* InterfaceTest.h */,
- );
- name = "Unit Tests";
+ 0C7C00491DD553490078BA89 /* unittest_common.c */,
+ );
+ name = "Unit Test Utilities";
+ path = ..;
sourceTree = "<group>";
};
6575FC1F022EB78C00000109 /* Command-Line Clients */ = {
isa = PBXGroup;
children = (
+ BD97754A221D643500F68FFC /* dnssdutil */,
+ D49ECA15220BBA2D00655887 /* command_line_client_entitlements */,
FF1C919D07021D77001048AB /* dns-sd.1 */,
FF1C919F07021E3F001048AB /* dns-sd.c */,
- 72FB545A166D5F960090B2D9 /* dnsctl.c */,
FF5852100DD27BD300862BDF /* ClientCommon.c */,
- BD9BA7541EAF91E700658CCF /* dnssdutil.c */,
);
name = "Command-Line Clients";
sourceTree = "<group>";
};
+ B7473E621EC3954400D31B9D /* Bonjour Safari Menu */ = {
+ isa = PBXGroup;
+ children = (
+ B7473E651EC3954400D31B9D /* AppDelegate.h */,
+ B7473E661EC3954400D31B9D /* AppDelegate.m */,
+ B7473E6A1EC3954400D31B9D /* ViewController.h */,
+ B7473E6B1EC3954400D31B9D /* ViewController.m */,
+ B7473E6D1EC3954400D31B9D /* Assets.xcassets */,
+ B7473E6F1EC3954400D31B9D /* Main.storyboard */,
+ B7473E721EC3954400D31B9D /* Info.plist */,
+ B7473E631EC3954400D31B9D /* Supporting Files */,
+ );
+ path = "Bonjour Safari Menu";
+ sourceTree = "<group>";
+ };
+ B7473E631EC3954400D31B9D /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ B7473E641EC3954400D31B9D /* BonjourSafariMenu.entitlements */,
+ B7473E681EC3954400D31B9D /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ B7473E7E1EC395C300D31B9D /* Bonjour Safari Extension */ = {
+ isa = PBXGroup;
+ children = (
+ B76373741ECA25DE00B9404A /* CNServiceBrowserView.h */,
+ B76373751ECA25DE00B9404A /* CNServiceBrowserView.m */,
+ B7473E811EC395C300D31B9D /* SafariExtensionHandler.h */,
+ B7473E821EC395C300D31B9D /* SafariExtensionHandler.m */,
+ B7473E841EC395C300D31B9D /* SafariExtensionViewController.h */,
+ B7473E851EC395C300D31B9D /* SafariExtensionViewController.m */,
+ B7473E871EC395C300D31B9D /* SafariExtensionViewController.xib */,
+ B7473E8A1EC395C300D31B9D /* Info.plist */,
+ B7473E7F1EC395C300D31B9D /* Supporting Files */,
+ );
+ path = "Bonjour Safari Extension";
+ sourceTree = "<group>";
+ };
+ B7473E7F1EC395C300D31B9D /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ B7473E8B1EC395C300D31B9D /* script.js */,
+ B7CEF6121F635404008B08D3 /* ToolbarItemIcon.png */,
+ B72D38B31ECB96ED00B10E39 /* Localizable.strings */,
+ B7473E801EC395C300D31B9D /* BonjourSafariExtension.entitlements */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
B74EC11A1D47FC7800A1D155 /* SettingsBundle */ = {
isa = PBXGroup;
children = (
path = SettingsBundle;
sourceTree = "<group>";
};
+ B74F16EC2114E49D00BEBE84 /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ B74F16EF2114E49D00BEBE84 /* Info.plist */,
+ BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */,
+ B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */,
+ B7A861962127845700E81CC3 /* CNameRecordTest.m */,
+ B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */,
+ B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */,
+ B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */,
+ D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */,
+ D448F7A6222DA98E0069E1D2 /* BATS Scripts */,
+ 37DDE9241BA382280092AC61 /* Unit Test Utilities */,
+ );
+ path = Tests;
+ sourceTree = "<group>";
+ };
B76783BA1E82D8F500DA271E /* BonjourPrefTool */ = {
isa = PBXGroup;
children = (
path = BonjourPrefTool;
sourceTree = "<group>";
};
+ B79FA152211CF0AF00B7861E /* mDNSCore */ = {
+ isa = PBXGroup;
+ children = (
+ B79FA153211CF0AF00B7861E /* dnsproxy.h */,
+ B79FA154211CF0AF00B7861E /* uDNS.h */,
+ B79FA155211CF0AF00B7861E /* nsec.h */,
+ B79FA156211CF0AF00B7861E /* DNSCommon.c */,
+ B79FA157211CF0AF00B7861E /* mDNSDebug.h */,
+ B79FA158211CF0AF00B7861E /* dnssec.c */,
+ B79FA159211CF0AF00B7861E /* CryptoAlg.h */,
+ B79FA15A211CF0AF00B7861E /* nsec3.h */,
+ B79FA15B211CF0AF00B7861E /* Implementer Notes.txt */,
+ B79FA15C211CF0AF00B7861E /* nsec.c */,
+ B79FA15D211CF0AF00B7861E /* uDNS.c */,
+ B79FA15E211CF0AF00B7861E /* dnsproxy.c */,
+ B79FA15F211CF0AF00B7861E /* dnssec.h */,
+ B79FA160211CF0AF00B7861E /* mDNS.c */,
+ B79FA162211CF0AF00B7861E /* DNSCommon.h */,
+ B79FA163211CF0AF00B7861E /* CryptoAlg.c */,
+ B79FA164211CF0AF00B7861E /* mDNSEmbeddedAPI.h */,
+ B79FA165211CF0AF00B7861E /* nsec3.c */,
+ B79FA166211CF0AF00B7861E /* DNSDigest.c */,
+ );
+ name = mDNSCore;
+ path = ../mDNSCore;
+ sourceTree = "<group>";
+ };
B7A214061D1B29D6005F7DD9 /* iOS */ = {
isa = PBXGroup;
children = (
path = macOS;
sourceTree = "<group>";
};
+ BD11266C21DB1AB3006115E6 /* mDNSMacOSX */ = {
+ isa = PBXGroup;
+ children = (
+ D421B3DC22178B7800D35C20 /* utilities */,
+ BDF2D02D216A25E800D0DBF5 /* ApplePlatformFeatures.h */,
+ BD11267721DB2A9A006115E6 /* dnssd.c */,
+ BD11267B21DB2C7C006115E6 /* dnssd_object.h */,
+ BD11267621DB2A9A006115E6 /* dnssd_object.m */,
+ BD11267521DB2A9A006115E6 /* dnssd_private.h */,
+ BD11266F21DB1AFE006115E6 /* dnssd_server.c */,
+ BD11267021DB1AFE006115E6 /* dnssd_server.h */,
+ BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */,
+ BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */,
+ BD2A15B7225ED2E500BEA50A /* mdns.c */,
+ BD2A15B6225ED2E500BEA50A /* mdns_object.h */,
+ BD2A15B5225ED2E500BEA50A /* mdns_object.m */,
+ BD2A15B8225ED2E500BEA50A /* mdns_private.h */,
+ );
+ name = mDNSMacOSX;
+ sourceTree = "<group>";
+ usesTabs = 1;
+ };
BD28AE8D207B88F600F0B257 /* Scripts */ = {
isa = PBXGroup;
children = (
path = Scripts;
sourceTree = "<group>";
};
+ BD97754A221D643500F68FFC /* dnssdutil */ = {
+ isa = PBXGroup;
+ children = (
+ BD97754D221D64BF00F68FFC /* DNSMessage.c */,
+ BD97754E221D64BF00F68FFC /* DNSMessage.h */,
+ BD97754B221D643500F68FFC /* dnssdutil.c */,
+ );
+ name = dnssdutil;
+ path = ../Clients/dnssdutil;
+ sourceTree = "<group>";
+ };
BD9BA7561EAF929C00658CCF /* Frameworks */ = {
isa = PBXGroup;
children = (
+ BDA82B8922BF8A7000A31CBE /* libdns_services.tbd */,
+ D448F7AD222DCC0A0069E1D2 /* CoreFoundation.framework */,
+ D448F7AB222DCB5B0069E1D2 /* libarchive.tbd */,
+ D408BAAF221243DA00139EDA /* libarchive.2.tbd */,
+ D470807222123E44006BAB32 /* libarchive.tbd */,
+ BD42EE1F21DB41970053A651 /* libobjc.tbd */,
BDAF4BBF20B52D3D0062219E /* CFNetwork.framework */,
BD41F9C3209B60AC0077F8B6 /* libpcap.tbd */,
BD893CE6206C0EAF0055F9E7 /* CoreFoundation.framework */,
BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */,
789036911F7AC1F90077A962 /* libnetwork.tbd */,
BD9BA7571EAF929C00658CCF /* CoreUtils.framework */,
+ B735A2EE21B8293900025BB0 /* Foundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
BDB61842206ADB7700AFF600 /* LoggingProfiles */ = {
isa = PBXGroup;
children = (
+ D4CFA7D021E7BA0E00F5AD0E /* liblog_mdnsresponder.m */,
BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */,
BDB61844206ADB7700AFF600 /* AppleInternal */,
);
path = AppleInternal;
sourceTree = "<group>";
};
- BDF8BB8E2208E26E00419B62 /* BATS */ = {
+ D421B3DC22178B7800D35C20 /* utilities */ = {
+ isa = PBXGroup;
+ children = (
+ D421B3DD22178BE700D35C20 /* system_utilities.h */,
+ D421B3DE22178BE700D35C20 /* system_utilities.c */,
+ );
+ path = utilities;
+ sourceTree = "<group>";
+ };
+ D448F7A6222DA98E0069E1D2 /* BATS Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */,
+ D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */,
+ );
+ path = "BATS Scripts";
+ sourceTree = "<group>";
+ };
+ D461F9472203A59200A88910 /* xpc_services */ = {
+ isa = PBXGroup;
+ children = (
+ 848DA5D516547F7200D2E8B4 /* xpc_clients.h */,
+ D461F9482203A6B400A88910 /* xpc_services.h */,
+ D461F9492203A6B400A88910 /* xpc_services.c */,
+ D461F94D2203A8AA00A88910 /* xpc_service_dns_proxy.h */,
+ D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */,
+ D4C2AED822050E8800B35685 /* xpc_client_dns_proxy.h */,
+ D4C2AED32203E4F900B35685 /* xpc_service_log_utility.h */,
+ D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */,
+ D4C2AEDA22050F4E00B35685 /* xpc_client_log_utility.h */,
+ );
+ path = xpc_services;
+ sourceTree = "<group>";
+ };
+ D49ECA15220BBA2D00655887 /* command_line_client_entitlements */ = {
+ isa = PBXGroup;
+ children = (
+ D49ECA17220BBAC400655887 /* dns-sd-entitlements.plist */,
+ );
+ path = command_line_client_entitlements;
+ sourceTree = "<group>";
+ };
+ D4BFF8D822B1C29E00A0BA86 /* mDNSPosix */ = {
isa = PBXGroup;
children = (
- BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */,
+ D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */,
+ D4BFF8DA22B1C52100A0BA86 /* posix_utilities.h */,
);
- path = BATS;
+ name = mDNSPosix;
sourceTree = "<group>";
};
DB2CC4420662DCE500335AB3 /* Java Support */ = {
FF260A2A07B4464B00CE10E5 /* failure.tiff */,
FF260A3207B4466900CE10E5 /* BonjourPref.icns */,
FF260A3307B4466900CE10E5 /* BonjourPref.tiff */,
- FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */,
+ B78A9C2E223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib */,
FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */,
);
name = Resources;
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- BDA9A7891B3A92A500523835 /* dns_sd_private.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */,
2EDC5E730C39EA640092701B /* helper-server.h in Headers */,
2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
- 2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
- 2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 37538DFB1D7A421500226BE4 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 37538E0D1D7A437300226BE4 /* DNSSECSupport.h in Headers */,
- 37538E0C1D7A435200226BE4 /* dnssec.h in Headers */,
- 37538E0B1D7A432200226BE4 /* Metrics.h in Headers */,
- 37538E0A1D7A430600226BE4 /* anonymous.h in Headers */,
- 37538E091D7A42FC00226BE4 /* xpc_services.h in Headers */,
- 37538E081D7A42F000226BE4 /* dns_xpc.h in Headers */,
- 37538E071D7A42E200226BE4 /* coreBLE.h in Headers */,
- 37538E061D7A42DA00226BE4 /* dnsproxy.h in Headers */,
- 37538E051D7A42D000226BE4 /* DNSServiceDiscoveryDefines.h in Headers */,
- 37538E041D7A42BE00226BE4 /* BLE.h in Headers */,
- 37538E021D7A42B000226BE4 /* nsec.h in Headers */,
- 37538E031D7A42B000226BE4 /* nsec3.h in Headers */,
- 37538E001D7A429900226BE4 /* CryptoAlg.h in Headers */,
- 37538E011D7A429900226BE4 /* CryptoSupport.h in Headers */,
- 37538DFF1D7A428500226BE4 /* helpermsg-types.h in Headers */,
- 37538DFE1D7A427B00226BE4 /* helper-server.h in Headers */,
- 37538DFD1D7A425700226BE4 /* helper.h in Headers */,
- 37538DFC1D7A424500226BE4 /* dnssd_ipc.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
84C5B3331665529800C324A8 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ D4C2AEDD22052A3400B35685 /* xpc_clients.h in Headers */,
84F4C090188F050200D1E1DE /* dns_services.h in Headers */,
+ BD11267821DB2A9B006115E6 /* dnssd_private.h in Headers */,
+ BD11267C21DB2C7C006115E6 /* dnssd_object.h in Headers */,
+ BD11267E21DB3019006115E6 /* dnssd_xpc.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ BD977550221D64BF00F68FFC /* DNSMessage.h in Headers */,
+ D4A9F60521FA797F0079D0C6 /* dns_sd_private.h in Headers */,
+ BD2A15B9225ED30C00BEA50A /* mdns_private.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
files = (
D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */,
+ D4C2AED922050E8800B35685 /* xpc_client_dns_proxy.h in Headers */,
+ D4C2AEDB22050F4E00B35685 /* xpc_client_log_utility.h in Headers */,
2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
+ BDF2D02E216A25E800D0DBF5 /* ApplePlatformFeatures.h in Headers */,
+ BDF2D02C2169B77C00D0DBF5 /* SymptomReporter.h in Headers */,
+ BD1628CF2168B02700020528 /* ClientRequests.h in Headers */,
+ BD11267121DB1B25006115E6 /* dnssd_server.h in Headers */,
+ D421B3DF22178BE700D35C20 /* system_utilities.h in Headers */,
2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */,
21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */,
- BDE5BCCA226D7181009C723C /* DNSCommon.h in Headers */,
2124FA2C1471E98C0021D7BB /* nsec.h in Headers */,
- BDE5BCCC226D7198009C723C /* uDNS.h in Headers */,
+ D4CFA7D421E7BA9700F5AD0E /* mDNSFeatures.h in Headers */,
+ D401238D22728506006C9BBE /* mdns_private.h in Headers */,
+ D4BFF8DC22B1C52100A0BA86 /* posix_utilities.h in Headers */,
+ 897729B42202A5370018FAEB /* dso-transport.h in Headers */,
2124FA301471E9B50021D7BB /* dnssec.h in Headers */,
+ D461F94F2203A8AA00A88910 /* xpc_service_dns_proxy.h in Headers */,
+ B7A8619B212B34CF00E81CC3 /* unittest.h in Headers */,
BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */,
+ BD11267221DB1B29006115E6 /* dnssd_xpc.h in Headers */,
218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */,
2127A47915C3C7B900A857FC /* nsec3.h in Headers */,
222A3C5B1C1B75F2003A6FFD /* DNSServiceDiscoveryDefines.h in Headers */,
- 21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */,
+ 897729B52202A5370018FAEB /* dso.h in Headers */,
21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */,
- 848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */,
BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */,
22448EA71C90A837004F25CC /* coreBLE.h in Headers */,
220ABBF21D78F10F008423A7 /* D2D.h in Headers */,
22448EA41C90A7CB004F25CC /* BLE.h in Headers */,
- 848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */,
+ D461F94A2203A6B400A88910 /* xpc_services.h in Headers */,
+ 848DA5D616547F7200D2E8B4 /* xpc_clients.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
);
runOnlyForDeploymentPostprocessing = 0;
};
+ D4CFA7C821E7B95E00F5AD0E /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D4A1591822E27F61002F6278 /* DNSMessage.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
FFA572310AF18F1C0055A0F1 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- BDB04221203FEF4C00419961 /* dns_sd.h in Headers */,
- BDB04223203FF18000419961 /* dns_sd_private.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
- BDB04222203FEF4D00419961 /* dns_sd.h in Headers */,
- BDB04224203FF18000419961 /* dns_sd_private.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */;
productType = "com.apple.product-type.tool";
};
- 37DDE92C1BA383610092AC61 /* unittests */ = {
+ 84C5B3341665529800C324A8 /* dns_services */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */;
+ buildConfigurationList = 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */;
buildPhases = (
- 37DDE9291BA383610092AC61 /* Sources */,
- 37DDE92A1BA383610092AC61 /* Frameworks */,
- 37DDE9341BA384000092AC61 /* ShellScript */,
- 37538DFB1D7A421500226BE4 /* Headers */,
+ 84C5B3311665529800C324A8 /* Sources */,
+ 84C5B3321665529800C324A8 /* Frameworks */,
+ 84C5B3331665529800C324A8 /* Headers */,
);
buildRules = (
);
dependencies = (
);
- name = unittests;
- productName = unittests;
- productReference = 37DDE92D1BA383610092AC61 /* unittests */;
- productType = "com.apple.product-type.tool";
+ name = dns_services;
+ productName = dns_services;
+ productReference = 84C5B3351665529800C324A8 /* libdns_services.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
};
- 72FB545E166D5FB00090B2D9 /* dnsctl */ = {
+ B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */;
+ buildConfigurationList = B7325FF31DA47EBA00663834 /* Build configuration list for PBXNativeTarget "DomainBrowser-iOS" */;
buildPhases = (
- 72FB545B166D5FB00090B2D9 /* Sources */,
- 72FB545C166D5FB00090B2D9 /* Frameworks */,
- 72FB545D166D5FB00090B2D9 /* CopyFiles */,
- );
+ B7325FE91DA47EBA00663834 /* Sources */,
+ B7325FEA1DA47EBA00663834 /* Frameworks */,
+ B7325FEB1DA47EBA00663834 /* Headers */,
+ B7325FEC1DA47EBA00663834 /* Resources */,
+ );
buildRules = (
);
dependencies = (
- 0C2AAB321B6929F300113637 /* PBXTargetDependency */,
);
- name = dnsctl;
- productName = dnsctl;
- productReference = 72FB545F166D5FB00090B2D9 /* dnsctl */;
- productType = "com.apple.product-type.tool";
+ name = "DomainBrowser-iOS";
+ productName = BonjourBrowser;
+ productReference = B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */;
+ productType = "com.apple.product-type.framework";
};
- 84C5B3341665529800C324A8 /* dns_services */ = {
+ B7473E601EC3954400D31B9D /* Bonjour Safari Menu */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */;
+ buildConfigurationList = B7473E751EC3954400D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Menu" */;
buildPhases = (
- 84C5B3311665529800C324A8 /* Sources */,
- 84C5B3321665529800C324A8 /* Frameworks */,
- 84C5B3331665529800C324A8 /* Headers */,
+ B7473E5D1EC3954400D31B9D /* Sources */,
+ B7473E5E1EC3954400D31B9D /* Frameworks */,
+ B7473E5F1EC3954400D31B9D /* Resources */,
+ B7473E951EC395C300D31B9D /* Embed App Extensions */,
);
buildRules = (
);
dependencies = (
+ B7473E901EC395C300D31B9D /* PBXTargetDependency */,
);
- name = dns_services;
- productName = dns_services;
- productReference = 84C5B3351665529800C324A8 /* libdns_services.dylib */;
- productType = "com.apple.product-type.library.dynamic";
+ name = "Bonjour Safari Menu";
+ productName = "Bonjour Browser";
+ productReference = B7473E611EC3954400D31B9D /* Bonjour Safari Menu.app */;
+ productType = "com.apple.product-type.application";
};
- B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */ = {
+ B7473E791EC395C300D31B9D /* Bonjour Safari Extension */ = {
isa = PBXNativeTarget;
- buildConfigurationList = B7325FF31DA47EBA00663834 /* Build configuration list for PBXNativeTarget "DomainBrowser-iOS" */;
+ buildConfigurationList = B7473E921EC395C300D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Extension" */;
buildPhases = (
- B7325FE91DA47EBA00663834 /* Sources */,
- B7325FEA1DA47EBA00663834 /* Frameworks */,
- B7325FEB1DA47EBA00663834 /* Headers */,
- B7325FEC1DA47EBA00663834 /* Resources */,
+ B7473E761EC395C300D31B9D /* Sources */,
+ B7473E771EC395C300D31B9D /* Frameworks */,
+ B7473E781EC395C300D31B9D /* Resources */,
);
buildRules = (
);
dependencies = (
);
- name = "DomainBrowser-iOS";
- productName = BonjourBrowser;
- productReference = B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */;
- productType = "com.apple.product-type.framework";
+ name = "Bonjour Safari Extension";
+ productName = "Bonjour Extension";
+ productReference = B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */;
+ productType = "com.apple.product-type.app-extension";
};
B74EC1151D47FC7700A1D155 /* BonjourSettings */ = {
isa = PBXNativeTarget;
productReference = B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */;
productType = "com.apple.product-type.bundle";
};
+ B74F16EA2114E49C00BEBE84 /* Tests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B74F16F02114E49D00BEBE84 /* Build configuration list for PBXNativeTarget "Tests" */;
+ buildPhases = (
+ B74F16E72114E49C00BEBE84 /* Sources */,
+ B74F16E82114E49C00BEBE84 /* Frameworks */,
+ B74F16E92114E49C00BEBE84 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Tests;
+ productName = Tests;
+ productReference = B74F16EB2114E49C00BEBE84 /* Tests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
B76783AB1E82D65900DA271E /* BonjourPrefsTool */ = {
isa = PBXNativeTarget;
buildConfigurationList = B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */;
D284BE550ADD80740027CCDF /* Sources */,
D284BE640ADD80740027CCDF /* Frameworks */,
D284BE6A0ADD80740027CCDF /* CopyFiles */,
- 4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */,
- 4A7B9E8114FDA25500B84CC1 /* CopyFiles */,
D284BE6C0ADD80740027CCDF /* Run Script */,
21F51DC01B35418C0070B05C /* CopyFiles */,
8418673D15AB8BFF00BB7F70 /* Copy Base Logging Profile */,
BD75E93F206ADEAD00656ED3 /* Copy AppleInternal Logging Profile */,
BD28AE8C207B888E00F0B257 /* Copy diagnose scripts */,
- BDF8BB8A2208E09D00419B62 /* Copy BATS test plist */,
+ D448F7A5222DA8E20069E1D2 /* Copy script-based unit tests */,
+ BD98A797213A41240002EC47 /* Copy BATS test plist */,
+ D4C07948220A180000E485FF /* Create Log Directory for mDNSResponder */,
);
buildRules = (
);
buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
buildPhases = (
D284BEC20ADD80A20027CCDF /* Headers */,
- 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */,
+ 4A4EE3A413CB8E82005C624B /* Pre-generate dnsextd_parser.h file for dnsextd_lexer.c */,
D284BEC40ADD80A20027CCDF /* Sources */,
D284BECE0ADD80A20027CCDF /* Frameworks */,
D284BED40ADD80A20027CCDF /* CopyFiles */,
productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */;
productType = "com.apple.product-type.bundle";
};
- FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */ = {
+ D4CFA7CB21E7B95E00F5AD0E /* liblog_mdnsresponder */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = D4CFA7CF21E7B95E00F5AD0E /* Build configuration list for PBXNativeTarget "liblog_mdnsresponder" */;
+ buildPhases = (
+ D4CFA7C821E7B95E00F5AD0E /* Headers */,
+ D4CFA7C921E7B95E00F5AD0E /* Sources */,
+ D4CFA7CA21E7B95E00F5AD0E /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = liblog_mdnsresponder;
+ productName = liblog_mdnsresponder;
+ productReference = D4CFA7CC21E7B95E00F5AD0E /* liblog_mdnsresponder.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ FFA572300AF18F1C0055A0F1 /* libsystem_dnssd_debug */ = {
isa = PBXNativeTarget;
- buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */;
+ buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_debug" */;
buildPhases = (
FFA572310AF18F1C0055A0F1 /* Headers */,
FFA572320AF18F1C0055A0F1 /* Sources */,
);
dependencies = (
);
- name = libdns_sd_debug_dynamic;
+ name = libsystem_dnssd_debug;
productName = libdns_sd.dylib;
productReference = FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
- FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */ = {
+ FFA5723C0AF18F450055A0F1 /* libsystem_dnssd_profile */ = {
isa = PBXNativeTarget;
- buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */;
+ buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_profile" */;
buildPhases = (
FFA5723D0AF18F450055A0F1 /* Headers */,
FFA5723E0AF18F450055A0F1 /* Sources */,
);
dependencies = (
);
- name = libdns_sd_profile_dynamic;
+ name = libsystem_dnssd_profile;
productName = libdns_sd.dylib;
productReference = FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
- FFB765830AEED9C700583A2C /* libdns_sd_dynamic */ = {
+ FFB765830AEED9C700583A2C /* libsystem_dnssd */ = {
isa = PBXNativeTarget;
- buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */;
+ buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libsystem_dnssd" */;
buildPhases = (
FFB765800AEED9C700583A2C /* Headers */,
FFB765810AEED9C700583A2C /* Sources */,
);
dependencies = (
);
- name = libdns_sd_dynamic;
+ name = libsystem_dnssd;
productName = libdns_sd.dylib;
productReference = FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */;
productType = "com.apple.product-type.library.dynamic";
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
+ DefaultBuildSystemTypeForWorkspace = Latest;
LastUpgradeCheck = 0700;
TargetAttributes = {
0C635A751E9418A60026C796 = {
DevelopmentTeam = 63ZFQSB63Y;
ProvisioningStyle = Automatic;
};
- 37DDE92C1BA383610092AC61 = {
- CreatedOnToolsVersion = 7.0;
+ B70F38A5217AA6CE00612D3A = {
+ ProvisioningStyle = Automatic;
};
B7325FED1DA47EBA00663834 = {
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
+ B7473E601EC3954400D31B9D = {
+ CreatedOnToolsVersion = 9.0;
+ ProvisioningStyle = Automatic;
+ };
+ B7473E791EC395C300D31B9D = {
+ CreatedOnToolsVersion = 9.0;
+ ProvisioningStyle = Automatic;
+ };
B74EC1151D47FC7700A1D155 = {
CreatedOnToolsVersion = 8.0;
DevelopmentTeam = 6DMBYZ9NJ7;
DevelopmentTeamName = "Apple Inc. - Embedded Platform";
ProvisioningStyle = Automatic;
};
+ B74F16EA2114E49C00BEBE84 = {
+ CreatedOnToolsVersion = 10.0;
+ };
B76783AB1E82D65900DA271E = {
CreatedOnToolsVersion = 8.3;
ProvisioningStyle = Automatic;
};
- B7C4B7251E71BD5000136C7A = {
- CreatedOnToolsVersion = 9.0;
- ProvisioningStyle = Automatic;
- };
B7D566B91E81D8FD00E43008 = {
CreatedOnToolsVersion = 8.3;
ProvisioningStyle = Automatic;
CreatedOnToolsVersion = 8.0;
ProvisioningStyle = Automatic;
};
+ B7DB5895215EB4DD0054CD46 = {
+ CreatedOnToolsVersion = 10.0;
+ ProvisioningStyle = Automatic;
+ };
+ B7DB589D215EB61C0054CD46 = {
+ ProvisioningStyle = Automatic;
+ };
+ D4CFA7CB21E7B95E00F5AD0E = {
+ CreatedOnToolsVersion = 11.0;
+ ProvisioningStyle = Automatic;
+ };
};
};
buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
projectDirPath = "";
projectRoot = "";
targets = (
- 00AD62BB032D7A0C0CCA2C71 /* Build More */,
- B7C4B7251E71BD5000136C7A /* Build Some iOS */,
- 03067D640C83A3700022BE1F /* Build Some */,
+ 03067D640C83A3700022BE1F /* Build Core */,
+ B718416921F8D0A600CA42AD /* Build Services */,
+ B7DB589D215EB61C0054CD46 /* Build Extras-macOS */,
+ B7DB5895215EB4DD0054CD46 /* Build Extras-iOS */,
+ B70F38A5217AA6CE00612D3A /* Build Extras */,
FFB7657B0AEED96B00583A2C /* Build All */,
D284BE500ADD80740027CCDF /* mDNSResponder */,
2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
D284BEA50ADD80920027CCDF /* dns-sd tool */,
- 72FB545E166D5FB00090B2D9 /* dnsctl */,
D284BEBF0ADD80A20027CCDF /* dnsextd */,
B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */,
B7D6CA6F1D1076F3005E24CF /* DomainBrowser-macOS */,
D284BEEA0ADD80B00027CCDF /* PreferencePane */,
B76783AB1E82D65900DA271E /* BonjourPrefsTool */,
B7D566B91E81D8FD00E43008 /* RemoteViewService */,
+ B7473E601EC3954400D31B9D /* Bonjour Safari Menu */,
+ B7473E791EC395C300D31B9D /* Bonjour Safari Extension */,
213FB21712028A7A002B3A08 /* BonjourEvents */,
2141DCF8123FFB5D0086D23E /* SystemLibraries */,
2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */,
2141DD1C123FFCDB0086D23E /* libdns_sd_static */,
2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */,
2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */,
- FFB765830AEED9C700583A2C /* libdns_sd_dynamic */,
- FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */,
- FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */,
+ FFB765830AEED9C700583A2C /* libsystem_dnssd */,
+ FFA572300AF18F1C0055A0F1 /* libsystem_dnssd_debug */,
+ FFA5723C0AF18F450055A0F1 /* libsystem_dnssd_profile */,
84C5B3341665529800C324A8 /* dns_services */,
D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
4AE471670EAFF81900A6C5AD /* dns_sd.jar */,
- 37DDE92C1BA383610092AC61 /* unittests */,
+ B74F16EA2114E49C00BEBE84 /* Tests */,
0C1596AB1D773FE300E09998 /* mDNSNetMonitor */,
0C635A751E9418A60026C796 /* BonjourTop */,
BD9BA7481EAF90E400658CCF /* dnssdutil */,
+ D4CFA7CB21E7B95E00F5AD0E /* liblog_mdnsresponder */,
);
};
/* End PBXProject section */
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B7473E5F1EC3954400D31B9D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7473E6E1EC3954400D31B9D /* Assets.xcassets in Resources */,
+ B7473E711EC3954400D31B9D /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B7473E781EC395C300D31B9D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B7CEF6131F6354AA008B08D3 /* ToolbarItemIcon.png in Resources */,
+ B72D38B41ECB96ED00B10E39 /* Localizable.strings in Resources */,
+ B7473E891EC395C300D31B9D /* SafariExtensionViewController.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
B74EC1141D47FC7700A1D155 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B74F16E92114E49C00BEBE84 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D4E219202268E09F00F06AA5 /* bats_test_state_dump.sh in Resources */,
+ 894A55D722C438AF008CDEA1 /* bats_test_proxy.sh in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
B76783AA1E82D65900DA271E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
D284BEF50ADD80B00027CCDF /* failure.tiff in Resources */,
D284BEF60ADD80B00027CCDF /* BonjourPref.icns in Resources */,
D284BEF70ADD80B00027CCDF /* BonjourPref.tiff in Resources */,
- D284BEF80ADD80B00027CCDF /* DNSServiceDiscoveryPref.nib in Resources */,
D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
+ B78A9C30223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
shellPath = "/bin/bash -e -x";
shellScript = "DSTROOT=${DSTROOT}\n\nif [[ \"${ACTION}\" == \"installhdrs\" ]] || [[ \"${ACTION}\" == \"installapi\" ]]; then\n exit 0\nfi\n\nif [[ \"${PLATFORM_NAME}\" =~ \"simulator\" ]]; then\n ln -s libsystem_dnssd.dylib ${DSTROOT}${INSTALL_PATH}/libsystem_sim_dnssd.dylib\nfi\n";
};
- 37DDE9341BA384000092AC61 /* ShellScript */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 12;
- files = (
- );
- inputPaths = (
- "$(TARGET_BUILD_DIR)/$(TARGET_NAME)",
- );
- outputPaths = (
- "$(TARGET_BUILD_DIR)/unittest_success",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "cd \"$TARGET_BUILD_DIR\"\n./\"$TARGET_NAME\"\n# touch unittest_success\nif [ ! -f unittest_success ] ; then exit -1; fi";
- };
- 4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */ = {
+ 4A4EE3A413CB8E82005C624B /* Pre-generate dnsextd_parser.h file for dnsextd_lexer.c */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
inputPaths = (
"$(SRCROOT)/../mDNSShared/dnsextd_parser.y",
);
- name = "Build yacc file into derived source files";
+ name = "Pre-generate dnsextd_parser.h file for dnsextd_lexer.c";
outputPaths = (
- "$(DERIVED_FILE_DIR)/dnsextd_parser.c",
"$(DERIVED_FILE_DIR)/dnsextd_parser.h",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}";
+ shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}\n";
};
- B7E2951A1E259AA000C42F6D /* ShellScript */ = {
+ B7E2951A1E259AA000C42F6D /* Copy Sandbox Profile */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 8;
files = (
);
inputPaths = (
+ "$(SRCROOT)/mDNSResponder.sb",
);
+ name = "Copy Sandbox Profile";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/sh;
- shellScript = "# Copy Sandbox profile\nif [[ ! \"${PLATFORM_NAME}\" =~ \"simulator\" ]] ; then\n if [ -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" -a -z \"${TVOS_DEPLOYMENT_TARGET}\" -a -z \"${WATCHOS_DEPLOYMENT_TARGET}\" ] ; then\n SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\n else\n SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\n fi\n (umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\n cp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\nfi";
+ shellScript = "# Copy Sandbox profile\n[[ \"${PLATFORM_NAME}\" =~ \"simulator\" ]] && exit 0\n\nif [[ \"${PLATFORM_NAME}\" == \"macosx\" || \"${PLATFORM_NAME}\" == \"bridgeos\" ]] ; then\n SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\nelse\n SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\nfi\n(umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\ncp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\n";
};
D284BE510ADD80740027CCDF /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
+ shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
};
D284BE6C0ADD80740027CCDF /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
name = "Run Script";
runOnlyForDeploymentPostprocessing = 1;
shellPath = /bin/bash;
- shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj";
+ shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n";
+ };
+ D4C07948220A180000E485FF /* Create Log Directory for mDNSResponder */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Create Log Directory for mDNSResponder";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = "/bin/bash -x";
+ shellScript = "#!/bin/bash -x\n\n# Created by Joey Deng on 02/05/2019\n# Copyright 2019 Apple, Inc. All rights reserved.\n\n# This script creates the mdnsresponder directory in DSTROOT\n# with appropriate ownership and permissions\n\nMDNSRESPONDER_LOG_DIR=\"/private/var/log/mDNSResponder\"\nMDNSRESPONDER_USER=\"_mdnsresponder\"\nMDNSRESPONDER_USER_UID=65\n# MDNSRESPONDER_USER_UID is only used as a fallback\n# when the build machine does not have the right user\n\n\n[ \"$DSTROOT\" != \"\" ] && [ \"$DSTROOT\" != \"/\" ] && [ -d \"$DSTROOT\" ] || exit 1\n[ \"$(/usr/bin/whoami)\" == \"root\" ] || exit 0\n\nMDNSRESPONDER_LOG_DIR_TO_CREATE=\"${DSTROOT}${MDNSRESPONDER_LOG_DIR}\"\n\n/bin/mkdir -p -m 755 \"$MDNSRESPONDER_LOG_DIR_TO_CREATE\"\n\n/usr/bin/id \"$MDNSRESPONDER_USER\" >/dev/null 2>/dev/null\nif [ \"$?\" != \"0\" ] ; then\nMDNSRESPONDER_USER=\"$MDNSRESPONDER_USER_UID\"\nfi\n\n/usr/sbin/chown \"${MDNSRESPONDER_USER}:wheel\" \"$MDNSRESPONDER_LOG_DIR_TO_CREATE\"\n\n/bin/ls -ld \"$MDNSRESPONDER_LOG_DIR_TO_CREATE\"\n\nexit 0\n";
+ showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 898E98342203619800812DC6 /* dso-transport.c in Sources */,
+ 898E98352203619800812DC6 /* dso.c in Sources */,
0C1596B61D7740B500E09998 /* NetMonitor.c in Sources */,
0C1596BB1D7740D700E09998 /* DNSDigest.c in Sources */,
0C1596B81D7740C100E09998 /* mDNSUNP.c in Sources */,
0C1596BC1D7740DC00E09998 /* DNSCommon.c in Sources */,
0C1596C01D77410A00E09998 /* GenLinkedList.c in Sources */,
0C1596BE1D7740E900E09998 /* mDNSDebug.c in Sources */,
- 0C1596B91D7740CD00E09998 /* anonymous.c in Sources */,
0C1596BF1D7740EF00E09998 /* PlatformCommon.c in Sources */,
0C1596BA1D7740D200E09998 /* CryptoAlg.c in Sources */,
0C1596B51D7740B500E09998 /* mDNSPosix.c in Sources */,
files = (
2E0405F50C3195F700F13B59 /* helper.c in Sources */,
2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
- 2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 37DDE9291BA383610092AC61 /* Sources */ = {
+ 84C5B3311665529800C324A8 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 0CB1C7FC1D9C5C1100A5939F /* D2D.c in Sources */,
- 37538E1F1D7A504F00226BE4 /* helper-stubs.c in Sources */,
- 37538E1E1D7A4F9D00226BE4 /* anonymous.c in Sources */,
- 37538E1D1D7A449D00226BE4 /* coreBLE.m in Sources */,
- 37538E1C1D7A449000226BE4 /* Metrics.m in Sources */,
- 37812CD41D7A307200F34505 /* BLE.c in Sources */,
- 37812CD71D7A307200F34505 /* CryptoAlg.c in Sources */,
- 37812CD81D7A307200F34505 /* CryptoSupport.c in Sources */,
- 37812CD91D7A307200F34505 /* daemon.c in Sources */,
- 37812CDA1D7A307200F34505 /* dns_services.c in Sources */,
- 37812CDB1D7A307200F34505 /* DNSDigest.c in Sources */,
- 37812CDE1D7A307200F34505 /* dnsproxy.c in Sources */,
- 37812CDF1D7A307200F34505 /* DNSProxySupport.c in Sources */,
- 37812CE01D7A307200F34505 /* dnssd_clientlib.c in Sources */,
- 37812CE11D7A307300F34505 /* dnssd_clientstub.c in Sources */,
- 37812CE21D7A307300F34505 /* dnssd_ipc.c in Sources */,
- 37812CE31D7A307300F34505 /* dnssec.c in Sources */,
- 37812CE41D7A307300F34505 /* DNSSECSupport.c in Sources */,
- 37812CE51D7A307300F34505 /* GenLinkedList.c in Sources */,
- 37812CE91D7A307300F34505 /* LegacyNATTraversal.c in Sources */,
- 37812CEA1D7A307300F34505 /* mDNS.c in Sources */,
- 37812CEB1D7A307300F34505 /* mDNSDebug.c in Sources */,
- 37812CEC1D7A307300F34505 /* mDNSMacOSX.c in Sources */,
- 37812CED1D7A307300F34505 /* nsec.c in Sources */,
- 37812CEE1D7A307300F34505 /* nsec3.c in Sources */,
- 37812CEF1D7A307300F34505 /* P2PPacketFilter.c in Sources */,
- 37812CF11D7A307300F34505 /* PlatformCommon.c in Sources */,
- 37812CF21D7A307300F34505 /* SymptomReporter.c in Sources */,
- 37812CF31D7A307300F34505 /* uDNS.c in Sources */,
- 37812CF41D7A307300F34505 /* uDNSPathEvalulation.c in Sources */,
- 37812CF51D7A307300F34505 /* uds_daemon.c in Sources */,
- 37812CF61D7A307300F34505 /* dnsctl_server.c in Sources */,
- 37812CF71D7A307300F34505 /* xpc_services.c in Sources */,
- 371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */,
- 37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */,
- 37DDE9331BA383D30092AC61 /* unittest.c in Sources */,
- 371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */,
- 373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */,
- 0C7C00501DD553640078BA89 /* unittest_common.c in Sources */,
- 0C5674B41DA2BF8600AF3367 /* mDNSCoreReceiveTest.c in Sources */,
- 0C10EC281DDB956E00D7A0E3 /* LocalOnlyTimeoutTests.c in Sources */,
- 0C7C00511DD5536E0078BA89 /* CNameRecordTests.c in Sources */,
- 3771F67D1BA387DD0072355E /* main.c in Sources */,
+ 84C5B33C166553F100C324A8 /* dns_services.c in Sources */,
+ BD11267A21DB2A9B006115E6 /* dnssd.c in Sources */,
+ BD11267921DB2A9B006115E6 /* dnssd_object.m in Sources */,
+ BD11267F21DB303F006115E6 /* dnssd_xpc.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 72FB545B166D5FB00090B2D9 /* Sources */ = {
+ B7325FE91DA47EBA00663834 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */,
+ B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */,
+ B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */,
+ B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */,
+ B76431A01DB0423900DB376D /* ClientCommon.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 84C5B3311665529800C324A8 /* Sources */ = {
+ B7473E5D1EC3954400D31B9D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 84C5B33C166553F100C324A8 /* dns_services.c in Sources */,
+ B7473E6C1EC3954400D31B9D /* ViewController.m in Sources */,
+ B7473E691EC3954400D31B9D /* main.m in Sources */,
+ B7473E671EC3954400D31B9D /* AppDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- B7325FE91DA47EBA00663834 /* Sources */ = {
+ B7473E761EC395C300D31B9D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */,
- B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */,
- B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */,
- B76431A01DB0423900DB376D /* ClientCommon.c in Sources */,
+ B7473E971EC3C77D00D31B9D /* CNDomainBrowserPathUtils.m in Sources */,
+ B7473E861EC395C300D31B9D /* SafariExtensionViewController.m in Sources */,
+ B7473E831EC395C300D31B9D /* SafariExtensionHandler.m in Sources */,
+ B7473E981EC3C78300D31B9D /* _CNDomainBrowser.m in Sources */,
+ B7473E961EC3C77800D31B9D /* CNDomainBrowserView.m in Sources */,
+ B7473E991EC3C86600D31B9D /* ClientCommon.c in Sources */,
+ B76373761ECA25DE00B9404A /* CNServiceBrowserView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
);
runOnlyForDeploymentPostprocessing = 0;
};
+ B74F16E72114E49C00BEBE84 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 898E98392203633800812DC6 /* dnssd_clientshim.c in Sources */,
+ D459F0D4222862BA0056AC5B /* HelperFunctionTest.m in Sources */,
+ 898E983A2203633800812DC6 /* dso-transport.c in Sources */,
+ 898E983B2203633800812DC6 /* dso.c in Sources */,
+ B7EEF7C1212601460093828F /* mDNSMacOSX.c in Sources */,
+ B7EEF7CC212604A80093828F /* LegacyNATTraversal.c in Sources */,
+ B7A86199212B074500E81CC3 /* LocalOnlyTimeoutTest.m in Sources */,
+ B7EEF7CB2126048F0093828F /* SymptomReporter.c in Sources */,
+ B7EEF7D6212606F50093828F /* uDNSPathEvalulation.c in Sources */,
+ B7EEF7EA212613260093828F /* uds_daemon.c in Sources */,
+ B7A861952127806600E81CC3 /* unittest_common.c in Sources */,
+ B7EEF7E921260E4C0093828F /* CryptoSupport.c in Sources */,
+ B7EEF7D9212607C40093828F /* nsec.c in Sources */,
+ D40123912272B6E3006C9BBE /* mdns_object.m in Sources */,
+ D461F9512203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */,
+ B7A861972127845800E81CC3 /* CNameRecordTest.m in Sources */,
+ B7EEF7C5212603D50093828F /* CryptoAlg.c in Sources */,
+ D461F94C2203A6B400A88910 /* xpc_services.c in Sources */,
+ B7EEF7EC212613D10093828F /* dnsproxy.c in Sources */,
+ B7EEF7D7212607520093828F /* mDNSDebug.c in Sources */,
+ B7EEF7E421260DC90093828F /* dnssd_ipc.c in Sources */,
+ B7EEF7E221260A610093828F /* PlatformCommon.c in Sources */,
+ B7EEF7E521260DE80093828F /* daemon.c in Sources */,
+ B7EEF7C2212602EC0093828F /* mDNS.c in Sources */,
+ B7EEF7ED212613D50093828F /* DNSProxySupport.c in Sources */,
+ D40123922272B7A7006C9BBE /* mdns.c in Sources */,
+ B7EEF7CA2126046A0093828F /* uDNS.c in Sources */,
+ D4F2BB2822CD21CB00234A38 /* posix_utilities.c in Sources */,
+ B7EEF7D82126076F0093828F /* dnssec.c in Sources */,
+ B7EEF7E021260A1F0093828F /* helper-stubs.c in Sources */,
+ B79FA14B211CE8CA00B7861E /* DNSCommon.c in Sources */,
+ B7EEF7CD212604CB0093828F /* DNSDigest.c in Sources */,
+ B7A8618B21274FA200E81CC3 /* mDNSCoreReceiveTest.m in Sources */,
+ B7EEF7DA212608F50093828F /* nsec3.c in Sources */,
+ B7EEF7DB2126090D0093828F /* DNSSECSupport.c in Sources */,
+ BDF2D02A2169961900D0DBF5 /* ClientRequests.c in Sources */,
+ B7EEF7D0212605170093828F /* D2D.c in Sources */,
+ B74F16F4211BA55400BEBE84 /* DNSMessageTest.m in Sources */,
+ D448F7AF222DCC8F0069E1D2 /* system_utilities.c in Sources */,
+ D4C2AED72203E4F900B35685 /* xpc_service_log_utility.c in Sources */,
+ B7A8618921274BFC00E81CC3 /* ResourceRecordTest.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
B76783A81E82D65900DA271E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- BD9BA7551EAF91FB00658CCF /* dnssdutil.c in Sources */,
+ BD97754C221D643600F68FFC /* dnssdutil.c in Sources */,
+ BD97754F221D64BF00F68FFC /* DNSMessage.c in Sources */,
+ BD2A15BA225ED31C00BEA50A /* mdns.c in Sources */,
+ BD2A15BB225ED33C00BEA50A /* mdns_object.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
files = (
22C7633E1D777B940077AFCA /* D2D.c in Sources */,
227687F31C90AD580019382D /* coreBLE.m in Sources */,
+ BD11267421DB1B4D006115E6 /* dnssd_xpc.c in Sources */,
+ 897729B32202A5370018FAEB /* dso-transport.c in Sources */,
D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
BD691B2A1ED2F47100E6F317 /* DNS64.c in Sources */,
+ BD11267321DB1B34006115E6 /* dnssd_server.c in Sources */,
D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */,
+ D401238B227284FE006C9BBE /* mdns.c in Sources */,
+ 897729B22202A5370018FAEB /* dso.c in Sources */,
+ D401238F227286BE006C9BBE /* mdns_object.m in Sources */,
+ D461F9502203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */,
D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */,
22448EA31C90A7BE004F25CC /* BLE.c in Sources */,
+ D461F94B2203A6B400A88910 /* xpc_services.c in Sources */,
D284BE5F0ADD80740027CCDF /* dnssd_ipc.c in Sources */,
D284BE600ADD80740027CCDF /* PlatformCommon.c in Sources */,
D284BE610ADD80740027CCDF /* mDNSMacOSX.c in Sources */,
D284BE620ADD80740027CCDF /* LegacyNATTraversal.c in Sources */,
D284BE630ADD80740027CCDF /* daemon.c in Sources */,
2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+ 897729B72202A5480018FAEB /* dnssd_clientshim.c in Sources */,
21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */,
+ BD1628D02168B02700020528 /* ClientRequests.c in Sources */,
21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */,
2124FA331471E9DE0021D7BB /* nsec.c in Sources */,
213BDC6D147319F400000896 /* dnssec.c in Sources */,
218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */,
+ D4BFF8DB22B1C52100A0BA86 /* posix_utilities.c in Sources */,
21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */,
216D9ACE1720C9F5008066E1 /* uDNSPathEvalulation.c in Sources */,
BD03E88D1AD31278005E8A81 /* SymptomReporter.c in Sources */,
2127A47715C3C7B900A857FC /* nsec3.c in Sources */,
- 21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */,
+ D421B3E022178BE700D35C20 /* system_utilities.c in Sources */,
21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */,
- 848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */,
- 8417375C1B967D37000CD5C2 /* dnsctl_server.c in Sources */,
+ D4C2AED62203E4F900B35685 /* xpc_service_log_utility.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 898E98362203621200812DC6 /* dnssd_clientshim.c in Sources */,
+ 898E98372203621200812DC6 /* dso-transport.c in Sources */,
+ 898E98382203621200812DC6 /* dso.c in Sources */,
21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */,
D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */,
D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+ D4CFA7C921E7B95E00F5AD0E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D4CFA7D121E7BA0E00F5AD0E /* liblog_mdnsresponder.m in Sources */,
+ D4A1591622E27D43002F6278 /* DNSMessage.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
FFA572320AF18F1C0055A0F1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
target = D284BE500ADD80740027CCDF /* mDNSResponder */;
targetProxy = 03067D670C83A3830022BE1F /* PBXContainerItemProxy */;
};
- 03067D6C0C83A3920022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
- targetProxy = 03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */;
- };
03067D6E0C83A39C0022BE1F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 2E0405EF0C31955500F13B59 /* mDNSResponderHelper */;
targetProxy = 03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */;
};
- 03067D860C849CC30022BE1F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 03067D640C83A3700022BE1F /* Build Some */;
- targetProxy = 03067D850C849CC30022BE1F /* PBXContainerItemProxy */;
- };
- 0C1596C71D7751AD00E09998 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */;
- targetProxy = 0C1596C61D7751AD00E09998 /* PBXContainerItemProxy */;
- };
- 0C2AAB321B6929F300113637 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 84C5B3341665529800C324A8 /* dns_services */;
- targetProxy = 0C2AAB311B6929F300113637 /* PBXContainerItemProxy */;
- };
- 0C4F36B41E206711005A536B /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 37DDE92C1BA383610092AC61 /* unittests */;
- targetProxy = 0C4F36B31E206711005A536B /* PBXContainerItemProxy */;
- };
- 0C52E92F1E96AD74006EFE7B /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 0C635A751E9418A60026C796 /* BonjourTop */;
- targetProxy = 0C52E92E1E96AD74006EFE7B /* PBXContainerItemProxy */;
- };
2130257112400E9300AC839F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */;
target = 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */;
targetProxy = 215FFB1C124002CC00470DE1 /* PBXContainerItemProxy */;
};
- 217A4C49138EE14C000A5BA8 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 213FB21712028A7A002B3A08 /* BonjourEvents */;
- targetProxy = 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */;
- };
4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 4AE471670EAFF81900A6C5AD /* dns_sd.jar */;
targetProxy = 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */;
};
- 84C5B3411665544B00C324A8 /* PBXTargetDependency */ = {
+ B70F38A6217AA6CE00612D3A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B74F16EA2114E49C00BEBE84 /* Tests */;
+ targetProxy = B70F38A7217AA6CE00612D3A /* PBXContainerItemProxy */;
+ };
+ B70F38A8217AA6CE00612D3A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BD9BA7481EAF90E400658CCF /* dnssdutil */;
+ targetProxy = B70F38A9217AA6CE00612D3A /* PBXContainerItemProxy */;
+ };
+ B70F38AE217AA6CE00612D3A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+ targetProxy = B70F38AF217AA6CE00612D3A /* PBXContainerItemProxy */;
+ };
+ B718416E21F8D0A600CA42AD /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 84C5B3341665529800C324A8 /* dns_services */;
- targetProxy = 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */;
+ targetProxy = B718416F21F8D0A600CA42AD /* PBXContainerItemProxy */;
};
- B76783B91E82D83800DA271E /* PBXTargetDependency */ = {
+ B7237FDA2194D0EF00B113B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = B76783AB1E82D65900DA271E /* BonjourPrefsTool */;
- targetProxy = B76783B81E82D83800DA271E /* PBXContainerItemProxy */;
+ target = 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */;
+ targetProxy = B7237FD92194D0EF00B113B1 /* PBXContainerItemProxy */;
};
- B7C4B72C1E71BD6000136C7A /* PBXTargetDependency */ = {
+ B7237FDC2194D16900B113B1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = B74EC1151D47FC7700A1D155 /* BonjourSettings */;
- targetProxy = B7C4B72B1E71BD6000136C7A /* PBXContainerItemProxy */;
+ target = B70F38A5217AA6CE00612D3A /* Build Extras */;
+ targetProxy = B7237FDB2194D16900B113B1 /* PBXContainerItemProxy */;
+ };
+ B7237FDE2194D16E00B113B1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B70F38A5217AA6CE00612D3A /* Build Extras */;
+ targetProxy = B7237FDD2194D16E00B113B1 /* PBXContainerItemProxy */;
+ };
+ B7237FE62194D99200B113B1 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 213FB21712028A7A002B3A08 /* BonjourEvents */;
+ targetProxy = B7237FE52194D99200B113B1 /* PBXContainerItemProxy */;
+ };
+ B7473E901EC395C300D31B9D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B7473E791EC395C300D31B9D /* Bonjour Safari Extension */;
+ targetProxy = B7473E8F1EC395C300D31B9D /* PBXContainerItemProxy */;
};
- B7C4B72E1E71BE3500136C7A /* PBXTargetDependency */ = {
+ B76783B91E82D83800DA271E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 03067D640C83A3700022BE1F /* Build Some */;
- targetProxy = B7C4B72D1E71BE3500136C7A /* PBXContainerItemProxy */;
+ target = B76783AB1E82D65900DA271E /* BonjourPrefsTool */;
+ targetProxy = B76783B81E82D83800DA271E /* PBXContainerItemProxy */;
};
B7D566C81E81D9E700E43008 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = B7D566B91E81D8FD00E43008 /* RemoteViewService */;
targetProxy = B7D566C71E81D9E700E43008 /* PBXContainerItemProxy */;
};
- BD7833F01ABA5E3500EC51ED /* PBXTargetDependency */ = {
+ B7DB589A215EB4F70054CD46 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 72FB545E166D5FB00090B2D9 /* dnsctl */;
- targetProxy = BD7833EF1ABA5E3500EC51ED /* PBXContainerItemProxy */;
+ target = B74EC1151D47FC7700A1D155 /* BonjourSettings */;
+ targetProxy = B7DB5899215EB4F70054CD46 /* PBXContainerItemProxy */;
};
- BD9BA7721EAFA3D500658CCF /* PBXTargetDependency */ = {
+ B7DB58A0215EB61C0054CD46 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = BD9BA7481EAF90E400658CCF /* dnssdutil */;
- targetProxy = BD9BA7711EAFA3D500658CCF /* PBXContainerItemProxy */;
+ target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
+ targetProxy = B7DB58A1215EB61C0054CD46 /* PBXContainerItemProxy */;
};
- D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = {
+ B7DB58A6215ED26D0054CD46 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = D284BEBF0ADD80A20027CCDF /* dnsextd */;
- targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */;
+ target = B7473E601EC3954400D31B9D /* Bonjour Safari Menu */;
+ targetProxy = B7DB58A5215ED26D0054CD46 /* PBXContainerItemProxy */;
};
- D284BF300ADD81630027CCDF /* PBXTargetDependency */ = {
+ B7DB58C2215F04490054CD46 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
- targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */;
+ target = 0C635A751E9418A60026C796 /* BonjourTop */;
+ targetProxy = B7DB58C1215F04490054CD46 /* PBXContainerItemProxy */;
+ };
+ D4528FFE21F91263004D61BF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = D4CFA7CB21E7B95E00F5AD0E /* liblog_mdnsresponder */;
+ targetProxy = D4528FFD21F91263004D61BF /* PBXContainerItemProxy */;
};
FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = FFB765830AEED9C700583A2C /* libdns_sd_dynamic */;
+ target = FFB765830AEED9C700583A2C /* libsystem_dnssd */;
targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */;
};
FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */;
+ target = FFA572300AF18F1C0055A0F1 /* libsystem_dnssd_debug */;
targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */;
};
FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */;
+ target = FFA5723C0AF18F450055A0F1 /* libsystem_dnssd_profile */;
targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */;
};
- FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
- targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */;
- };
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
- FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
+ B7473E6F1EC3954400D31B9D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
- B7E5920F1DB687A700A38085 /* Base */,
+ B7473E701EC3954400D31B9D /* Base */,
);
- name = DNSServiceDiscoveryPref.nib;
- path = PreferencePane;
- sourceTree = SOURCE_ROOT;
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+ B7473E871EC395C300D31B9D /* SafariExtensionViewController.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ B7473E881EC395C300D31B9D /* Base */,
+ );
+ name = SafariExtensionViewController.xib;
+ sourceTree = "<group>";
+ };
+ B78A9C2E223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ B78A9C2F223941A900BFB0C6 /* Base */,
+ );
+ name = DNSServiceDiscoveryPref.xib;
+ sourceTree = "<group>";
};
FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
- FF260A4C07B4477F00CE10E5 /* English */,
+ B78A9C322239485E00BFB0C6 /* en */,
);
name = InfoPlist.strings;
path = PreferencePane;
0C1596B01D773FE300E09998 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"USE_LIBIDN=1",
- "USE_AWD=0",
"__MAC_OS_X_VERSION_MIN_REQUIRED=1",
"IPV6_PKTINFO=1",
"HAVE_IPV6=1",
0C1596B11D773FE300E09998 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
"DEBUG=1",
"HAVE_IPV6=1",
"_BUILDING_XCODE_PROJECT_=1",
- "USE_AWD=0",
"__MAC_OS_X_VERSION_MIN_REQUIRED=1",
"IPV6_PKTINFO=1",
);
0C419F121BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Debug";
CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)/Debug";
COPY_PHASE_STRIP = NO;
"mDNSResponderVersion=${MVERS}",
_LEGACY_NAT_TRAVERSAL_,
"_BUILDING_XCODE_PROJECT_=1",
- "BONJOUR_ON_DEMAND=1",
"USE_LIBIDN=1",
- "USE_AWD=1",
"DEBUG=1",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
SDKROOT = macosx.internal;
STRIP_INSTALLED_PRODUCT = NO;
STRIP_STYLE = debugging;
- SUPPORTED_PLATFORMS = "macosx iphoneos";
+ SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos";
WARNING_CFLAGS = (
"-W",
"-Wall",
};
name = Debug;
};
- 0C419F131BA20DF600A70FF7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = "Build All";
- };
- name = Debug;
- };
0C419F141BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES;
"APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES;
"APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist";
CODE_SIGN_IDENTITY = "-";
FRAMEWORK_SEARCH_PATHS = (
);
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
- "HAVE_DNS64=1",
+ "MDNSRESPONDER_PLATFORM_APPLE=1",
+ DSO_USES_NETWORK_FRAMEWORK,
);
- GCC_TREAT_WARNINGS_AS_ERRORS = NO;
HEADER_SEARCH_PATHS = (
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
../mDNSShared,
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
);
INSTALL_PATH = /usr/sbin;
LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
OTHER_LDFLAGS = "";
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-weak_framework",
DeviceToDeviceManager,
- "-lMobileGestalt",
);
"OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
"-weak_framework",
"PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
PRODUCT_NAME = mDNSResponder;
PROVISIONING_PROFILE = "";
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ "-Wshadow",
+ "-Wno-format",
+ "-Wformat-security",
+ );
};
name = Debug;
};
INSTALL_PATH = /usr/sbin;
LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
MACOSX_DEPLOYMENT_TARGET = 10.10;
- OTHER_LDFLAGS = "-lipsec";
"PLIST_FILE_OUTPUT_FORMAT[sdk=appletvos*]" = binary;
"PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary;
"PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
0C419F181BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "command_line_client_entitlements/dns-sd-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
HEADER_SEARCH_PATHS = (
../mDNSShared,
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
};
name = Debug;
};
- 0C419F191BA20DF600A70FF7 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_ENTITLEMENTS = "dnsctl-entitlements.plist";
- CODE_SIGN_IDENTITY = "-";
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_STRICT_ALIASING = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/local/bin;
- MACOSX_DEPLOYMENT_TARGET = 10.9;
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE = "";
- SDKROOT = macosx;
- };
- name = Debug;
- };
0C419F1A1BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"mDNSResponderVersion=${MVERS}",
_LEGACY_NAT_TRAVERSAL_,
"_BUILDING_XCODE_PROJECT_=1",
- "BONJOUR_ON_DEMAND=1",
"USE_LIBIDN=1",
- "USE_AWD=1",
);
HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../mDNSShared",
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
"${CONFIGURATION_TEMP_DIR}",
);
INSTALL_PATH = /usr/sbin;
LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
OTHER_CFLAGS = "-UAPPLE_OSX_mDNSResponder";
PRODUCT_NAME = dnsextd;
};
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = Bonjour;
SUPPORTED_PLATFORMS = macosx;
0C419F1D1BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
BUNDLE_LOADER = /usr/libexec/UserEventAgent;
- CODE_SIGN_IDENTITY = "-";
INFOPLIST_FILE = "BonjourEvents-Info.plist";
INSTALL_PATH = /System/Library/UserEventPlugins/;
PRODUCT_NAME = BonjourEvents;
INSTALL_PATH = /usr/lib/system;
INTERPOSITION_SIM_SUFFIX = "";
"INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim;
- IS_ZIPPERED = YES;
+ "IS_ZIPPERED[sdk=macosx*]" = YES;
LINK_WITH_STANDARD_LIBRARIES = NO;
OTHER_LDFLAGS = (
"-Wl,-umbrella,System",
"-lsystem_c",
"-lsystem_blocks",
"-ldispatch",
- "-llaunch",
"-lsystem_asl",
);
OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
"-lsystem_c",
"-lsystem_blocks",
"-ldispatch",
- "-llaunch",
"-lsystem_asl",
);
- OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+ OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
PRODUCT_NAME = libsystem_dnssd_debug;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
SUPPORTS_TEXT_BASED_API = YES;
"-lsystem_c",
"-lsystem_blocks",
"-ldispatch",
- "-llaunch",
"-lsystem_asl",
);
- OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+ OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
PRODUCT_NAME = libsystem_dnssd_profile;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
SUPPORTS_TEXT_BASED_API = YES;
0C419F271BA20DF600A70FF7 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+ CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
+ CLANG_WARN_ASSIGN_ENUM = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_CXX0X_EXTENSIONS = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_FLOAT_CONVERSION = YES;
+ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
+ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
+ CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+ CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
EXECUTABLE_PREFIX = lib;
- GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+ GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+ GCC_WARN_PEDANTIC = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INSTALL_PATH = /usr/lib;
- MACOSX_DEPLOYMENT_TARGET = 10.8;
+ "IS_ZIPPERED[sdk=macosx*]" = YES;
+ LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
+ LLVM_LTO = YES;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx;
+ SDKROOT = macosx.internal;
+ SUPPORTS_TEXT_BASED_API = YES;
+ TAPI_VERIFY_MODE = Pedantic;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wall",
+ "-Warc-repeated-use-of-weak",
+ "-Wassign-enum",
+ "-Wconditional-uninitialized",
+ "-Wconversion",
+ "-Werror",
+ "-Werror-implicit-function-declaration",
+ "-Wextra",
+ "-Wfour-char-constants",
+ "-Wpedantic",
+ "-Wsign-compare",
+ "-Wsign-conversion",
+ "-Wundef",
+ "-Wuninitialized",
+ "-Wunreachable-code",
+ "-Wunused-parameter",
+ "-Wunused-parameter",
+ "-Wstrict-selector-match",
+ "-Wexplicit-ownership-type",
+ "-pedantic",
+ "-Wno-nullability-extension",
+ );
};
name = Debug;
};
0C635A7A1E9418A60026C796 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-lncurses";
PRODUCT_NAME = bonjourtop;
0C635A7B1E9418A60026C796 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-lncurses";
213FB21A12028A7B002B3A08 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
BUNDLE_LOADER = /usr/libexec/UserEventAgent;
- CODE_SIGN_IDENTITY = "-";
INFOPLIST_FILE = "BonjourEvents-Info.plist";
INSTALL_PATH = /System/Library/UserEventPlugins/;
PRODUCT_NAME = BonjourEvents;
);
INSTALL_PATH = /usr/sbin;
LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
- OTHER_LDFLAGS = "-lipsec";
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
"PLIST_FILE_OUTPUT_FORMAT[sdk=appletvos*]" = binary;
"PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary;
"PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
};
name = Release;
};
- 37AF80281BF6997A00D657F6 /* Release */ = {
+ 84C5B3371665529800C324A8 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- COPY_PHASE_STRIP = YES;
- DEAD_CODE_STRIPPING = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- );
- GCC_PREPROCESSOR_DEFINITIONS = (
- "__APPLE_USE_RFC_3542=1",
- "APPLE_OSX_mDNSResponder=1",
- "__MigTypeCheck=1",
- "mDNSResponderVersion=${MVERS}",
- _LEGACY_NAT_TRAVERSAL_,
- "_BUILDING_XCODE_PROJECT_=1",
- "BONJOUR_ON_DEMAND=1",
- "USE_LIBIDN=1",
- "USE_AWD=1",
- "UNIT_TEST=1",
- "NO_AWACS=1",
- );
- GCC_TREAT_WARNINGS_AS_ERRORS = NO;
- HEADER_SEARCH_PATHS = (
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
- ../mDNSShared,
- "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
- "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
- "${CONFIGURATION_TEMP_DIR}",
- "$(SDKROOT)/usr/include/libxml2",
- "$(SDKROOT)/usr/local/include/",
- "$(SDKROOT)/usr/include/",
- );
- LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+ CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
+ CLANG_WARN_ASSIGN_ENUM = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_CXX0X_EXTENSIONS = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_FLOAT_CONVERSION = YES;
+ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
+ CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
+ CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+ CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
+ EXECUTABLE_PREFIX = lib;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+ GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+ GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+ GCC_WARN_PEDANTIC = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/lib;
+ "IS_ZIPPERED[sdk=macosx*]" = YES;
+ LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
+ LLVM_LTO = YES;
ONLY_ACTIVE_ARCH = NO;
- OTHER_LDFLAGS = (
- "-weak_framework",
- WebFilterDNS,
- "-weak_framework",
- DeviceToDeviceManager,
- );
- PRODUCT_NAME = unittests;
- SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = macosx;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTS_TEXT_BASED_API = YES;
+ TAPI_VERIFY_MODE = Pedantic;
WARNING_CFLAGS = (
- "-W",
+ "$(inherited)",
"-Wall",
- "-Wmissing-prototypes",
- "-Wno-four-char-constants",
- "-Wno-unknown-pragmas",
- "-Wshadow",
- "-Wno-format",
- "-Wformat-security",
+ "-Warc-repeated-use-of-weak",
+ "-Wassign-enum",
+ "-Wconditional-uninitialized",
+ "-Wconversion",
+ "-Werror",
+ "-Werror-implicit-function-declaration",
+ "-Wextra",
+ "-Wfour-char-constants",
+ "-Wpedantic",
+ "-Wsign-compare",
+ "-Wsign-conversion",
+ "-Wundef",
+ "-Wuninitialized",
+ "-Wunreachable-code",
+ "-Wunused-parameter",
+ "-Wunused-parameter",
+ "-Wstrict-selector-match",
+ "-Wexplicit-ownership-type",
+ "-pedantic",
+ "-Wno-nullability-extension",
);
};
name = Release;
};
- 37AF80291BF6997A00D657F6 /* Debug */ = {
+ B70F38B1217AA6CE00612D3A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- COPY_PHASE_STRIP = NO;
- DEAD_CODE_STRIPPING = YES;
- ENABLE_TESTABILITY = YES;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
- );
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "__APPLE_USE_RFC_3542=1",
- "APPLE_OSX_mDNSResponder=1",
- "__MigTypeCheck=1",
- "mDNSResponderVersion=${MVERS}",
- _LEGACY_NAT_TRAVERSAL_,
- "_BUILDING_XCODE_PROJECT_=1",
- "DEBUG=1",
- "BONJOUR_ON_DEMAND=1",
- "USE_LIBIDN=1",
- "USE_AWD=1",
- "UNIT_TEST=1",
- "NO_AWACS=1",
- );
- GCC_TREAT_WARNINGS_AS_ERRORS = NO;
- HEADER_SEARCH_PATHS = (
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
- ../mDNSShared,
- "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
- "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
- "${CONFIGURATION_TEMP_DIR}",
- "$(SDKROOT)/usr/include/libxml2",
- "$(SDKROOT)/usr/local/include/",
- "$(SDKROOT)/usr/include/",
- );
- LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
- ONLY_ACTIVE_ARCH = NO;
- OTHER_LDFLAGS = (
- "-weak_framework",
- WebFilterDNS,
- "-weak_framework",
- DeviceToDeviceManager,
- );
- PRODUCT_NAME = unittests;
- SUPPORTED_PLATFORMS = "macosx iphoneos";
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
};
- name = Debug;
+ name = Release;
};
- 72FB5466166D5FB00090B2D9 /* Release */ = {
+ B70F38B2217AA6CE00612D3A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_ENTITLEMENTS = "dnsctl-entitlements.plist";
- CODE_SIGN_IDENTITY = "-";
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_STRICT_ALIASING = YES;
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/local/bin;
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ CODE_SIGN_STYLE = Automatic;
PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE = "";
- SDKROOT = macosx;
};
- name = Release;
+ name = Debug;
};
- 84C5B3371665529800C324A8 /* Release */ = {
+ B718417321F8D0A600CA42AD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- EXECUTABLE_PREFIX = lib;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- INSTALL_PATH = /usr/lib;
- MACOSX_DEPLOYMENT_TARGET = 10.8;
- ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "$(TARGET_NAME)";
- SDKROOT = macosx;
};
name = Release;
};
- B7325FF41DA47EBA00663834 /* Release */ = {
+ B718417421F8D0A600CA42AD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ B7325FF41DA47EBA00663834 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
B7325FF51DA47EBA00663834 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
};
name = Debug;
};
+ B7473E731EC3954400D31B9D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Menu/BonjourSafariMenu.entitlements";
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "Bonjour Safari Menu/Info.plist";
+ INSTALL_PATH = /AppleInternal/Applications;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ B7473E741EC3954400D31B9D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Menu/BonjourSafariMenu.entitlements";
+ CODE_SIGN_IDENTITY = "-";
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "Bonjour Safari Menu/Info.plist";
+ INSTALL_PATH = /AppleInternal/Applications;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ B7473E931EC395C300D31B9D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Extension/BonjourSafariExtension.entitlements";
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "Bonjour Safari Extension/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu.BonjourSafariExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+ B7473E941EC395C300D31B9D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Extension/BonjourSafariExtension.entitlements";
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INFOPLIST_FILE = "Bonjour Safari Extension/Info.plist";
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu.BonjourSafariExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SKIP_INSTALL = YES;
+ };
+ name = Debug;
+ };
B74EC11C1D47FC7800A1D155 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
B74EC11D1D47FC7800A1D155 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
"DEBUG=1",
"${inherited}",
);
- INFOPLIST_FILE = SettingsBundle/Info.plist;
- INSTALL_PATH = /AppleInternal/Library/PreferenceBundles;
- MTL_ENABLE_DEBUG_INFO = YES;
+ INFOPLIST_FILE = SettingsBundle/Info.plist;
+ INSTALL_PATH = /AppleInternal/Library/PreferenceBundles;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.network.bonjour.BonjourSettings;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = iphoneos.internal;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ B74F16F12114E49D00BEBE84 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "UNIT_TEST=1",
+ "USE_XCTEST=1",
+ "MDNSRESPONDER_PLATFORM_APPLE=1",
+ "MDNSRESPONDER_SUPPORTS_APPLE_METRICS=0",
+ "MDNSRESPONDER_SUPPORTS_APPLE_DNS64=0",
+ "MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE=0",
+ "MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH=0",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSCore,
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/usr/include/libxml2",
+ "${CONFIGURATION_TEMP_DIR}",
+ );
+ INFOPLIST_FILE = Tests/Info.plist;
+ INSTALL_PATH = /AppleInternal/XCTests/com.apple.mDNSResponder/;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ MTL_FAST_MATH = YES;
+ OTHER_CFLAGS = (
+ "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
+ "-DNO_SECURITYFRAMEWORK",
+ "-fwrapv",
+ "-flto=full",
+ );
+ OTHER_LDFLAGS = (
+ "-weak_framework",
+ WebFilterDNS,
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
+ "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.Tests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = iphoneos.internal;
+ SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ "-Wshadow",
+ "-Wno-format",
+ "-Wformat-security",
+ );
+ };
+ name = Release;
+ };
+ B74F16F22114E49D00BEBE84 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "UNIT_TEST=1",
+ "USE_XCTEST=1",
+ "MDNSRESPONDER_PLATFORM_APPLE=1",
+ "MDNSRESPONDER_SUPPORTS_APPLE_METRICS=0",
+ "MDNSRESPONDER_SUPPORTS_APPLE_DNS64=0",
+ "MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE=0",
+ "MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH=0",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ../mDNSCore,
+ ../mDNSShared,
+ "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/usr/include/libxml2",
+ "${CONFIGURATION_TEMP_DIR}",
+ );
+ INFOPLIST_FILE = Tests/Info.plist;
+ INSTALL_PATH = /AppleInternal/XCTests/com.apple.mDNSResponder/;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.apple.network.bonjour.BonjourSettings;
+ OTHER_CFLAGS = (
+ "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
+ "-DNO_SECURITYFRAMEWORK",
+ "-fwrapv",
+ );
+ OTHER_LDFLAGS = (
+ "-weak_framework",
+ WebFilterDNS,
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
+ "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+ "-weak_framework",
+ DeviceToDeviceManager,
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.Tests;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos.internal;
- SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
- TARGETED_DEVICE_FAMILY = "1,2";
+ SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ "-Wshadow",
+ "-Wno-format",
+ "-Wformat-security",
+ );
};
name = Debug;
};
B76783B51E82D65900DA271E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist";
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_NAME = com.apple.preference.bonjour.tool;
SDKROOT = macosx.internal;
B76783B61E82D65900DA271E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist";
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = com.apple.preference.bonjour.tool;
};
name = Debug;
};
- B7C4B7261E71BD5000136C7A /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Release;
- };
- B7C4B7271E71BD5000136C7A /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Debug;
- };
B7D566C41E81D8FD00E43008 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist";
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_NAME = com.apple.preference.bonjour.remoteservice;
SKIP_INSTALL = YES;
B7D566C51E81D8FD00E43008 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist";
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = com.apple.preference.bonjour.remoteservice;
B7D6CA761D1076F3005E24CF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPRESSION = "respect-asset-catalog";
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = ../mDNSUI/DomainBrowser/macOS/Info.plist;
INSTALL_PATH = "@rpath";
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.apple.coreos.network.bonjour.DomainBrowser;
PRODUCT_NAME = DomainBrowser;
B7D6CA771D1076F3005E24CF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPRESSION = lossless;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = ../mDNSUI/DomainBrowser/macOS/Info.plist;
INSTALL_PATH = "@rpath";
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.apple.coreos.network.bonjour.DomainBrowser;
};
name = Debug;
};
+ B7DB5896215EB4DD0054CD46 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ B7DB5897215EB4DD0054CD46 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ B7DB58A3215EB61C0054CD46 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ B7DB58A4215EB61C0054CD46 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
BD9BA7511EAF90E400658CCF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_GCD_PERFORMANCE = YES;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
- CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = NO;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
- CODE_SIGN_ENTITLEMENTS = "dnssdutil-entitlements.plist";
+ CODE_SIGN_ENTITLEMENTS = "../Clients/dnssdutil/dnssdutil-entitlements.plist";
CODE_SIGN_IDENTITY = "-";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
- GCC_PREPROCESSOR_DEFINITIONS = "MDNSRESPONDER_PROJECT=1";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "MDNSRESPONDER_PROJECT=1",
+ "DEBUG=0",
+ );
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
HEADER_SEARCH_PATHS = "$(SDKROOT)${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders";
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = "$(TARGET_NAME)";
- WARNING_CFLAGS = "-Wno-nullability-extension";
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Warc-repeated-use-of-weak",
+ "-Wassign-enum",
+ "-Wconditional-uninitialized",
+ "-Wconversion",
+ "-Werror",
+ "-Werror-implicit-function-declaration",
+ "-Wextra",
+ "-Wfour-char-constants",
+ "-Wnullable-to-nonnull-conversion",
+ "-Wsign-compare",
+ "-Wsign-conversion",
+ "-Wundef",
+ "-Wuninitialized",
+ "-Wunreachable-code",
+ "-Wunused-parameter",
+ "-Wunused-parameter",
+ "-Wstrict-selector-match",
+ "-Wexplicit-ownership-type",
+ "-Wpedantic",
+ "-pedantic",
+ "-Wno-nullability-extension",
+ "-Wno-fixed-enum-extension",
+ );
};
name = Release;
};
BD9BA7521EAF90E400658CCF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_GCD_PERFORMANCE = YES;
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
- CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = NO;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_ASSIGN_ENUM = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
- CODE_SIGN_ENTITLEMENTS = "dnssdutil-entitlements.plist";
+ CODE_SIGN_ENTITLEMENTS = "../Clients/dnssdutil/dnssdutil-entitlements.plist";
CODE_SIGN_IDENTITY = "-";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
HEADER_SEARCH_PATHS = "$(SDKROOT)${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders";
INSTALL_PATH = /usr/local/bin;
PRODUCT_NAME = "$(TARGET_NAME)";
- WARNING_CFLAGS = "-Wno-nullability-extension";
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Warc-repeated-use-of-weak",
+ "-Wassign-enum",
+ "-Wconditional-uninitialized",
+ "-Wconversion",
+ "-Werror",
+ "-Werror-implicit-function-declaration",
+ "-Wextra",
+ "-Wfour-char-constants",
+ "-Wnullable-to-nonnull-conversion",
+ "-Wsign-compare",
+ "-Wsign-conversion",
+ "-Wundef",
+ "-Wuninitialized",
+ "-Wunreachable-code",
+ "-Wunused-parameter",
+ "-Wunused-parameter",
+ "-Wstrict-selector-match",
+ "-Wexplicit-ownership-type",
+ "-Wpedantic",
+ "-pedantic",
+ "-Wno-nullability-extension",
+ "-Wno-fixed-enum-extension",
+ );
};
name = Debug;
};
- D284BE290ADD78180027CCDF /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- PRODUCT_NAME = "Build All";
- };
- name = Release;
- };
D284BE2C0ADD78180027CCDF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Release";
CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)/Release";
COPY_PHASE_STRIP = NO;
"mDNSResponderVersion=${MVERS}",
_LEGACY_NAT_TRAVERSAL_,
"_BUILDING_XCODE_PROJECT_=1",
- "BONJOUR_ON_DEMAND=1",
"USE_LIBIDN=1",
- "USE_AWD=1",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
OTHER_CFLAGS = (
"-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
"-fwrapv",
+ "-flto=full",
);
SDKROOT = macosx.internal;
STRIP_STYLE = debugging;
+ SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos";
WARNING_CFLAGS = (
"-W",
"-Wall",
"APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES;
"APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES;
"APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist";
CODE_SIGN_IDENTITY = "-";
FRAMEWORK_SEARCH_PATHS = (
);
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
- "HAVE_DNS64=1",
+ "MDNSRESPONDER_PLATFORM_APPLE=1",
+ DSO_USES_NETWORK_FRAMEWORK,
);
- GCC_TREAT_WARNINGS_AS_ERRORS = NO;
HEADER_SEARCH_PATHS = (
- "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
../mDNSShared,
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
);
INSTALL_PATH = /usr/sbin;
LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
OTHER_LDFLAGS = "";
"OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
"-weak_framework",
DeviceToDeviceManager,
- "-lMobileGestalt",
);
"OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
"-weak_framework",
"PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
PRODUCT_NAME = mDNSResponder;
PROVISIONING_PROFILE = "";
+ WARNING_CFLAGS = (
+ "-W",
+ "-Wall",
+ "-Wmissing-prototypes",
+ "-Wno-four-char-constants",
+ "-Wno-unknown-pragmas",
+ "-Wshadow",
+ "-Wno-format",
+ "-Wformat-security",
+ );
};
name = Release;
};
D284BEAE0ADD80920027CCDF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "command_line_client_entitlements/dns-sd-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
HEADER_SEARCH_PATHS = (
../mDNSShared,
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
+ "$(SRCROOT)/../mDNSShared",
"${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
"${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
"${CONFIGURATION_TEMP_DIR}",
);
INSTALL_PATH = /usr/sbin;
LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
OTHER_CFLAGS = "-UAPPLE_OSX_mDNSResponder";
PRODUCT_NAME = dnsextd;
};
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
- MACOSX_DEPLOYMENT_TARGET = 10.9;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
PRODUCT_NAME = Bonjour;
SUPPORTED_PLATFORMS = macosx;
WRAPPER_EXTENSION = prefPane;
};
name = Release;
};
+ D4CFA7CD21E7B95E00F5AD0E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ EXECUTABLE_PREFIX = "";
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/lib/log;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SKIP_INSTALL = NO;
+ };
+ name = Release;
+ };
+ D4CFA7CE21E7B95E00F5AD0E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ CODE_SIGN_STYLE = Automatic;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ EXECUTABLE_PREFIX = "";
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/lib/log;
+ MACOSX_DEPLOYMENT_TARGET = 10.14;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SKIP_INSTALL = NO;
+ };
+ name = Debug;
+ };
FFA572380AF18F1C0055A0F1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"-lsystem_c",
"-lsystem_blocks",
"-ldispatch",
- "-llaunch",
"-lsystem_asl",
);
- OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+ OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
PRODUCT_NAME = libsystem_dnssd_debug;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
SUPPORTS_TEXT_BASED_API = YES;
"-lsystem_c",
"-lsystem_blocks",
"-ldispatch",
- "-llaunch",
"-lsystem_asl",
);
- OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+ OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
PRODUCT_NAME = libsystem_dnssd_profile;
PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
SUPPORTS_TEXT_BASED_API = YES;
INSTALL_PATH = /usr/lib/system;
INTERPOSITION_SIM_SUFFIX = "";
"INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim;
- IS_ZIPPERED = YES;
+ "IS_ZIPPERED[sdk=macosx*]" = YES;
LINK_WITH_STANDARD_LIBRARIES = NO;
OTHER_LDFLAGS = (
"-Wl,-umbrella,System",
"-lsystem_c",
"-lsystem_blocks",
"-ldispatch",
- "-llaunch",
"-lsystem_asl",
);
OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = {
+ 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Core" */ = {
isa = XCConfigurationList;
buildConfigurations = (
03067D740C83A3CB0022BE1F /* Release */,
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */ = {
+ 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 37AF80281BF6997A00D657F6 /* Release */,
- 37AF80291BF6997A00D657F6 /* Debug */,
+ 0C419F291BA20DF600A70FF7 /* Debug */,
+ 37AF80271BF6997A00D657F6 /* Release */,
);
defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Development;
+ defaultConfigurationName = Release;
};
- 4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
+ 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 0C419F291BA20DF600A70FF7 /* Debug */,
- 37AF80271BF6997A00D657F6 /* Release */,
+ 84C5B3371665529800C324A8 /* Release */,
+ 0C419F271BA20DF600A70FF7 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */ = {
+ B70F38B0217AA6CE00612D3A /* Build configuration list for PBXAggregateTarget "Build Extras" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 72FB5466166D5FB00090B2D9 /* Release */,
- 0C419F191BA20DF600A70FF7 /* Debug */,
+ B70F38B1217AA6CE00612D3A /* Release */,
+ B70F38B2217AA6CE00612D3A /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = {
+ B718417221F8D0A600CA42AD /* Build configuration list for PBXAggregateTarget "Build Services" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 84C5B3371665529800C324A8 /* Release */,
- 0C419F271BA20DF600A70FF7 /* Debug */,
+ B718417321F8D0A600CA42AD /* Release */,
+ B718417421F8D0A600CA42AD /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ B7473E751EC3954400D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Menu" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7473E731EC3954400D31B9D /* Release */,
+ B7473E741EC3954400D31B9D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B7473E921EC395C300D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Extension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7473E931EC395C300D31B9D /* Release */,
+ B7473E941EC395C300D31B9D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
B74EC11E1D47FC7800A1D155 /* Build configuration list for PBXNativeTarget "BonjourSettings" */ = {
isa = XCConfigurationList;
buildConfigurations = (
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */ = {
+ B74F16F02114E49D00BEBE84 /* Build configuration list for PBXNativeTarget "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- B76783B51E82D65900DA271E /* Release */,
- B76783B61E82D65900DA271E /* Debug */,
+ B74F16F12114E49D00BEBE84 /* Release */,
+ B74F16F22114E49D00BEBE84 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- B7C4B7281E71BD5000136C7A /* Build configuration list for PBXAggregateTarget "Build Some iOS" */ = {
+ B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- B7C4B7261E71BD5000136C7A /* Release */,
- B7C4B7271E71BD5000136C7A /* Debug */,
+ B76783B51E82D65900DA271E /* Release */,
+ B76783B61E82D65900DA271E /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- BD9BA7501EAF90E400658CCF /* Build configuration list for PBXNativeTarget "dnssdutil" */ = {
+ B7DB5898215EB4DD0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- BD9BA7511EAF90E400658CCF /* Release */,
- BD9BA7521EAF90E400658CCF /* Debug */,
+ B7DB5896215EB4DD0054CD46 /* Release */,
+ B7DB5897215EB4DD0054CD46 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B7DB58A2215EB61C0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-macOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B7DB58A3215EB61C0054CD46 /* Release */,
+ B7DB58A4215EB61C0054CD46 /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
+ BD9BA7501EAF90E400658CCF /* Build configuration list for PBXNativeTarget "dnssdutil" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- D284BE290ADD78180027CCDF /* Release */,
- 0C419F131BA20DF600A70FF7 /* Debug */,
+ BD9BA7511EAF90E400658CCF /* Release */,
+ BD9BA7521EAF90E400658CCF /* Debug */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */ = {
+ D4CFA7CF21E7B95E00F5AD0E /* Build configuration list for PBXNativeTarget "liblog_mdnsresponder" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ D4CFA7CD21E7B95E00F5AD0E /* Release */,
+ D4CFA7CE21E7B95E00F5AD0E /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_debug" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FFA572380AF18F1C0055A0F1 /* Release */,
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */ = {
+ FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_profile" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FFA572440AF18F450055A0F1 /* Release */,
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */ = {
+ FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libsystem_dnssd" */ = {
isa = XCConfigurationList;
buildConfigurations = (
FFB7658A0AEED9FB00583A2C /* Release */,
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
+ <TestableReference
+ skipped = "NO">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "B74F16EA2114E49C00BEBE84"
+ BuildableName = "Tests.xctest"
+ BlueprintName = "Tests"
+ ReferencedContainer = "container:mDNSResponder.xcodeproj">
+ </BuildableReference>
+ </TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
--- /dev/null
+/*
+ * Copyright (c) 2019 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mdns_private.h"
+
+#include "mdns_object.h"
+
+#include <CoreUtils/CoreUtils.h>
+#include <network_information.h>
+#include <notify.h>
+#include <os/log.h>
+#include <os/object_private.h>
+
+//======================================================================================================================
+// MARK: - Kind Declarations
+
+#define MDNS_STRUCT(NAME) struct mdns_ ## NAME ## _s
+
+// Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
+// comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
+// the warning hasn't been disabled.
+
+#define MDNS_BASE_CHECK(NAME, SUPER) \
+ check_compile_time(offsetof(MDNS_STRUCT(NAME), base) == 0); \
+ check_compile_time(sizeof_field(MDNS_STRUCT(NAME), base) == sizeof(MDNS_STRUCT(SUPER))); \
+ extern int _mdns_base_type_check[sizeof(&(((mdns_ ## NAME ## _t)0)->base) == ((mdns_ ## SUPER ## _t)0))]
+
+#define MDNS_OBJECT_SUBKIND_DEFINE(NAME) \
+ static void \
+ _mdns_ ## NAME ## _finalize(mdns_ ## NAME ## _t object); \
+ \
+ static char * \
+ _mdns_ ## NAME ## _copy_description(mdns_ ## NAME ## _t object, bool debug, bool privacy); \
+ \
+ static const struct mdns_kind_s _mdns_ ## NAME ## _kind = { \
+ &_mdns_object_kind, \
+ # NAME, \
+ _mdns_ ## NAME ## _copy_description, \
+ _mdns_ ## NAME ## _finalize \
+ }; \
+ \
+ static mdns_ ## NAME ## _t \
+ _mdns_ ## NAME ## _alloc(void) \
+ { \
+ mdns_ ## NAME ## _t obj = mdns_object_ ## NAME ## _alloc(sizeof(*obj)); \
+ require_quiet(obj, exit); \
+ \
+ const mdns_object_t base = (mdns_object_t)obj; \
+ base->kind = &_mdns_ ## NAME ## _kind; \
+ \
+ exit: \
+ return obj; \
+ } \
+ MDNS_BASE_CHECK(NAME, object)
+
+typedef char * (*mdns_copy_description_f)(mdns_any_t object, bool debug, bool privacy);
+typedef void (*mdns_finalize_f)(mdns_any_t object);
+
+typedef const struct mdns_kind_s * mdns_kind_t;
+struct mdns_kind_s {
+ mdns_kind_t superkind; // This kind's superkind.
+ const char * name; // Name of this kind.
+ mdns_copy_description_f copy_description; // Creates a textual description of object.
+ mdns_finalize_f finalize; // Releases object's resources right before the object is freed.
+};
+
+//======================================================================================================================
+// MARK: - mdns_object Kind Definition
+
+struct mdns_object_s {
+ _OS_OBJECT_HEADER(const void *_os_obj_isa, _os_obj_refcnt, _os_obj_xref_cnt);
+ mdns_kind_t kind; // Pointer to an object's kind.
+};
+
+static const struct mdns_kind_s _mdns_object_kind = {
+ NULL, // No superkind.
+ "object", // Name.
+ NULL, // No copy_description method.
+ NULL // No finalize method.
+};
+
+static const void *
+_mdns_cf_collection_callback_retain(CFAllocatorRef allocator, const void *object);
+
+static void
+_mdns_cf_collection_callback_release(CFAllocatorRef allocator, const void *object);
+
+static CFStringRef
+_mdns_cf_collection_callback_copy_description(const void *object);
+
+const CFArrayCallBacks mdns_cfarray_callbacks = {
+ 0, // version
+ _mdns_cf_collection_callback_retain, // retain
+ _mdns_cf_collection_callback_release, // release
+ _mdns_cf_collection_callback_copy_description, // copy description
+ NULL // equal (NULL for pointer equality)
+};
+
+//======================================================================================================================
+// MARK: - mdns_interface_monitor Kind Definition
+
+struct mdns_interface_monitor_s {
+ struct mdns_object_s base; // Object base.
+ mdns_interface_monitor_t next; // Next monitor in list.
+ dispatch_queue_t user_queue; // User's queue for invoking handlers.
+ nw_path_evaluator_t path_evaluator; // Path evaluator for interface properties.
+ dispatch_source_t update_source; // Data source for triggering user's update handler.
+ mdns_interface_monitor_update_handler_t update_handler; // User's update handler.
+ mdns_event_handler_t event_handler; // User's event handler.
+ char * ifname; // Name of monitored interface.
+ uint32_t ifindex; // Index of monitored interface.
+ mdns_interface_flags_t pending_flags; // The latest interface flags from path updates.
+ mdns_interface_flags_t flags; // The current interface flags made known to user.
+ bool user_activated; // True if user called activate method.
+ bool activated; // True if the monitor has been activated.
+ bool invalidated; // True if the monitor has been invalidated.
+ bool path_evaluator_started; // True if the path evaluator has been started.
+};
+
+MDNS_OBJECT_SUBKIND_DEFINE(interface_monitor);
+
+//======================================================================================================================
+// MARK: - Local Prototypes
+
+static dispatch_queue_t
+_mdns_internal_queue(void);
+
+static dispatch_queue_t
+_mdns_nwi_state_mutex_queue(void);
+
+static void
+_mdns_interface_monitor_activate_async(mdns_interface_monitor_t monitor);
+
+static void
+_mdns_interface_monitor_terminate(mdns_interface_monitor_t me, const OSStatus error);
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nw_path(nw_path_t path, mdns_interface_flags_t current_flags);
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nwi_state(const char *ifname, mdns_interface_flags_t current_flags);
+
+static int
+_mdns_snprintf_add(char **ptr, const char *lim, const char *fmt, ...);
+
+static void
+_mdns_start_nwi_state_monitoring(void);
+
+#if !defined(nw_forget)
+ #define nw_forget(X) ForgetCustom(X, nw_release)
+#endif
+
+#if !defined(nw_release_null_safe)
+ #define nw_release_null_safe(X) do { if (X) { nw_release(X); } } while (0)
+#endif
+
+#if !defined(nwi_state_release_null_safe)
+ #define nwi_state_release_null_safe(X) do { if (X) { nwi_state_release(X); } } while (0)
+#endif
+
+//======================================================================================================================
+// MARK: - Globals
+
+static mdns_interface_monitor_t g_monitor_list = NULL;
+static nwi_state_t g_nwi_state = NULL;
+
+//======================================================================================================================
+// MARK: - Internals
+
+static dispatch_queue_t
+_mdns_internal_queue(void)
+{
+ static dispatch_once_t s_once = 0;
+ static dispatch_queue_t s_queue = NULL;
+ dispatch_once(&s_once,
+ ^{
+ s_queue = dispatch_queue_create("com.apple.mdns.internal_queue", DISPATCH_QUEUE_SERIAL);
+ });
+ return s_queue;
+}
+
+//======================================================================================================================
+
+static dispatch_queue_t
+_mdns_nwi_state_mutex_queue(void)
+{
+ static dispatch_once_t s_once = 0;
+ static dispatch_queue_t s_queue = NULL;
+ dispatch_once(&s_once,
+ ^{
+ s_queue = dispatch_queue_create("com.apple.mdns.nwi_state_mutex", DISPATCH_QUEUE_SERIAL);
+ });
+ return s_queue;
+}
+
+//======================================================================================================================
+
+#define MDNS_LOG_CATEGORY_DEFINE(SHORT_NAME, CATEGORY_STR) \
+ static os_log_t \
+ _mdns_ ## SHORT_NAME ## _log(void) \
+ { \
+ static dispatch_once_t s_once = 0; \
+ static os_log_t s_log = NULL; \
+ dispatch_once(&s_once, \
+ ^{ \
+ s_log = os_log_create("com.apple.mdns", CATEGORY_STR); \
+ }); \
+ return s_log; \
+ } \
+ extern int _mdns_dummy_variable
+
+MDNS_LOG_CATEGORY_DEFINE(ifmon, "interface_monitor");
+MDNS_LOG_CATEGORY_DEFINE(nwi, "NWI");
+
+//======================================================================================================================
+// MARK: - mdns_object Public Methods
+
+void
+mdns_retain(mdns_any_t object)
+{
+ os_retain(object.base);
+}
+
+//======================================================================================================================
+
+void
+mdns_release(mdns_any_t object)
+{
+ os_release(object.base);
+}
+
+//======================================================================================================================
+
+char *
+mdns_copy_description(mdns_any_t object)
+{
+ return mdns_object_copy_description(object, false, false);
+}
+
+//======================================================================================================================
+// MARK: - mdns_object Private Methods
+
+char *
+mdns_object_copy_description(mdns_any_t object, bool debug, bool privacy)
+{
+ for (mdns_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+ if (kind->copy_description) {
+ return kind->copy_description(object, debug, privacy);
+ }
+ }
+ return NULL;
+}
+
+//======================================================================================================================
+
+CFStringRef
+mdns_object_copy_description_as_cfstring(mdns_any_t object, bool debug, bool privacy)
+{
+ CFStringRef description = NULL;
+ char *cstring = mdns_object_copy_description(object, debug, privacy);
+ require_quiet(cstring, exit);
+
+ description = CFStringCreateWithCStringNoCopy(NULL, cstring, kCFStringEncodingUTF8, kCFAllocatorMalloc);
+ require_quiet(description, exit);
+ cstring = NULL;
+
+exit:
+ FreeNullSafe(cstring);
+ return description;
+}
+
+//======================================================================================================================
+
+void
+mdns_object_finalize(mdns_any_t object)
+{
+ for (mdns_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+ if (kind->finalize) {
+ kind->finalize(object);
+ }
+ }
+}
+
+//======================================================================================================================
+
+static const void *
+_mdns_cf_collection_callback_retain(__unused CFAllocatorRef allocator, const void *object)
+{
+ mdns_retain((mdns_object_t)object);
+ return object;
+}
+
+//======================================================================================================================
+
+static void
+_mdns_cf_collection_callback_release(__unused CFAllocatorRef allocator, const void *object)
+{
+ mdns_release((mdns_object_t)object);
+}
+
+//======================================================================================================================
+
+static CFStringRef
+_mdns_cf_collection_callback_copy_description(const void *object)
+{
+ return mdns_object_copy_description_as_cfstring((mdns_object_t)object, false, false);
+}
+
+//======================================================================================================================
+// MARK: - mdns_interface_monitor Public Methods
+
+mdns_interface_monitor_t
+mdns_interface_monitor_create(uint32_t interface_index)
+{
+ mdns_interface_monitor_t monitor = NULL;
+ nw_interface_t interface = NULL;
+ nw_parameters_t params = NULL;
+
+ mdns_interface_monitor_t obj = _mdns_interface_monitor_alloc();
+ require_quiet(obj, exit);
+
+ obj->ifindex = interface_index;
+ char ifname[IF_NAMESIZE + 1];
+ if (if_indextoname(obj->ifindex, ifname) == NULL) {
+ os_log_error(_mdns_ifmon_log(), "if_indextoname returned NULL for index %u", obj->ifindex);
+ goto exit;
+ }
+ obj->ifname = strdup(ifname);
+ require_quiet(obj->ifname, exit);
+
+ interface = nw_interface_create_with_index(obj->ifindex);
+ if (!interface) {
+ os_log_error(_mdns_ifmon_log(), "nw_interface_create_with_index returned NULL for index %u", obj->ifindex);
+ goto exit;
+ }
+
+ params = nw_parameters_create();
+ require_quiet(params, exit);
+
+ nw_parameters_require_interface(params, interface);
+ obj->path_evaluator = nw_path_create_evaluator_for_endpoint(NULL, params);
+ if (!obj->path_evaluator) {
+ os_log_error(_mdns_ifmon_log(), "nw_path_create_evaluator_for_endpoint returned NULL for params: %@", params);
+ goto exit;
+ }
+
+ nw_path_t path = nw_path_evaluator_copy_path(obj->path_evaluator);
+ require_quiet(path, exit);
+
+ obj->pending_flags = _mdns_get_interface_flags_from_nw_path(path, mdns_interface_flag_null);
+ obj->pending_flags = _mdns_get_interface_flags_from_nwi_state(obj->ifname, obj->pending_flags);
+ obj->flags = obj->pending_flags;
+ nw_forget(&path);
+
+ monitor = obj;
+ obj = NULL;
+
+exit:
+ if (obj) {
+ mdns_release(obj);
+ }
+ nw_release_null_safe(interface);
+ nw_release_null_safe(params);
+ return monitor;
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_activate(mdns_interface_monitor_t me)
+{
+ if (!me->user_activated) {
+ if (me->user_queue) {
+ _mdns_interface_monitor_activate_async(me);
+ }
+ me->user_activated = true;
+ }
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_invalidate(mdns_interface_monitor_t me)
+{
+ mdns_retain(me);
+ dispatch_async(_mdns_internal_queue(),
+ ^{
+ if (!me->invalidated) {
+ _mdns_interface_monitor_terminate(me, kNoErr);
+ me->invalidated = true;
+ }
+ mdns_release(me);
+ });
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_set_queue(mdns_interface_monitor_t me, dispatch_queue_t queue)
+{
+ if (!me->user_activated) {
+ dispatch_retain(queue);
+ dispatch_release_null_safe(me->user_queue);
+ me->user_queue = queue;
+ } else if (!me->user_queue) {
+ me->user_queue = queue;
+ dispatch_retain(me->user_queue);
+ _mdns_interface_monitor_activate_async(me);
+ }
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_set_event_handler(mdns_interface_monitor_t me, mdns_event_handler_t handler)
+{
+ mdns_event_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+ if (me->event_handler) {
+ Block_release(me->event_handler);
+ }
+ me->event_handler = new_handler;
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_set_update_handler(mdns_interface_monitor_t me, mdns_interface_monitor_update_handler_t handler)
+{
+ mdns_interface_monitor_update_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+ if (me->update_handler) {
+ Block_release(me->update_handler);
+ }
+ me->update_handler = new_handler;
+}
+
+//======================================================================================================================
+
+uint32_t
+mdns_interface_monitor_get_interface_index(mdns_interface_monitor_t me)
+{
+ return me->ifindex;
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_has_ipv4_connectivity(mdns_interface_monitor_t me)
+{
+ return ((me->flags & mdns_interface_flag_ipv4_connectivity) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_has_ipv6_connectivity(mdns_interface_monitor_t me)
+{
+ return ((me->flags & mdns_interface_flag_ipv6_connectivity) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_is_expensive(mdns_interface_monitor_t me)
+{
+ return ((me->flags & mdns_interface_flag_expensive) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_is_constrained(mdns_interface_monitor_t me)
+{
+ return ((me->flags & mdns_interface_flag_constrained) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_is_clat46(mdns_interface_monitor_t me)
+{
+ return ((me->flags & mdns_interface_flag_clat46) ? true : false);
+}
+
+//======================================================================================================================
+// MARK: - mdns_interface_monitor Private Methods
+
+typedef struct {
+ mdns_interface_flags_t flag;
+ const char * desc;
+} mdns_interface_flag_description_t;
+
+const mdns_interface_flag_description_t mdns_interface_flag_descriptions[] = {
+ { mdns_interface_flag_ipv4_connectivity, "IPv4" },
+ { mdns_interface_flag_ipv6_connectivity, "IPv6" },
+ { mdns_interface_flag_expensive, "expensive" },
+ { mdns_interface_flag_constrained, "constrained" },
+ { mdns_interface_flag_clat46, "CLAT46" }
+};
+
+static char *
+_mdns_interface_monitor_copy_description(mdns_interface_monitor_t me, const bool debug, __unused const bool privacy)
+{
+ char * description = NULL;
+ char buffer[128];
+ char * dst = buffer;
+ const char * const lim = &buffer[countof(buffer)];
+ int n;
+
+ *dst = '\0';
+ if (debug) {
+ n = _mdns_snprintf_add(&dst, lim, "mdns_%s (%p): ", me->base.kind->name, me);
+ require_quiet(n >= 0, exit);
+ }
+ n = _mdns_snprintf_add(&dst, lim, "interface %s (%u): ", me->ifname, me->ifindex);
+ require_quiet(n >= 0, exit);
+
+ const char *separator = "";
+ for (size_t i = 0; i < countof(mdns_interface_flag_descriptions); ++i) {
+ const mdns_interface_flag_description_t * const flag_desc = &mdns_interface_flag_descriptions[i];
+ if (me->flags & flag_desc->flag) {
+ n = _mdns_snprintf_add(&dst, lim, "%s%s", separator, flag_desc->desc);
+ require_quiet(n >= 0, exit);
+ separator = ", ";
+ }
+ }
+ description = strdup(buffer);
+
+exit:
+ return description;
+}
+
+//======================================================================================================================
+
+static void
+_mdns_interface_monitor_finalize(mdns_interface_monitor_t me)
+{
+ dispatch_forget(&me->user_queue);
+ nw_forget(&me->path_evaluator);
+ BlockForget(&me->update_handler);
+ BlockForget(&me->event_handler);
+ ForgetMem(&me->ifname);
+}
+
+//======================================================================================================================
+
+static void
+_mdns_interface_monitor_activate_internal(mdns_interface_monitor_t monitor);
+
+static void
+_mdns_interface_monitor_activate_async(mdns_interface_monitor_t me)
+{
+ mdns_retain(me);
+ dispatch_async(_mdns_internal_queue(),
+ ^{
+ _mdns_interface_monitor_activate_internal(me);
+ mdns_release(me);
+ });
+}
+
+static void
+_mdns_interface_monitor_activate_internal(mdns_interface_monitor_t me)
+{
+ OSStatus err;
+ require_action_quiet(!me->activated && !me->invalidated, exit, err = kNoErr);
+ me->activated = true;
+
+ me->update_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_REPLACE, 0, 0, me->user_queue);
+ require_action_quiet(me->update_source, exit, err = kNoResourcesErr);
+
+ mdns_retain(me);
+ const dispatch_source_t update_source = me->update_source;
+ dispatch_source_set_event_handler(me->update_source,
+ ^{
+ const unsigned long data = dispatch_source_get_data(update_source);
+ const mdns_interface_flags_t new_flags = ((mdns_interface_flags_t)data) & ~mdns_interface_flag_reserved;
+ const mdns_interface_flags_t changed_flags = me->flags ^ new_flags;
+ if (changed_flags != 0) {
+ me->flags = new_flags;
+ if (me->update_handler) {
+ me->update_handler(changed_flags);
+ }
+ }
+ });
+ dispatch_source_set_cancel_handler(me->update_source,
+ ^{
+ mdns_release(me);
+ });
+ dispatch_activate(me->update_source);
+
+ mdns_retain(me);
+ nw_path_evaluator_set_update_handler(me->path_evaluator, _mdns_internal_queue(),
+ ^(nw_path_t path)
+ {
+ const mdns_interface_flags_t new_flags = _mdns_get_interface_flags_from_nw_path(path, me->pending_flags);
+ if (new_flags != me->pending_flags) {
+ me->pending_flags = new_flags;
+ if (me->update_source) {
+ // Note: mdns_interface_flag_reserved is used to ensure that the data is non-zero. According to the
+ // dispatch_source_create(3) man page, if the data value is zero, the source handler won't be invoked.
+ dispatch_source_merge_data(me->update_source, me->pending_flags | mdns_interface_flag_reserved);
+ }
+ }
+ });
+ nw_path_evaluator_set_cancel_handler(me->path_evaluator,
+ ^{
+ mdns_release(me);
+ });
+ nw_path_evaluator_start(me->path_evaluator);
+ me->path_evaluator_started = true;
+
+ mdns_interface_monitor_t *p = &g_monitor_list;
+ while (*p != NULL) {
+ p = &(*p)->next;
+ }
+ mdns_retain(me);
+ *p = me;
+
+ // This is called after adding the monitor to the global list to ensure that the initial NWI state check is aware
+ // that the interface monitor exists.
+ _mdns_start_nwi_state_monitoring();
+ err = kNoErr;
+
+exit:
+ if (err) {
+ _mdns_interface_monitor_terminate(me, err);
+ }
+}
+
+//======================================================================================================================
+
+static void
+_mdns_interface_monitor_terminate(mdns_interface_monitor_t me, const OSStatus error)
+{
+ dispatch_source_forget(&me->update_source);
+ if (me->path_evaluator) {
+ if (me->path_evaluator_started) {
+ nw_path_evaluator_cancel(me->path_evaluator);
+ }
+ nw_forget(&me->path_evaluator);
+ }
+ for (mdns_interface_monitor_t *p = &g_monitor_list; *p; p = &(*p)->next) {
+ if (*p == me) {
+ *p = me->next;
+ me->next = NULL;
+ mdns_release(me);
+ break;
+ }
+ }
+ mdns_retain(me);
+ dispatch_async(me->user_queue,
+ ^{
+ if (me->event_handler) {
+ me->event_handler(error ? mdns_event_error : mdns_event_invalidated, error);
+ }
+ mdns_release(me);
+ });
+}
+
+//======================================================================================================================
+// MARK: - NW Path Helpers
+
+#define MDNS_INTERFACE_FLAGS_FROM_NWPATH \
+ (mdns_interface_flag_ipv4_connectivity | \
+ mdns_interface_flag_ipv6_connectivity | \
+ mdns_interface_flag_expensive | \
+ mdns_interface_flag_constrained)
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nw_path(nw_path_t path, mdns_interface_flags_t current_flags)
+{
+ mdns_interface_flags_t flags = current_flags & ~MDNS_INTERFACE_FLAGS_FROM_NWPATH;
+ if (nw_path_has_ipv4(path)) {
+ flags |= mdns_interface_flag_ipv4_connectivity;
+ }
+ if (nw_path_has_ipv6(path)) {
+ flags |= mdns_interface_flag_ipv6_connectivity;
+ }
+ if (nw_path_is_expensive(path)) {
+ flags |= mdns_interface_flag_expensive;
+ }
+ if (__builtin_available(macOS 10.15, *)) {
+ if (nw_path_is_constrained(path)) {
+ flags |= mdns_interface_flag_constrained;
+ }
+ }
+ return flags;
+}
+
+//======================================================================================================================
+// MARK: - NWI Helpers
+
+#if !defined(NWI_IFSTATE_FLAGS_HAS_CLAT46)
+ #define NWI_IFSTATE_FLAGS_HAS_CLAT46 0x0040
+#endif
+
+#define MDNS_INTERFACE_FLAGS_FROM_NWI_STATE mdns_interface_flag_clat46
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nwi_state(const char *ifname, mdns_interface_flags_t current_flags)
+{
+ __block nwi_ifstate_flags ifstate_flags = 0;
+ dispatch_sync(_mdns_nwi_state_mutex_queue(),
+ ^{
+ if (g_nwi_state) {
+ const nwi_ifstate_t ifstate = nwi_state_get_ifstate(g_nwi_state, ifname);
+ if (ifstate) {
+ ifstate_flags = nwi_ifstate_get_flags(ifstate);
+ }
+ }
+ });
+ mdns_interface_flags_t flags = current_flags & ~MDNS_INTERFACE_FLAGS_FROM_NWI_STATE;
+ if (ifstate_flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) {
+ flags |= mdns_interface_flag_clat46;
+ }
+ return flags;
+}
+
+//======================================================================================================================
+
+static void
+_mdns_nwi_state_update(void);
+
+static void
+_mdns_start_nwi_state_monitoring(void)
+{
+ static int s_nwi_notify_token = NOTIFY_TOKEN_INVALID;
+ if (s_nwi_notify_token == NOTIFY_TOKEN_INVALID) {
+ const uint32_t status = notify_register_dispatch(nwi_state_get_notify_key(), &s_nwi_notify_token,
+ _mdns_internal_queue(),
+ ^(__unused int token)
+ {
+ _mdns_nwi_state_update();
+ });
+ if (s_nwi_notify_token == NOTIFY_TOKEN_INVALID) {
+ os_log_error(_mdns_nwi_log(), "Failed to register for NWI state notifications (status %u)", status);
+ } else {
+ _mdns_nwi_state_update();
+ }
+ }
+}
+
+static void
+_mdns_nwi_state_update(void)
+{
+ nwi_state_t new_state = nwi_state_copy();
+ if (!new_state) {
+ os_log_error(_mdns_nwi_log(), "Failed to copy NWI state");
+ }
+ __block nwi_state_t old_state;
+ dispatch_sync(_mdns_nwi_state_mutex_queue(),
+ ^{
+ old_state = g_nwi_state;
+ g_nwi_state = new_state;
+ });
+ nwi_state_release_null_safe(old_state);
+ for (mdns_interface_monitor_t m = g_monitor_list; m; m = m->next) {
+ const mdns_interface_flags_t new_flags = _mdns_get_interface_flags_from_nwi_state(m->ifname, m->pending_flags);
+ if (new_flags != m->pending_flags) {
+ m->pending_flags = new_flags;
+ if (m->update_source) {
+ // Note: mdns_interface_flag_reserved is used to ensure that the data is non-zero. According to the
+ // dispatch_source_create(3) man page, if the data value is zero, the source handler won't be invoked.
+ dispatch_source_merge_data(m->update_source, m->pending_flags | mdns_interface_flag_reserved);
+ }
+ }
+ }
+}
+
+//======================================================================================================================
+// MARK: - General Helpers
+
+static int
+_mdns_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
+{
+ char * const dst = *ptr;
+ const size_t len = (size_t)(lim - dst);
+ int n;
+
+ require_action_quiet(len > 0, exit, n = 0);
+
+ va_list args;
+ va_start(args, fmt);
+ n = vsnprintf(dst, len, fmt, args);
+ va_end(args);
+ require_quiet(n >= 0, exit);
+
+ if (((size_t)n) > len) {
+ n = (int)len;
+ }
+ *ptr = dst + n;
+
+exit:
+ return n;
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MDNS_OBJECT_H__
+#define __MDNS_OBJECT_H__
+
+#include "mdns_private.h"
+
+//======================================================================================================================
+// MARK: - mdns_object Private Method Declarations
+
+char *
+mdns_object_copy_description(mdns_any_t object, bool debug, bool privacy);
+
+CFStringRef
+mdns_object_copy_description_as_cfstring(mdns_any_t object, bool debug, bool privacy);
+
+void
+mdns_object_finalize(mdns_any_t object);
+
+#define MDNS_OBJECT_ALLOC_DECLARE(NAME) \
+ mdns_ ## NAME ## _t \
+ mdns_object_ ## NAME ## _alloc(size_t size)
+
+MDNS_OBJECT_ALLOC_DECLARE(interface_monitor);
+
+#endif // __MDNS_OBJECT_H__
--- /dev/null
+/*
+ * Copyright (c) 2019 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "mdns_object.h"
+
+#import <CoreUtils/CoreUtils.h>
+#import <Foundation/Foundation.h>
+#import <os/object_private.h>
+
+//======================================================================================================================
+// MARK: - Class Declarations
+
+#define MDNS_OBJECT_CLASS_DECLARE(NAME) \
+ _OS_OBJECT_DECL_SUBCLASS_INTERFACE(mdns_ ## NAME, mdns_object) \
+ extern int _mdns_dummy_variable
+
+_OS_OBJECT_DECL_SUBCLASS_INTERFACE(mdns_object, object)
+
+MDNS_OBJECT_CLASS_DECLARE(interface_monitor);
+
+//======================================================================================================================
+// MARK: - Class Definitions
+
+@implementation OS_OBJECT_CLASS(mdns_object)
+- (void)dealloc
+{
+ mdns_object_finalize(self);
+ arc_safe_super_dealloc();
+}
+
+- (NSString *)description
+{
+ return arc_safe_autorelease((NSString *)mdns_object_copy_description_as_cfstring(self, false, false));
+}
+
+- (NSString *)debugDescription
+{
+ return arc_safe_autorelease((NSString *)mdns_object_copy_description_as_cfstring(self, true, false));
+}
+
+- (NSString *)redactedDescription
+{
+ return arc_safe_autorelease((NSString *)mdns_object_copy_description_as_cfstring(self, false, true));
+}
+@end
+
+#define MDNS_CLASS(NAME) OS_OBJECT_CLASS(mdns_ ## NAME)
+#define MDNS_OBJECT_CLASS_DEFINE(NAME) \
+ @implementation MDNS_CLASS(NAME) \
+ @end \
+ \
+ mdns_ ## NAME ## _t \
+ mdns_object_ ## NAME ## _alloc(const size_t size) \
+ { \
+ return (mdns_## NAME ##_t)_os_object_alloc([MDNS_CLASS(NAME) class], size); \
+ } \
+ extern int _mdns_dummy_variable
+
+MDNS_OBJECT_CLASS_DEFINE(interface_monitor);
--- /dev/null
+/*
+ * Copyright (c) 2019 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
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MDNS_PRIVATE_H__
+#define __MDNS_PRIVATE_H__
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <dispatch/dispatch.h>
+#include <MacTypes.h>
+#include <os/object.h>
+
+#if OS_OBJECT_USE_OBJC
+ #define MDNS_DECL(NAME) OS_OBJECT_DECL_SUBCLASS(mdns_ ## NAME, mdns_object)
+ #define MDNS_RETURNS_RETAINED OS_OBJECT_RETURNS_RETAINED
+
+ OS_OBJECT_DECL(mdns_object,);
+#else
+ #define MDNS_DECL(NAME) typedef struct mdns_ ## NAME ## _s * mdns_ ## NAME ## _t
+ #define MDNS_RETURNS_RETAINED
+
+ MDNS_DECL(object);
+#endif
+
+// mdns Object Declarations
+
+MDNS_DECL(interface_monitor);
+
+OS_ASSUME_NONNULL_BEGIN
+
+#if OS_OBJECT_USE_OBJC
+ typedef mdns_object_t mdns_any_t;
+#else
+ #if !defined(__cplusplus)
+ typedef union {
+ mdns_object_t base;
+ mdns_interface_monitor_t interface_monitor;
+ } mdns_any_t __attribute__((__transparent_union__));
+ #else
+ typedef void * mdns_any_t;
+ #endif
+#endif
+
+__BEGIN_DECLS
+
+/*!
+ * @brief
+ * Increments the reference count of an mdns object.
+ *
+ * @param object
+ * The mdns object.
+ */
+void
+mdns_retain(mdns_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+ #undef mdns_retain
+ #define mdns_retain(object) [(object) retain]
+#endif
+
+/*!
+ * @brief
+ * Decrements the reference count of an mdns object.
+ *
+ * @param object
+ * The mdns object.
+ */
+void
+mdns_release(mdns_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+ #undef mdns_release
+ #define mdns_release(object) [(object) release]
+#endif
+
+/*!
+ * @brief
+ * Creates a human-readable description of an mdns object as a C string.
+ *
+ * @param object
+ * The mdns object.
+ *
+ * @result
+ * A C string that must be freed with free(3).
+ */
+OS_WARN_RESULT
+char * _Nullable
+mdns_copy_description(mdns_any_t object);
+
+/*!
+ * @brief
+ * CFArray callbacks for mdns objects.
+ */
+extern const CFArrayCallBacks mdns_cfarray_callbacks;
+
+/*!
+ * @brief
+ * Creates an interface monitor.
+ *
+ * @param interface_index
+ * Index of the interface to monitor.
+ *
+ * @result
+ * A new interface monitor or NULL if there was a lack of resources.
+ *
+ * @discussion
+ * An interface monitor provides up-to-date information about an interface's properties, such as IPv4
+ * connectivity, IPv6 connectivity, whether the interface is expensive, and whether the interface is constrained.
+ *
+ * If this function returns non-NULL, then the caller has an ownership reference to the newly created interface
+ * monitor, which can be relinquished with <code>mdns_release()</code>.
+ */
+MDNS_RETURNS_RETAINED mdns_interface_monitor_t _Nullable
+mdns_interface_monitor_create(uint32_t interface_index);
+
+/*!
+ * @brief
+ * Activates an interface monitor.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * Successful activation enables interface monitor updates.
+ *
+ * This function has no effect on an interface monitor that has already been activated or one that has been
+ * invalidated.
+ */
+void
+mdns_interface_monitor_activate(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Asynchronously invalidates an interface monitor.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * This function should be called when the interface monitor is no longer needed.
+ *
+ * As a result of calling this function, the interface monitor's event handler will be invoked with a
+ * <code>mdns_event_invalidated</code> event, after which the interface monitor's event and update handlers will
+ * never be invoked again.
+ *
+ * This function has no effect on an interface monitor that has already been invalidated.
+ */
+void
+mdns_interface_monitor_invalidate(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Specifies the queue on which to invoke the interface monitor's event and update handlers.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @param queue
+ * A serial queue.
+ *
+ * @discussion
+ * This function must be called before activating the interface monitor.
+ *
+ * This function has no effect on an interface monitor that has been activated or invalidated.
+ */
+void
+mdns_interface_monitor_set_queue(mdns_interface_monitor_t monitor, dispatch_queue_t queue);
+
+/*!
+ * @brief
+ * Generic events that can occur during the lifetime of an mdns object.
+ */
+OS_CLOSED_ENUM(mdns_event, int,
+ /*! @const mdns_event_error A fatal error has occurred. */
+ mdns_event_error = 1,
+ /*! @const mdns_event_invalidated The object has been invalidated. */
+ mdns_event_invalidated = 2
+);
+
+static inline const char *
+mdns_event_to_string(mdns_event_t event)
+{
+ switch (event) {
+ case mdns_event_error: return "Error";
+ case mdns_event_invalidated: return "Invalidated";
+ default: return "?";
+ }
+}
+
+/*!
+ * @brief
+ * Generic event handler for mdns objects.
+ *
+ * @param event
+ * The event.
+ *
+ * @param error
+ * The error associated with a <code>mdns_event_error</code> event. This argument should be ignored for all other
+ * types of events.
+ *
+ * @discussion
+ * After an <code>mdns_event_invalidated</code> event, none of the object's handlers will ever be invoked again.
+ */
+typedef void (^mdns_event_handler_t)(mdns_event_t event, OSStatus error);
+
+/*!
+ * @brief
+ * Sets an interface monitor's event handler.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @param handler
+ * The event handler.
+ *
+ * @discussion
+ * The event handler will never be invoked prior to activation.
+ *
+ * The event handler will be invoked on the dispatch queue specified by
+ * <code>mdns_interface_monitor_set_queue()</code> with event <code>mdns_event_error</code> when a fatal error
+ * occurs and with event <code>mdns_event_invalidated</code> when the interface monitor has been invalidated.
+ *
+ * After an <code>mdns_event_invalidated</code> event, the event handler will never be invoked again.
+ */
+void
+mdns_interface_monitor_set_event_handler(mdns_interface_monitor_t monitor, mdns_event_handler_t _Nullable handler);
+
+/*!
+ * @brief
+ * Flags that represent the properties of a monitored interface.
+ *
+ * @discussion
+ * These flags don't represent the actual values of properties. The meaning of these flags depends on the context
+ * in which they're used. For example, as a parameter of mdns_interface_monitor_update_handler_t, a set flag
+ * means that the value of a given property has changed.
+ */
+OS_CLOSED_OPTIONS(mdns_interface_flags, uint32_t,
+ mdns_interface_flag_null = 0,
+ mdns_interface_flag_ipv4_connectivity = (1U << 0),
+ mdns_interface_flag_ipv6_connectivity = (1U << 1),
+ mdns_interface_flag_expensive = (1U << 2),
+ mdns_interface_flag_constrained = (1U << 3),
+ mdns_interface_flag_clat46 = (1U << 4),
+ mdns_interface_flag_reserved = (1U << 31)
+);
+
+/*!
+ * @brief
+ * Update handler for an interface monitor.
+ *
+ * @param change_flags
+ * Each flag bit represents a property of a monitored interface. If the bit is set, then the value of that
+ * property has changed. If the bit is clear, then the value of that property has not changed.
+ */
+typedef void (^mdns_interface_monitor_update_handler_t)(mdns_interface_flags_t change_flags);
+
+/*!
+ * @brief
+ * Sets an interface monitor's update handler.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @param handler
+ * The update handler.
+ *
+ * @discussion
+ * The update handler will never be invoked prior to activation.
+ *
+ * The update handler will be invoked on the dispatch queue specified by
+ * <code>mdns_interface_monitor_set_queue()</code> when any of the monitored interface's properties have been
+ * updated.
+ *
+ * After an <code>mdns_event_invalidated</code> event, the update handler will ever be invoked again.
+ */
+void
+mdns_interface_monitor_set_update_handler(mdns_interface_monitor_t monitor,
+ mdns_interface_monitor_update_handler_t _Nullable handler);
+
+/*!
+ * @brief
+ * Returns the index of the monitored interface.
+ *
+ * @param monitor
+ * The interface monitor.
+ */
+uint32_t
+mdns_interface_monitor_get_interface_index(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Determines whether the monitored interface currently has IPv4 connectivity.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * mdns_interface_flag_ipv4_connectivity will be set in the update handler's change_flags argument when the value
+ * of this property has changed.
+ */
+bool
+mdns_interface_monitor_has_ipv4_connectivity(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Determines whether the monitored interface currently has IPv6 connectivity.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * mdns_interface_flag_ipv6_connectivity will be set in the update handler's change_flags argument when the value
+ * of this property has changed.
+ */
+bool
+mdns_interface_monitor_has_ipv6_connectivity(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Determines whether the monitored interface is currently expensive.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * mdns_interface_flag_expensive will be set in the update handler's change_flags argument when the value
+ * of this property has changed.
+ */
+bool
+mdns_interface_monitor_is_expensive(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Determines whether the monitored interface is currently constrained.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * mdns_interface_flag_constrained will be set in the update handler's change_flags argument when the value
+ * of this property has changed.
+ */
+bool
+mdns_interface_monitor_is_constrained(mdns_interface_monitor_t monitor);
+
+/*!
+ * @brief
+ * Determines whether the monitored interface has CLAT46 support.
+ *
+ * @param monitor
+ * The interface monitor.
+ *
+ * @discussion
+ * mdns_interface_flag_clat46 will be set in the update handler's change_flags argument when the value
+ * of this property has changed.
+ */
+bool
+mdns_interface_monitor_is_clat46(mdns_interface_monitor_t monitor);
+
+__END_DECLS
+
+OS_ASSUME_NONNULL_END
+
+#endif // __MDNS_PRIVATE_H__
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */
-/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */
-
-/*
- * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the project nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <net/pfkeyv2.h>
-#include <netinet/in.h>
-#include <netinet6/ipsec.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <TargetConditionals.h>
-
-#include "ipsec_strerror.h"
-#include "libpfkey.h"
-#include "ipsec_options.h"
-
-#if TARGET_OS_EMBEDDED
-#ifndef MDNS_NO_IPSEC
-#define MDNS_NO_IPSEC 1
-#endif
-#endif
-
-#ifndef MDNS_NO_IPSEC
-
-#define CALLOC(size, cast) (cast)calloc(1, (size))
-
-static int findsupportedmap __P((int));
-static int setsupportedmap __P((struct sadb_supported *));
-static struct sadb_alg *findsupportedalg __P((u_int, u_int));
-static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *,
- struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t,
- u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t,
- u_int32_t, u_int32_t, u_int32_t));
-static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
- struct sockaddr *, struct sockaddr *, u_int32_t));
-static int pfkey_send_x3 __P((int, u_int, u_int));
-static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
- struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
- char *, int, u_int32_t));
-static int pfkey_send_x5 __P((int, u_int, u_int32_t));
-
-static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
- u_int, u_int32_t, pid_t));
-static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
- u_int, u_int, u_int32_t));
-static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
- struct sockaddr *, u_int, u_int));
-static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
-static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
- u_int32_t, u_int32_t, u_int32_t));
-static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
-
-/*
- * make and search supported algorithm structure.
- */
-static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, };
-
-static int supported_map[] = {
- SADB_SATYPE_AH,
- SADB_SATYPE_ESP,
- SADB_X_SATYPE_IPCOMP,
-};
-
-static int
-findsupportedmap(satype)
-int satype;
-{
- int i;
-
- for (i = 0; (unsigned int)i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
- if (supported_map[i] == satype)
- return i;
- return -1;
-}
-
-static struct sadb_alg *
-findsupportedalg(satype, alg_id)
-u_int satype, alg_id;
-{
- int algno;
- int tlen;
- caddr_t p;
-
- /* validity check */
- algno = findsupportedmap(satype);
- if (algno == -1) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return NULL;
- }
- if (ipsec_supported[algno] == NULL) {
- __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
- return NULL;
- }
-
- tlen = ipsec_supported[algno]->sadb_supported_len
- - sizeof(struct sadb_supported);
- p = (caddr_t)(ipsec_supported[algno] + 1);
- while (tlen > 0) {
- if ((unsigned int)tlen < sizeof(struct sadb_alg)) {
- /* invalid format */
- break;
- }
- if (((struct sadb_alg *)p)->sadb_alg_id == alg_id)
- return (struct sadb_alg *)p;
-
- tlen -= sizeof(struct sadb_alg);
- p += sizeof(struct sadb_alg);
- }
-
- __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
- return NULL;
-}
-
-static int
-setsupportedmap(sup)
-struct sadb_supported *sup;
-{
- struct sadb_supported **ipsup;
-
- switch (sup->sadb_supported_exttype) {
- case SADB_EXT_SUPPORTED_AUTH:
- ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
- break;
- case SADB_EXT_SUPPORTED_ENCRYPT:
- ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
-
- if (*ipsup)
- free(*ipsup);
-
- *ipsup = malloc(sup->sadb_supported_len);
- if (!*ipsup) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- memcpy(*ipsup, sup, sup->sadb_supported_len);
-
- return 0;
-}
-
-/*
- * check key length against algorithm specified.
- * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
- * augument, and only calls to ipsec_check_keylen2();
- * keylen is the unit of bit.
- * OUT:
- * -1: invalid.
- * 0: valid.
- */
-int
-ipsec_check_keylen(supported, alg_id, keylen)
-u_int supported;
-u_int alg_id;
-u_int keylen;
-{
- int satype;
-
- /* validity check */
- switch (supported) {
- case SADB_EXT_SUPPORTED_AUTH:
- satype = SADB_SATYPE_AH;
- break;
- case SADB_EXT_SUPPORTED_ENCRYPT:
- satype = SADB_SATYPE_ESP;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- return ipsec_check_keylen2(satype, alg_id, keylen);
-}
-
-/*
- * check key length against algorithm specified.
- * satype is one of satype defined at pfkeyv2.h.
- * keylen is the unit of bit.
- * OUT:
- * -1: invalid.
- * 0: valid.
- */
-int
-ipsec_check_keylen2(satype, alg_id, keylen)
-u_int satype;
-u_int alg_id;
-u_int keylen;
-{
- struct sadb_alg *alg;
-
- alg = findsupportedalg(satype, alg_id);
- if (!alg)
- return -1;
-
- if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
- __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
- return -1;
- }
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return 0;
-}
-
-/*
- * get max/min key length against algorithm specified.
- * satype is one of satype defined at pfkeyv2.h.
- * keylen is the unit of bit.
- * OUT:
- * -1: invalid.
- * 0: valid.
- */
-int
-ipsec_get_keylen(supported, alg_id, alg0)
-u_int supported, alg_id;
-struct sadb_alg *alg0;
-{
- struct sadb_alg *alg;
- u_int satype;
-
- /* validity check */
- if (!alg0) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- switch (supported) {
- case SADB_EXT_SUPPORTED_AUTH:
- satype = SADB_SATYPE_AH;
- break;
- case SADB_EXT_SUPPORTED_ENCRYPT:
- satype = SADB_SATYPE_ESP;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- alg = findsupportedalg(satype, alg_id);
- if (!alg)
- return -1;
-
- memcpy(alg0, alg, sizeof(*alg0));
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return 0;
-}
-
-/*
- * set the rate for SOFT lifetime against HARD one.
- * If rate is more than 100 or equal to zero, then set to 100.
- */
-static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
-static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
-static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
-static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
-
-u_int
-pfkey_set_softrate(type, rate)
-u_int type, rate;
-{
- __ipsec_errcode = EIPSEC_NO_ERROR;
-
- if (rate > 100 || rate == 0)
- rate = 100;
-
- switch (type) {
- case SADB_X_LIFETIME_ALLOCATIONS:
- soft_lifetime_allocations_rate = rate;
- return 0;
- case SADB_X_LIFETIME_BYTES:
- soft_lifetime_bytes_rate = rate;
- return 0;
- case SADB_X_LIFETIME_ADDTIME:
- soft_lifetime_addtime_rate = rate;
- return 0;
- case SADB_X_LIFETIME_USETIME:
- soft_lifetime_usetime_rate = rate;
- return 0;
- }
-
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return 1;
-}
-
-/*
- * get current rate for SOFT lifetime against HARD one.
- * ATTENTION: ~0 is returned if invalid type was passed.
- */
-u_int
-pfkey_get_softrate(type)
-u_int type;
-{
- switch (type) {
- case SADB_X_LIFETIME_ALLOCATIONS:
- return soft_lifetime_allocations_rate;
- case SADB_X_LIFETIME_BYTES:
- return soft_lifetime_bytes_rate;
- case SADB_X_LIFETIME_ADDTIME:
- return soft_lifetime_addtime_rate;
- case SADB_X_LIFETIME_USETIME:
- return soft_lifetime_usetime_rate;
- }
-
- return ~0;
-}
-
-/*
- * sending SADB_GETSPI message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq)
-int so;
-u_int satype, mode;
-struct sockaddr *src, *dst;
-u_int32_t min, max, reqid, seq;
-{
- struct sadb_msg *newmsg;
- caddr_t ep;
- int len;
- int need_spirange = 0;
- caddr_t p;
- int plen;
-
- /* validity check */
- if (src == NULL || dst == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
- if (src->sa_family != dst->sa_family) {
- __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
- return -1;
- }
- if (min > max || (min > 0 && min <= 255)) {
- __ipsec_errcode = EIPSEC_INVAL_SPI;
- return -1;
- }
- switch (src->sa_family) {
- case AF_INET:
- plen = sizeof(struct in_addr) << 3;
- break;
- case AF_INET6:
- plen = sizeof(struct in6_addr) << 3;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_FAMILY;
- return -1;
- }
-
- /* create new sadb_msg to send. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_x_sa2)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(src->sa_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(dst->sa_len);
-
- if (min > (u_int32_t)255 && max < (u_int32_t) ~0) {
- need_spirange++;
- len += sizeof(struct sadb_spirange);
- }
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI,
- len, satype, seq, getpid());
- if (!p) {
- free(newmsg);
- return -1;
- }
-
- p = pfkey_setsadbxsa2(p, ep, mode, reqid);
- if (!p) {
- free(newmsg);
- return -1;
- }
-
- /* set sadb_address for source */
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
- IPSEC_ULPROTO_ANY);
- if (!p) {
- free(newmsg);
- return -1;
- }
-
- /* set sadb_address for destination */
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
- IPSEC_ULPROTO_ANY);
- if (!p) {
- free(newmsg);
- return -1;
- }
-
- /* proccessing spi range */
- if (need_spirange) {
- struct sadb_spirange spirange;
-
- if (p + sizeof(spirange) > ep) {
- free(newmsg);
- return -1;
- }
-
- memset(&spirange, 0, sizeof(spirange));
- spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
- spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
- spirange.sadb_spirange_min = min;
- spirange.sadb_spirange_max = max;
-
- memcpy(p, &spirange, sizeof(spirange));
-
- p += sizeof(spirange);
- }
- if (p != ep) {
- free(newmsg);
- return -1;
- }
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/*
- * sending SADB_UPDATE message to the kernel.
- * The length of key material is a_keylen + e_keylen.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize,
- keymat, e_type, e_keylen, a_type, a_keylen, flags,
- l_alloc, l_bytes, l_addtime, l_usetime, seq)
-int so;
-u_int satype, mode, wsize;
-struct sockaddr *src, *dst;
-u_int32_t spi, reqid;
-caddr_t keymat;
-u_int e_type, e_keylen, a_type, a_keylen, flags;
-u_int32_t l_alloc;
-u_int64_t l_bytes, l_addtime, l_usetime;
-u_int32_t seq;
-{
- int len;
- if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi,
- reqid, wsize,
- keymat, e_type, e_keylen, a_type, a_keylen, flags,
- l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_ADD message to the kernel.
- * The length of key material is a_keylen + e_keylen.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize,
- keymat, e_type, e_keylen, a_type, a_keylen, flags,
- l_alloc, l_bytes, l_addtime, l_usetime, seq)
-int so;
-u_int satype, mode, wsize;
-struct sockaddr *src, *dst;
-u_int32_t spi, reqid;
-caddr_t keymat;
-u_int e_type, e_keylen, a_type, a_keylen, flags;
-u_int32_t l_alloc;
-u_int64_t l_bytes, l_addtime, l_usetime;
-u_int32_t seq;
-{
- int len;
- if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi,
- reqid, wsize,
- keymat, e_type, e_keylen, a_type, a_keylen, flags,
- l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_DELETE message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_delete(so, satype, mode, src, dst, spi)
-int so;
-u_int satype, mode;
-struct sockaddr *src, *dst;
-u_int32_t spi;
-{
- int len;
- if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_DELETE without spi to the kernel. This is
- * the "delete all" request (an extension also present in
- * Solaris).
- *
- * OUT:
- * positive: success and return length sent
- * -1 : error occured, and set errno
- */
-int
-pfkey_send_delete_all(so, satype, mode, src, dst)
-int so;
-u_int satype, mode;
-struct sockaddr *src, *dst;
-{
- struct sadb_msg *newmsg;
- int len;
- caddr_t p;
- int plen;
- caddr_t ep;
-
- (void)mode;
-
- /* validity check */
- if (src == NULL || dst == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
- if (src->sa_family != dst->sa_family) {
- __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
- return -1;
- }
- switch (src->sa_family) {
- case AF_INET:
- plen = sizeof(struct in_addr) << 3;
- break;
- case AF_INET6:
- plen = sizeof(struct in6_addr) << 3;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_FAMILY;
- return -1;
- }
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(src->sa_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(dst->sa_len);
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0,
- getpid());
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
- IPSEC_ULPROTO_ANY);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
- IPSEC_ULPROTO_ANY);
- if (!p || p != ep) {
- free(newmsg);
- return -1;
- }
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/*
- * sending SADB_GET message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_get(so, satype, mode, src, dst, spi)
-int so;
-u_int satype, mode;
-struct sockaddr *src, *dst;
-u_int32_t spi;
-{
- int len;
- if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_REGISTER message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_register(so, satype)
-int so;
-u_int satype;
-{
- int len, algno;
-
- if (satype == PF_UNSPEC) {
- for (algno = 0;
- (unsigned int)algno < sizeof(supported_map)/sizeof(supported_map[0]);
- algno++) {
- if (ipsec_supported[algno]) {
- free(ipsec_supported[algno]);
- ipsec_supported[algno] = NULL;
- }
- }
- } else {
- algno = findsupportedmap(satype);
- if (algno == -1) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- if (ipsec_supported[algno]) {
- free(ipsec_supported[algno]);
- ipsec_supported[algno] = NULL;
- }
- }
-
- if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * receiving SADB_REGISTER message from the kernel, and copy buffer for
- * sadb_supported returned into ipsec_supported.
- * OUT:
- * 0: success and return length sent.
- * -1: error occured, and set errno.
- */
-int
-pfkey_recv_register(so)
-int so;
-{
- pid_t pid = getpid();
- struct sadb_msg *newmsg;
- int error = -1;
-
- /* receive message */
- do {
- if ((newmsg = pfkey_recv(so)) == NULL)
- return -1;
- } while (newmsg->sadb_msg_type != SADB_REGISTER
- || (pid_t)newmsg->sadb_msg_pid != pid);
-
- /* check and fix */
- newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
-
- error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
- free(newmsg);
-
- if (error == 0)
- __ipsec_errcode = EIPSEC_NO_ERROR;
-
- return error;
-}
-
-/*
- * receiving SADB_REGISTER message from the kernel, and copy buffer for
- * sadb_supported returned into ipsec_supported.
- * NOTE: sadb_msg_len must be host order.
- * IN:
- * tlen: msg length, it's to makeing sure.
- * OUT:
- * 0: success and return length sent.
- * -1: error occured, and set errno.
- */
-int
-pfkey_set_supported(msg, tlen)
-struct sadb_msg *msg;
-int tlen;
-{
- struct sadb_supported *sup;
- caddr_t p;
- caddr_t ep;
-
- /* validity */
- if (msg->sadb_msg_len != tlen) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- p = (caddr_t)msg;
- ep = p + tlen;
-
- p += sizeof(struct sadb_msg);
-
- while (p < ep) {
- sup = (struct sadb_supported *)p;
- if (ep < p + sizeof(*sup) ||
- (size_t)PFKEY_EXTLEN(sup) < sizeof(*sup) ||
- ep < p + sup->sadb_supported_len) {
- /* invalid format */
- break;
- }
-
- switch (sup->sadb_supported_exttype) {
- case SADB_EXT_SUPPORTED_AUTH:
- case SADB_EXT_SUPPORTED_ENCRYPT:
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
-
- /* fixed length */
- sup->sadb_supported_len = PFKEY_EXTLEN(sup);
-
- /* set supported map */
- if (setsupportedmap(sup) != 0)
- return -1;
-
- p += sup->sadb_supported_len;
- }
-
- if (p != ep) {
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
-
- return 0;
-}
-
-/*
- * sending SADB_FLUSH message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_flush(so, satype)
-int so;
-u_int satype;
-{
- int len;
-
- if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_DUMP message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_dump(so, satype)
-int so;
-u_int satype;
-{
- int len;
-
- if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_PROMISC message to the kernel.
- * NOTE that this function handles promisc mode toggle only.
- * IN:
- * flag: set promisc off if zero, set promisc on if non-zero.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- * 0 : error occured, and set errno.
- * others: a pointer to new allocated buffer in which supported
- * algorithms is.
- */
-int
-pfkey_send_promisc_toggle(so, flag)
-int so;
-int flag;
-{
- int len;
-
- if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDADD message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int prefs, prefd, proto;
-caddr_t policy;
-int policylen;
-u_int32_t seq;
-{
- int len;
-
- if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
- src, prefs, dst, prefd, proto,
- 0, 0,
- policy, policylen, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDADD message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime,
- policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int prefs, prefd, proto;
-u_int64_t ltime, vtime;
-caddr_t policy;
-int policylen;
-u_int32_t seq;
-{
- int len;
-
- if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
- src, prefs, dst, prefd, proto,
- ltime, vtime,
- policy, policylen, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDUPDATE message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int prefs, prefd, proto;
-caddr_t policy;
-int policylen;
-u_int32_t seq;
-{
- int len;
-
- if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
- src, prefs, dst, prefd, proto,
- 0, 0,
- policy, policylen, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDUPDATE message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime,
- policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int prefs, prefd, proto;
-u_int64_t ltime, vtime;
-caddr_t policy;
-int policylen;
-u_int32_t seq;
-{
- int len;
-
- if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
- src, prefs, dst, prefd, proto,
- ltime, vtime,
- policy, policylen, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDDELETE message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int prefs, prefd, proto;
-caddr_t policy;
-int policylen;
-u_int32_t seq;
-{
- int len;
-
- if (policylen != sizeof(struct sadb_x_policy)) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
- src, prefs, dst, prefd, proto,
- 0, 0,
- policy, policylen, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDDELETE message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spddelete2(so, spid)
-int so;
-u_int32_t spid;
-{
- int len;
-
- if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDGET message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdget(so, spid)
-int so;
-u_int32_t spid;
-{
- int len;
-
- if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_X_SPDSETIDX message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int prefs, prefd, proto;
-caddr_t policy;
-int policylen;
-u_int32_t seq;
-{
- int len;
-
- if (policylen != sizeof(struct sadb_x_policy)) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
- src, prefs, dst, prefd, proto,
- 0, 0,
- policy, policylen, seq)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_SPDFLUSH message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spdflush(so)
-int so;
-{
- int len;
-
- if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
- return -1;
-
- return len;
-}
-
-/*
- * sending SADB_SPDDUMP message to the kernel.
- * OUT:
- * positive: success and return length sent.
- * -1 : error occured, and set errno.
- */
-int
-pfkey_send_spddump(so)
-int so;
-{
- int len;
-
- if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
- return -1;
-
- return len;
-}
-
-/* sending SADB_ADD or SADB_UPDATE message to the kernel */
-static int
-pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize,
- keymat, e_type, e_keylen, a_type, a_keylen, flags,
- l_alloc, l_bytes, l_addtime, l_usetime, seq)
-int so;
-u_int type, satype, mode;
-struct sockaddr *src, *dst;
-u_int32_t spi, reqid;
-u_int wsize;
-caddr_t keymat;
-u_int e_type, e_keylen, a_type, a_keylen, flags;
-u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq;
-{
- struct sadb_msg *newmsg;
- int len;
- caddr_t p;
- int plen;
- caddr_t ep;
-
- /* validity check */
- if (src == NULL || dst == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
- if (src->sa_family != dst->sa_family) {
- __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
- return -1;
- }
- switch (src->sa_family) {
- case AF_INET:
- plen = sizeof(struct in_addr) << 3;
- break;
- case AF_INET6:
- plen = sizeof(struct in6_addr) << 3;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_FAMILY;
- return -1;
- }
-
- switch (satype) {
- case SADB_SATYPE_ESP:
- if (e_type == SADB_EALG_NONE) {
- __ipsec_errcode = EIPSEC_NO_ALGS;
- return -1;
- }
- break;
- case SADB_SATYPE_AH:
- if (e_type != SADB_EALG_NONE) {
- __ipsec_errcode = EIPSEC_INVAL_ALGS;
- return -1;
- }
- if (a_type == SADB_AALG_NONE) {
- __ipsec_errcode = EIPSEC_NO_ALGS;
- return -1;
- }
- break;
- case SADB_X_SATYPE_IPCOMP:
- if (e_type == SADB_X_CALG_NONE) {
- __ipsec_errcode = EIPSEC_INVAL_ALGS;
- return -1;
- }
- if (a_type != SADB_AALG_NONE) {
- __ipsec_errcode = EIPSEC_NO_ALGS;
- return -1;
- }
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_sa)
- + sizeof(struct sadb_x_sa2)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(src->sa_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(dst->sa_len)
- + sizeof(struct sadb_lifetime)
- + sizeof(struct sadb_lifetime);
-
- if (e_type != SADB_EALG_NONE)
- len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen));
- if (a_type != SADB_AALG_NONE)
- len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen));
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
- satype, seq, getpid());
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbxsa2(p, ep, mode, reqid);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
- IPSEC_ULPROTO_ANY);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
- IPSEC_ULPROTO_ANY);
- if (!p) {
- free(newmsg);
- return -1;
- }
-
- if (e_type != SADB_EALG_NONE) {
- p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
- keymat, e_keylen);
- if (!p) {
- free(newmsg);
- return -1;
- }
- }
- if (a_type != SADB_AALG_NONE) {
- p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
- keymat + e_keylen, a_keylen);
- if (!p) {
- free(newmsg);
- return -1;
- }
- }
-
- /* set sadb_lifetime for destination */
- p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
- l_alloc, l_bytes, l_addtime, l_usetime);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
- l_alloc, l_bytes, l_addtime, l_usetime);
- if (!p || p != ep) {
- free(newmsg);
- return -1;
- }
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/* sending SADB_DELETE or SADB_GET message to the kernel */
-static int
-pfkey_send_x2(so, type, satype, mode, src, dst, spi)
-int so;
-u_int type, satype, mode;
-struct sockaddr *src, *dst;
-u_int32_t spi;
-{
- struct sadb_msg *newmsg;
- int len;
- caddr_t p;
- int plen;
- caddr_t ep;
-
- (void)mode;
-
- /* validity check */
- if (src == NULL || dst == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
- if (src->sa_family != dst->sa_family) {
- __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
- return -1;
- }
- switch (src->sa_family) {
- case AF_INET:
- plen = sizeof(struct in_addr) << 3;
- break;
- case AF_INET6:
- plen = sizeof(struct in6_addr) << 3;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_FAMILY;
- return -1;
- }
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_sa)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(src->sa_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(dst->sa_len);
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
- getpid());
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen,
- IPSEC_ULPROTO_ANY);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen,
- IPSEC_ULPROTO_ANY);
- if (!p || p != ep) {
- free(newmsg);
- return -1;
- }
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/*
- * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
- * to the kernel
- */
-static int
-pfkey_send_x3(so, type, satype)
-int so;
-u_int type, satype;
-{
- struct sadb_msg *newmsg;
- int len;
- caddr_t p;
- caddr_t ep;
-
- /* validity check */
- switch (type) {
- case SADB_X_PROMISC:
- if (satype != 0 && satype != 1) {
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
- break;
- default:
- switch (satype) {
- case SADB_SATYPE_UNSPEC:
- case SADB_SATYPE_AH:
- case SADB_SATYPE_ESP:
- case SADB_X_SATYPE_IPCOMP:
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
- }
-
- /* create new sadb_msg to send. */
- len = sizeof(struct sadb_msg);
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0,
- getpid());
- if (!p || p != ep) {
- free(newmsg);
- return -1;
- }
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/* sending SADB_X_SPDADD message to the kernel */
-static int
-pfkey_send_x4(so, type, src, prefs, dst, prefd, proto,
- ltime, vtime, policy, policylen, seq)
-int so;
-struct sockaddr *src, *dst;
-u_int type, prefs, prefd, proto;
-u_int64_t ltime, vtime;
-char *policy;
-int policylen;
-u_int32_t seq;
-{
- struct sadb_msg *newmsg;
- int len;
- caddr_t p;
- int plen;
- caddr_t ep;
-
- /* validity check */
- if (src == NULL || dst == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
- if (src->sa_family != dst->sa_family) {
- __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
- return -1;
- }
-
- switch (src->sa_family) {
- case AF_INET:
- plen = sizeof(struct in_addr) << 3;
- break;
- case AF_INET6:
- plen = sizeof(struct in6_addr) << 3;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_FAMILY;
- return -1;
- }
- if (prefs > (u_int)plen || prefd > (u_int)plen) {
- __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
- return -1;
- }
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(src->sa_len)
- + sizeof(struct sadb_address)
- + PFKEY_ALIGN8(src->sa_len)
- + sizeof(struct sadb_lifetime)
- + policylen;
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
- SADB_SATYPE_UNSPEC, seq, getpid());
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
- if (!p) {
- free(newmsg);
- return -1;
- }
- p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
- 0, 0, ltime, vtime);
- if (!p || p + policylen != ep) {
- free(newmsg);
- return -1;
- }
- memcpy(p, policy, policylen);
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
-static int
-pfkey_send_x5(so, type, spid)
-int so;
-u_int type;
-u_int32_t spid;
-{
- struct sadb_msg *newmsg;
- struct sadb_x_policy xpl;
- int len;
- caddr_t p;
- caddr_t ep;
-
- /* create new sadb_msg to reply. */
- len = sizeof(struct sadb_msg)
- + sizeof(xpl);
-
- if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
- ep = ((caddr_t)newmsg) + len;
-
- p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len,
- SADB_SATYPE_UNSPEC, 0, getpid());
- if (!p) {
- free(newmsg);
- return -1;
- }
-
- if (p + sizeof(xpl) != ep) {
- free(newmsg);
- return -1;
- }
- memset(&xpl, 0, sizeof(xpl));
- xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl));
- xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
- xpl.sadb_x_policy_id = spid;
- memcpy(p, &xpl, sizeof(xpl));
-
- /* send message */
- len = pfkey_send(so, newmsg, len);
- free(newmsg);
-
- if (len < 0)
- return -1;
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/*
- * open a socket.
- * OUT:
- * -1: fail.
- * others : success and return value of socket.
- */
-int
-pfkey_open()
-{
- int so;
- const int bufsiz = 128 * 1024; /*is 128K enough?*/
-
- if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
-
- /*
- * This is a temporary workaround for KAME PR 154.
- * Don't really care even if it fails.
- */
- (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz));
- (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz));
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return so;
-}
-
-/*
- * close a socket.
- * OUT:
- * 0: success.
- * -1: fail.
- */
-void
-pfkey_close(so)
-int so;
-{
- (void)close(so);
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return;
-}
-
-/*
- * receive sadb_msg data, and return pointer to new buffer allocated.
- * Must free this buffer later.
- * OUT:
- * NULL : error occured.
- * others : a pointer to sadb_msg structure.
- *
- * XXX should be rewritten to pass length explicitly
- */
-struct sadb_msg *
-pfkey_recv(so)
-int so;
-{
- struct sadb_msg buf, *newmsg;
- int len, reallen;
-
- while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) {
- if (errno == EINTR)
- continue;
- __ipsec_set_strerror(strerror(errno));
- return NULL;
- }
-
- if ((size_t)len < sizeof(buf)) {
- recv(so, (caddr_t)&buf, sizeof(buf), 0);
- __ipsec_errcode = EIPSEC_MAX;
- return NULL;
- }
-
- /* read real message */
- reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
- if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) {
- __ipsec_set_strerror(strerror(errno));
- return NULL;
- }
-
- while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) {
- if (errno == EINTR)
- continue;
- __ipsec_set_strerror(strerror(errno));
- free(newmsg);
- return NULL;
- }
-
- if (len != reallen) {
- __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
- free(newmsg);
- return NULL;
- }
-
- /* don't trust what the kernel says, validate! */
- if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
- __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
- free(newmsg);
- return NULL;
- }
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return newmsg;
-}
-
-/*
- * send message to a socket.
- * OUT:
- * others: success and return length sent.
- * -1 : fail.
- */
-int
-pfkey_send(so, msg, len)
-int so;
-struct sadb_msg *msg;
-int len;
-{
- if ((len = send(so, (caddr_t)msg, len, 0)) < 0) {
- __ipsec_set_strerror(strerror(errno));
- return -1;
- }
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return len;
-}
-
-/*
- * %%% Utilities
- * NOTE: These functions are derived from netkey/key.c in KAME.
- */
-/*
- * set the pointer to each header in this message buffer.
- * IN: msg: pointer to message buffer.
- * mhp: pointer to the buffer initialized like below:
- * caddr_t mhp[SADB_EXT_MAX + 1];
- * OUT: -1: invalid.
- * 0: valid.
- *
- * XXX should be rewritten to obtain length explicitly
- */
-int
-pfkey_align(msg, mhp)
-struct sadb_msg *msg;
-caddr_t *mhp;
-{
- struct sadb_ext *ext;
- int i;
- caddr_t p;
- caddr_t ep; /* XXX should be passed from upper layer */
-
- /* validity check */
- if (msg == NULL || mhp == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- /* initialize */
- for (i = 0; i < SADB_EXT_MAX + 1; i++)
- mhp[i] = NULL;
-
- mhp[0] = (caddr_t)msg;
-
- /* initialize */
- p = (caddr_t) msg;
- ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
-
- /* skip base header */
- p += sizeof(struct sadb_msg);
-
- while (p < ep) {
- ext = (struct sadb_ext *)p;
- if (ep < p + sizeof(*ext) || (size_t)PFKEY_EXTLEN(ext) < sizeof(*ext) ||
- ep < p + PFKEY_EXTLEN(ext)) {
- /* invalid format */
- break;
- }
-
- /* duplicate check */
- /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
- if (mhp[ext->sadb_ext_type] != NULL) {
- __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
- return -1;
- }
-
- /* set pointer */
- switch (ext->sadb_ext_type) {
- case SADB_EXT_SA:
- case SADB_EXT_LIFETIME_CURRENT:
- case SADB_EXT_LIFETIME_HARD:
- case SADB_EXT_LIFETIME_SOFT:
- case SADB_EXT_ADDRESS_SRC:
- case SADB_EXT_ADDRESS_DST:
- case SADB_EXT_ADDRESS_PROXY:
- case SADB_EXT_KEY_AUTH:
- /* XXX should to be check weak keys. */
- case SADB_EXT_KEY_ENCRYPT:
- /* XXX should to be check weak keys. */
- case SADB_EXT_IDENTITY_SRC:
- case SADB_EXT_IDENTITY_DST:
- case SADB_EXT_SENSITIVITY:
- case SADB_EXT_PROPOSAL:
- case SADB_EXT_SUPPORTED_AUTH:
- case SADB_EXT_SUPPORTED_ENCRYPT:
- case SADB_EXT_SPIRANGE:
- case SADB_X_EXT_POLICY:
- case SADB_X_EXT_SA2:
- mhp[ext->sadb_ext_type] = (caddr_t)ext;
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
- return -1;
- }
-
- p += PFKEY_EXTLEN(ext);
- }
-
- if (p != ep) {
- __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
- return -1;
- }
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return 0;
-}
-
-/*
- * check basic usage for sadb_msg,
- * NOTE: This routine is derived from netkey/key.c in KAME.
- * IN: msg: pointer to message buffer.
- * mhp: pointer to the buffer initialized like below:
- *
- * caddr_t mhp[SADB_EXT_MAX + 1];
- *
- * OUT: -1: invalid.
- * 0: valid.
- */
-int
-pfkey_check(mhp)
-caddr_t *mhp;
-{
- struct sadb_msg *msg;
-
- /* validity check */
- if (mhp == NULL || mhp[0] == NULL) {
- __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
- return -1;
- }
-
- msg = (struct sadb_msg *)mhp[0];
-
- /* check version */
- if (msg->sadb_msg_version != PF_KEY_V2) {
- __ipsec_errcode = EIPSEC_INVAL_VERSION;
- return -1;
- }
-
- /* check type */
- if (msg->sadb_msg_type > SADB_MAX) {
- __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
- return -1;
- }
-
- /* check SA type */
- switch (msg->sadb_msg_satype) {
- case SADB_SATYPE_UNSPEC:
- switch (msg->sadb_msg_type) {
- case SADB_GETSPI:
- case SADB_UPDATE:
- case SADB_ADD:
- case SADB_DELETE:
- case SADB_GET:
- case SADB_ACQUIRE:
- case SADB_EXPIRE:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
- break;
- case SADB_SATYPE_ESP:
- case SADB_SATYPE_AH:
- case SADB_X_SATYPE_IPCOMP:
- switch (msg->sadb_msg_type) {
- case SADB_X_SPDADD:
- case SADB_X_SPDDELETE:
- case SADB_X_SPDGET:
- case SADB_X_SPDDUMP:
- case SADB_X_SPDFLUSH:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
- break;
- case SADB_SATYPE_RSVP:
- case SADB_SATYPE_OSPFV2:
- case SADB_SATYPE_RIPV2:
- case SADB_SATYPE_MIP:
- __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
- return -1;
- case 1: /* XXX: What does it do ? */
- if (msg->sadb_msg_type == SADB_X_PROMISC)
- break;
- /*FALLTHROUGH*/
- default:
- __ipsec_errcode = EIPSEC_INVAL_SATYPE;
- return -1;
- }
-
- /* check field of upper layer protocol and address family */
- if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
- && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
- struct sadb_address *src0, *dst0;
-
- src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]);
- dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]);
-
- if (src0->sadb_address_proto != dst0->sadb_address_proto) {
- __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
- return -1;
- }
-
- if (PFKEY_ADDR_SADDR(src0)->sa_family
- != PFKEY_ADDR_SADDR(dst0)->sa_family) {
- __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
- return -1;
- }
-
- switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
- case AF_INET:
- case AF_INET6:
- break;
- default:
- __ipsec_errcode = EIPSEC_INVAL_FAMILY;
- return -1;
- }
-
- /*
- * prefixlen == 0 is valid because there must be the case
- * all addresses are matched.
- */
- }
-
- __ipsec_errcode = EIPSEC_NO_ERROR;
- return 0;
-}
-
-/*
- * set data into sadb_msg.
- * `buf' must has been allocated sufficiently.
- */
-static caddr_t
-pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid)
-caddr_t buf;
-caddr_t lim;
-u_int type, satype;
-u_int tlen;
-u_int32_t seq;
-pid_t pid;
-{
- struct sadb_msg *p;
- u_int len;
-
- p = (struct sadb_msg *)buf;
- len = sizeof(struct sadb_msg);
-
- if (buf + len > lim)
- return NULL;
-
- memset(p, 0, len);
- p->sadb_msg_version = PF_KEY_V2;
- p->sadb_msg_type = type;
- p->sadb_msg_errno = 0;
- p->sadb_msg_satype = satype;
- p->sadb_msg_len = PFKEY_UNIT64(tlen);
- p->sadb_msg_reserved = 0;
- p->sadb_msg_seq = seq;
- p->sadb_msg_pid = (u_int32_t)pid;
-
- return(buf + len);
-}
-
-/*
- * copy secasvar data into sadb_address.
- * `buf' must has been allocated sufficiently.
- */
-static caddr_t
-pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags)
-caddr_t buf;
-caddr_t lim;
-u_int32_t spi, flags;
-u_int wsize, auth, enc;
-{
- struct sadb_sa *p;
- u_int len;
-
- p = (struct sadb_sa *)buf;
- len = sizeof(struct sadb_sa);
-
- if (buf + len > lim)
- return NULL;
-
- memset(p, 0, len);
- p->sadb_sa_len = PFKEY_UNIT64(len);
- p->sadb_sa_exttype = SADB_EXT_SA;
- p->sadb_sa_spi = spi;
- p->sadb_sa_replay = wsize;
- p->sadb_sa_state = SADB_SASTATE_LARVAL;
- p->sadb_sa_auth = auth;
- p->sadb_sa_encrypt = enc;
- p->sadb_sa_flags = flags;
-
- return(buf + len);
-}
-
-/*
- * set data into sadb_address.
- * `buf' must has been allocated sufficiently.
- * prefixlen is in bits.
- */
-static caddr_t
-pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto)
-caddr_t buf;
-caddr_t lim;
-u_int exttype;
-struct sockaddr *saddr;
-u_int prefixlen;
-u_int ul_proto;
-{
- struct sadb_address *p;
- u_int len;
-
- p = (struct sadb_address *)buf;
- len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len);
-
- if (buf + len > lim)
- return NULL;
-
- memset(p, 0, len);
- p->sadb_address_len = PFKEY_UNIT64(len);
- p->sadb_address_exttype = exttype & 0xffff;
- p->sadb_address_proto = ul_proto & 0xff;
- p->sadb_address_prefixlen = prefixlen;
- p->sadb_address_reserved = 0;
-
- memcpy(p + 1, saddr, saddr->sa_len);
-
- return(buf + len);
-}
-
-/*
- * set sadb_key structure after clearing buffer with zero.
- * OUT: the pointer of buf + len.
- */
-static caddr_t
-pfkey_setsadbkey(buf, lim, type, key, keylen)
-caddr_t buf;
-caddr_t lim;
-caddr_t key;
-u_int type, keylen;
-{
- struct sadb_key *p;
- u_int len;
-
- p = (struct sadb_key *)buf;
- len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
-
- if (buf + len > lim)
- return NULL;
-
- memset(p, 0, len);
- p->sadb_key_len = PFKEY_UNIT64(len);
- p->sadb_key_exttype = type;
- p->sadb_key_bits = keylen << 3;
- p->sadb_key_reserved = 0;
-
- memcpy(p + 1, key, keylen);
-
- return buf + len;
-}
-
-/*
- * set sadb_lifetime structure after clearing buffer with zero.
- * OUT: the pointer of buf + len.
- */
-static caddr_t
-pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime)
-caddr_t buf;
-caddr_t lim;
-u_int type;
-u_int32_t l_alloc, l_bytes, l_addtime, l_usetime;
-{
- struct sadb_lifetime *p;
- u_int len;
-
- p = (struct sadb_lifetime *)buf;
- len = sizeof(struct sadb_lifetime);
-
- if (buf + len > lim)
- return NULL;
-
- memset(p, 0, len);
- p->sadb_lifetime_len = PFKEY_UNIT64(len);
- p->sadb_lifetime_exttype = type;
-
- switch (type) {
- case SADB_EXT_LIFETIME_SOFT:
- p->sadb_lifetime_allocations
- = (l_alloc * soft_lifetime_allocations_rate) /100;
- p->sadb_lifetime_bytes
- = (l_bytes * soft_lifetime_bytes_rate) /100;
- p->sadb_lifetime_addtime
- = (l_addtime * soft_lifetime_addtime_rate) /100;
- p->sadb_lifetime_usetime
- = (l_usetime * soft_lifetime_usetime_rate) /100;
- break;
- case SADB_EXT_LIFETIME_HARD:
- p->sadb_lifetime_allocations = l_alloc;
- p->sadb_lifetime_bytes = l_bytes;
- p->sadb_lifetime_addtime = l_addtime;
- p->sadb_lifetime_usetime = l_usetime;
- break;
- }
-
- return buf + len;
-}
-
-/*
- * copy secasvar data into sadb_address.
- * `buf' must has been allocated sufficiently.
- */
-static caddr_t
-pfkey_setsadbxsa2(buf, lim, mode0, reqid)
-caddr_t buf;
-caddr_t lim;
-u_int32_t mode0;
-u_int32_t reqid;
-{
- struct sadb_x_sa2 *p;
- u_int8_t mode = mode0 & 0xff;
- u_int len;
-
- p = (struct sadb_x_sa2 *)buf;
- len = sizeof(struct sadb_x_sa2);
-
- if (buf + len > lim)
- return NULL;
-
- memset(p, 0, len);
- p->sadb_x_sa2_len = PFKEY_UNIT64(len);
- p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
- p->sadb_x_sa2_mode = mode;
- p->sadb_x_sa2_reqid = reqid;
-
- return(buf + len);
-}
-
-#endif /* ndef MDNS_NO_IPSEC */
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2013-2018 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.
#include <nw/private.h>
#else
#include <network/private.h>
+ #define nw_release(X) network_release(X)
#endif
#include "dns_sd_internal.h"
//Gets the DNSPolicy from NW PATH EVALUATOR
mDNSexport void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q, mDNSBool *isBlocked)
{
- q->ServiceID = -1; // initialize the ServiceID to default value of -1
-
- // Return for non-unicast DNS queries, invalid pid, if NWPathEvaluation is already done by the client, or NWPathEvaluation not available on this OS
- if (mDNSOpaque16IsZero(q->TargetQID) || (q->pid < 0) || (q->flags & kDNSServiceFlagsPathEvaluationDone) || !nw_endpoint_create_host)
- {
- *isBlocked = mDNSfalse;
- return;
- }
-
- mDNSs32 service_id;
- mDNSu32 client_ifindex, dnspol_ifindex;
- int retval;
- struct proc_uniqidentifierinfo info;
- mDNSBool isUUIDSet;
-
- char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
- ConvertDomainNameToCString(&q->qname, unenc_name);
-
- nw_endpoint_t host = nw_endpoint_create_host(unenc_name, "0");
- if (host == NULL)
- LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t host is NULL", q->qname.c,
- DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-
- nw_parameters_t parameters = nw_parameters_create();
- if (parameters == NULL)
- LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t parameters is NULL", q->qname.c,
- DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-
- // Check for all the special (negative) internal value interface indices before initializing client_ifindex
- if ( (q->InterfaceID == mDNSInterface_Any)
- || (q->InterfaceID == mDNSInterface_Unicast)
- || (q->InterfaceID == mDNSInterface_LocalOnly)
- || (q->InterfaceID == mDNSInterfaceMark)
- || (q->InterfaceID == mDNSInterface_P2P)
- || (q->InterfaceID == mDNSInterface_BLE)
- || (q->InterfaceID == uDNSInterfaceMark))
- {
- client_ifindex = 0;
- }
- else
+ if (__builtin_available(macOS 10.14, *))
{
- client_ifindex = (mDNSu32)(uintptr_t)q->InterfaceID;
- }
+ q->ServiceID = -1; // initialize the ServiceID to default value of -1
-
- if (client_ifindex > 0)
- {
- nw_interface_t client_intf = nw_interface_create_with_index(client_ifindex);
- nw_parameters_require_interface(parameters, client_intf);
- if (client_intf != NULL)
- network_release(client_intf);
+ // Return for non-unicast DNS queries, invalid pid, if NWPathEvaluation is already done by the client, or NWPathEvaluation not available on this OS
+ if (mDNSOpaque16IsZero(q->TargetQID) || (q->pid < 0) || (q->flags & kDNSServiceFlagsPathEvaluationDone) || !nw_endpoint_create_host)
+ {
+ *isBlocked = mDNSfalse;
+ return;
+ }
+
+ mDNSs32 service_id;
+ mDNSu32 client_ifindex, dnspol_ifindex;
+ int retval;
+ struct proc_uniqidentifierinfo info;
+ mDNSBool isUUIDSet;
+
+ char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
+ ConvertDomainNameToCString(&q->qname, unenc_name);
+
+ nw_endpoint_t host = nw_endpoint_create_host(unenc_name, "0");
+ if (host == NULL)
+ LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t host is NULL", q->qname.c,
+ DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+
+ nw_parameters_t parameters = nw_parameters_create();
+ if (parameters == NULL)
+ LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t parameters is NULL", q->qname.c,
+ DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+
+#if TARGET_OS_WATCH
+ // Companion interface on watchOS does not support DNS, so we don't want path evalution to return it to us.
+ nw_parameters_set_companion_preference(parameters, nw_parameters_agent_preference_avoid);
+#endif // TARGET_OS_WATCH
+
+ // Check for all the special (negative) internal value interface indices before initializing client_ifindex
+ if ( (q->InterfaceID == mDNSInterface_Any)
+ || (q->InterfaceID == mDNSInterface_LocalOnly)
+ || (q->InterfaceID == mDNSInterfaceMark)
+ || (q->InterfaceID == mDNSInterface_P2P)
+ || (q->InterfaceID == mDNSInterface_BLE)
+ || (q->InterfaceID == uDNSInterfaceMark))
+ {
+ client_ifindex = 0;
+ }
else
- LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: client_intf returned by nw_interface_create_with_index() is NULL");
- }
-
- nw_parameters_set_uid(parameters,(uid_t)q->euid);
+ {
+ client_ifindex = (mDNSu32)(uintptr_t)q->InterfaceID;
+ }
- if (q->pid != 0)
- {
- nw_parameters_set_pid(parameters, q->pid);
- retval = proc_pidinfo(q->pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
- if (retval == (int)sizeof(info))
+ if (client_ifindex > 0)
{
- nw_parameters_set_e_proc_uuid(parameters, info.p_uuid);
- isUUIDSet = mDNStrue;
+ nw_interface_t client_intf = nw_interface_create_with_index(client_ifindex);
+ nw_parameters_require_interface(parameters, client_intf);
+ if (client_intf != NULL)
+ nw_release(client_intf);
+ else
+ LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: client_intf returned by nw_interface_create_with_index() is NULL");
+ }
+
+ nw_parameters_set_uid(parameters,(uid_t)q->euid);
+
+ if (q->pid != 0)
+ {
+ nw_parameters_set_pid(parameters, q->pid);
+ retval = proc_pidinfo(q->pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
+ if (retval == (int)sizeof(info))
+ {
+ nw_parameters_set_e_proc_uuid(parameters, info.p_uuid);
+ isUUIDSet = mDNStrue;
+ }
+ else
+ {
+ debugf("mDNSPlatformGetDNSRoutePolicy: proc_pidinfo returned %d", retval);
+ isUUIDSet = mDNSfalse;
+ }
}
else
{
- debugf("mDNSPlatformGetDNSRoutePolicy: proc_pidinfo returned %d", retval);
- isUUIDSet = mDNSfalse;
+ nw_parameters_set_e_proc_uuid(parameters, q->uuid);
+ isUUIDSet = mDNStrue;
}
- }
- else
- {
- nw_parameters_set_e_proc_uuid(parameters, q->uuid);
- isUUIDSet = mDNStrue;
- }
-
- nw_path_evaluator_t evaluator = nw_path_create_evaluator_for_endpoint(host, parameters);
- if (evaluator == NULL)
- LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_evaluator_t evaluator is NULL", q->qname.c,
- DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-
- if (host != NULL)
- network_release(host);
- if (parameters != NULL)
- network_release(parameters);
-
- nw_path_t path = nw_path_evaluator_copy_path(evaluator);
- if (path == NULL)
- LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_t path is NULL", q->qname.c,
- DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-
- service_id = nw_path_get_flow_divert_unit(path);
- if (service_id != 0)
- {
- q->ServiceID = service_id;
- LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s service ID is set ->service_ID:[%d] ", q->qname.c, service_id);
- }
- else
- {
- nw_interface_t nwpath_intf = nw_path_copy_scoped_interface(path);
- if (nwpath_intf != NULL)
+
+ nw_path_evaluator_t evaluator = nw_path_create_evaluator_for_endpoint(host, parameters);
+ if (evaluator == NULL)
+ LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_evaluator_t evaluator is NULL", q->qname.c,
+ DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+
+ if (host != NULL)
+ nw_release(host);
+ if (parameters != NULL)
+ nw_release(parameters);
+
+ nw_path_t path = nw_path_evaluator_copy_path(evaluator);
+ if (path == NULL)
+ LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_t path is NULL", q->qname.c,
+ DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+
+ service_id = nw_path_get_flow_divert_unit(path);
+ if (service_id != 0)
{
- // Use the new scoped interface given by NW PATH EVALUATOR
- dnspol_ifindex = nw_interface_get_index(nwpath_intf);
- q->InterfaceID = (mDNSInterfaceID)(uintptr_t)dnspol_ifindex;
-
- network_release(nwpath_intf);
-
- if (dnspol_ifindex != client_ifindex)
- LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy has changed the scoped ifindex from [%d] to [%d]",
- client_ifindex, dnspol_ifindex);
+ q->ServiceID = service_id;
+ LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s service ID is set ->service_ID:[%d] ", q->qname.c, service_id);
}
else
{
- debugf("mDNSPlatformGetDNSRoutePolicy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_interface_t nwpath_intf is NULL ", q->qname.c, DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+ nw_interface_t nwpath_intf = nw_path_copy_scoped_interface(path);
+ if (nwpath_intf != NULL)
+ {
+ // Use the new scoped interface given by NW PATH EVALUATOR
+ dnspol_ifindex = nw_interface_get_index(nwpath_intf);
+ q->InterfaceID = (mDNSInterfaceID)(uintptr_t)dnspol_ifindex;
+
+ nw_release(nwpath_intf);
+
+ if (dnspol_ifindex != client_ifindex)
+ LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy has changed the scoped ifindex from [%d] to [%d]",
+ client_ifindex, dnspol_ifindex);
+ }
+ else
+ {
+ debugf("mDNSPlatformGetDNSRoutePolicy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_interface_t nwpath_intf is NULL ", q->qname.c, DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+ }
}
+
+ if (isUUIDSet && path && (nw_path_get_status(path) == nw_path_status_unsatisfied) && (nw_path_get_reason(path) == nw_path_reason_policy_drop))
+ *isBlocked = mDNStrue;
+ else
+ *isBlocked = mDNSfalse;
+
+ if (path != NULL)
+ nw_release(path);
+ if (evaluator != NULL)
+ nw_release(evaluator);
}
-
- if (isUUIDSet && (nw_path_get_status(path) == nw_path_status_unsatisfied) && (nw_path_get_reason(path) == nw_path_reason_policy_drop))
- *isBlocked = mDNStrue;
else
+ {
*isBlocked = mDNSfalse;
-
- if (path != NULL)
- network_release(path);
- if (evaluator != NULL)
- network_release(evaluator);
-
+ }
}
--- /dev/null
+//
+// system_utilities.c
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#include <os/variant_private.h> // os_variant_has_internal_diagnostics
+#include "mDNSEmbeddedAPI.h"
+#include "system_utilities.h"
+
+mDNSexport mDNSBool IsAppleInternalBuild(void)
+{
+ return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
+}
--- /dev/null
+//
+// system_utilities.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef SYSTEM_UTILITIES_H
+#define SYSTEM_UTILITIES_H
+
+mDNSexport mDNSBool IsAppleInternalBuild(void);
+
+#endif /* SYSTEM_UTILITIES_H */
--- /dev/null
+//
+// xpc_client_dns_proxy.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_CLIENT_DNS_PROXY_H
+#define XPC_CLIENT_DNS_PROXY_H
+
+#define kDNSProxyService "com.apple.mDNSResponder.dnsproxy"
+#define kDNSProxyParameters "DNSProxyParameters"
+
+#define kDNSInIfindex0 "InputArrayInterfaceIndex[0]"
+#define kDNSInIfindex1 "InputArrayInterfaceIndex[1]"
+#define kDNSInIfindex2 "InputArrayInterfaceIndex[2]"
+#define kDNSInIfindex3 "InputArrayInterfaceIndex[3]"
+#define kDNSInIfindex4 "InputArrayInterfaceIndex[4]"
+
+#define kDNSOutIfindex "OutputInterfaceIndex"
+
+#endif /* XPC_CLIENT_DNS_PROXY_H */
--- /dev/null
+//
+// xpc_client_log_utility.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_CLIENT_LOG_UTILITY_H
+#define XPC_CLIENT_LOG_UTILITY_H
+
+#define kDNSLogUtilityService "com.apple.mDNSResponder.log_utility"
+
+typedef enum
+{
+ kDNSMsg_NoError = 0,
+ kDNSMsg_Busy,
+ kDNSMsg_UnknownRequest,
+ kDNSMsg_Error
+} DaemonReplyStatusCodes;
+
+#define kDNSErrorDescription "ErrorDescription"
+
+#define kDNSLogLevel "DNSLoggingVerbosity"
+typedef enum
+{
+ log_level1 = 1, // logging off
+ log_level2, // logging USR1
+ log_level3, // logging USR2
+ log_level4, // logging USR1/2
+} DNSLogLevels;
+
+#define kDNSStateInfo "DNSStateInfoLevels"
+typedef enum
+{
+ full_state = 1, // Dump state to a plain text file
+ full_state_with_compression = 2, // Dump state to a compressed file
+ full_state_to_stdout = 3, // Dump state to STDOUT
+} DNSStateInfo;
+
+#define kmDNSResponderTests "mDNSResponderTests"
+typedef enum
+{
+ test_helper_ipc = 1, // invokes mDNSResponder to send a test msg to mDNSResponderHelper
+ test_mDNS_log, // invokes mDNSResponder to log using different internal macros
+} mDNSTestModes;
+
+#define kDNSStateDump "mDNSResponderStateDump"
+#define kDNSDumpFilePath "mDNSResponderDumpFilePath"
+#define kDNSStateDumpTimeUsed "mDNSResponderDumpTimeUsed"
+#define kDNSStateDumpFD "mDNSResponderDumpFD"
+
+#endif /* XPC_CLIENT_LOG_UTILITY_H */
--- /dev/null
+//
+// xpc_clients.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_CLIENTS_H
+#define XPC_CLIENTS_H
+
+#include "xpc_client_dns_proxy.h"
+#include "xpc_client_log_utility.h"
+
+#define kDNSDaemonReply "DaemonReplyStatusToClient"
+
+#endif // XPC_CLIENTS_H
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <xpc/private.h>
+#include "xpc_service_dns_proxy.h"
+#include "xpc_clients.h"
+
+#include "dnsproxy.h"
+#include "mDNSMacOSX.h"
+#include "xpc_services.h"
+
+extern mDNS mDNSStorage;
+static int dps_client_pid; // To track current active client using DNS Proxy Service
+static dispatch_queue_t dps_queue = NULL;
+
+mDNSlocal void accept_dps_client(xpc_connection_t conn);
+mDNSlocal void handle_dps_request(xpc_object_t req);
+mDNSlocal void handle_dps_terminate();
+mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off);
+
+mDNSexport void log_dnsproxy_info(mDNS *const m)
+{
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "----- Active XPC Clients -----");
+ if (dps_client_pid) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]",
+ dps_client_pid, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4],
+ m->dp_opintf);
+ } else {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "<None>");
+ }
+}
+
+mDNSexport void log_dnsproxy_info_to_fd(int fd, mDNS *const m)
+{
+ LogToFD(fd, "----- Active XPC Clients -----");
+ if (dps_client_pid) {
+ LogToFD(fd, "DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]",
+ dps_client_pid, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4],
+ m->dp_opintf);
+ } else {
+ LogToFD(fd, "<None>");
+ }
+}
+
+mDNSexport void init_dnsproxy_service(void)
+{
+ xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+ if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
+ return;
+ }
+
+ dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL);
+
+ xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg)
+ {
+ xpc_type_t type = xpc_get_type(eventmsg);
+
+ if (type == XPC_TYPE_CONNECTION) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "init_dnsproxy_service: New DNSProxyService Client %p", eventmsg);
+ accept_dps_client(eventmsg);
+ }
+ else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "init_dnsproxy_service: XPCError: " PUB_S,
+ xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
+ return;
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "init_dnsproxy_service: Unknown EventMsg type");
+ return;
+ }
+ });
+
+ xpc_connection_resume(dps_listener);
+}
+
+mDNSlocal void accept_dps_client(xpc_connection_t conn)
+{
+ uid_t c_euid;
+ int c_pid;
+ c_euid = xpc_connection_get_euid(conn);
+ c_pid = xpc_connection_get_pid(conn);
+
+ if (c_euid != 0 || !IsEntitled(conn, kDNSProxyService))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "accept_dps_client: DNSProxyService Client PID[%d] is missing Entitlement or is not running as root!",
+ c_pid);
+ xpc_connection_cancel(conn);
+ return;
+ }
+
+ xpc_retain(conn);
+ xpc_connection_set_target_queue(conn, dps_queue);
+ xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
+ {
+ xpc_type_t type = xpc_get_type(req_msg);
+
+ if (type == XPC_TYPE_DICTIONARY)
+ {
+ handle_dps_request(req_msg);
+ }
+ else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn);
+ // Only the Client that has activated DPS should be able to terminate it
+ if (c_pid == dps_client_pid)
+ handle_dps_terminate();
+ xpc_release(conn);
+ }
+ });
+
+ xpc_connection_resume(conn);
+}
+
+mDNSlocal void handle_dps_request(xpc_object_t req)
+{
+ int dps_tmp_client;
+ mDNSBool proxy_off = mDNSfalse;
+ xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
+ dps_tmp_client = (int) xpc_connection_get_pid(remote_conn);
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "handle_dps_request: Handler for DNS Proxy Requests");
+
+ if (dps_client_pid <= 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "handle_dps_request: DNSProxy is not engaged (New Client)");
+ // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF)
+ dps_client_pid = dps_tmp_client;
+ proxy_off = mDNStrue;
+ }
+ else
+ {
+ // We already have an active DNS Proxy Client and until that client does not terminate the connection
+ // or crashes, a new client cannot change/override the current DNS Proxy settings.
+ if (dps_client_pid != dps_tmp_client)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time");
+ // Return Engaged Status to the client
+ xpc_object_t reply = xpc_dictionary_create_reply(req);
+ if (reply)
+ {
+ xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_Busy);
+ xpc_connection_send_message(remote_conn, reply);
+ xpc_release(reply);
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "handle_dps_request: Reply Dictionary could not be created");
+ return;
+ }
+ // We do not really need to terminate the connection with the client
+ // as it may try again later which is fine
+ return;
+ }
+ }
+
+
+ xpc_object_t response = xpc_dictionary_create_reply(req);
+ // Return Success Status to the client
+ if (response)
+ {
+ xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
+ xpc_connection_send_message(remote_conn, response);
+ xpc_release(response);
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "handle_dps_request: Response Dictionary could not be created");
+ return;
+ }
+
+ // Proceed to get DNS Proxy Settings from the Client
+ if (xpc_dictionary_get_uint64(req, kDNSProxyParameters))
+ {
+ mDNSu32 inIf[MaxIp], outIf;
+
+ inIf[0] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0);
+ inIf[1] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1);
+ inIf[2] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2);
+ inIf[3] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3);
+ inIf[4] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4);
+ outIf = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex);
+
+ ActivateDNSProxy(inIf, outIf, proxy_off);
+ }
+}
+
+mDNSlocal void handle_dps_terminate()
+{
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy",
+ dps_client_pid);
+ // Clear the Client's PID, so that we can now accept new DPS requests
+ dps_client_pid = 0;
+
+ KQueueLock();
+ mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
+ // TBD: Close TCP Sockets
+ DNSProxyTerminate();
+ KQueueUnlock("DNSProxy Deactivated");
+}
+
+mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off)
+{
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d]",
+ IpIfArr[0], IpIfArr[1], IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf);
+
+ KQueueLock();
+ DNSProxyInit(IpIfArr, OpIf);
+ if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts
+ mDNSPlatformInitDNSProxySkts(ProxyUDPCallback, ProxyTCPCallback);
+ KQueueUnlock("DNSProxy Activated");
+}
--- /dev/null
+//
+// xpc_service_dns_server.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_SERVICE_DNS_PROXY_H
+#define XPC_SERVICE_DNS_PROXY_H
+
+#include "xpc_client_dns_proxy.h"
+#include "dnsproxy.h"
+
+mDNSexport void log_dnsproxy_info(mDNS *const m);
+mDNSexport void log_dnsproxy_info_to_fd(int fd, mDNS *const m);
+mDNSexport void init_dnsproxy_service(void);
+
+#endif /* XPC_SERVICE_DNS_PROXY_H */
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <xpc/xpc.h>
+#include <dirent.h> // opendir
+#include <sys/stat.h> // stat
+#include <archive.h>
+#include <archive_entry.h>
+#include <AssertMacros.h> // require, require_action
+
+#include "mDNSMacOSX.h"
+#include "helper.h"
+#include "xpc_services.h"
+#include "xpc_service_log_utility.h"
+#include "xpc_clients.h"
+#include "system_utilities.h" // IsAppleInternalBuild
+
+#define STATE_DUMP_PLAIN_SUFFIX "txt"
+#define STATE_DUMP_COMPRESSED_SUFFIX "tar.bz2"
+
+// global variables
+extern mDNS mDNSStorage;
+static dispatch_queue_t log_utility_server_queue = NULL;
+
+// function declaration
+extern void dump_state_to_fd(int fd);
+mDNSlocal void accept_client(xpc_connection_t conn);
+mDNSlocal mDNSs8 handle_requests(xpc_object_t req);
+mDNSlocal mDNSs8 check_permission(xpc_connection_t connection);
+mDNSlocal mDNSs8 handle_state_dump(mDNSu32 dump_option, char *full_file_name, mDNSu32 name_buffer_len,
+ int client_fd, mDNSs32 *time_ms_used);
+mDNSlocal mDNSs32 find_oldest_state_dump(const char *dump_dir, const char *file_name, char *full_file_name,
+ mDNSu32 buffer_len, char *oldest_file_name);
+mDNSlocal mDNSs8 remove_state_dump_if_too_many(const char *dump_dir, const char *oldest_file_name, mDNSs32 dump_file_count,
+ mDNSs32 max_allowed);
+mDNSlocal int create_new_state_dump_file(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len);
+mDNSlocal mDNSs8 handle_state_dump_to_fd(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len,
+ mDNSBool if_compress);
+mDNSlocal mDNSs8 compress_state_dump_and_delete(char *input_file, mDNSu32 buffer_len);
+mDNSlocal mDNSs32 timediff_ms(struct timeval* t1, struct timeval* t2);
+
+// function definition
+mDNSexport void init_log_utility_service(void)
+{
+ xpc_connection_t log_utility_listener = xpc_connection_create_mach_service(kDNSLogUtilityService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+ if (!log_utility_listener || xpc_get_type(log_utility_listener) != XPC_TYPE_CONNECTION) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "Error Creating XPC Listener for Log Utility Server!");
+ return;
+ }
+
+ log_utility_server_queue = dispatch_queue_create("com.apple.mDNSResponder.log_utility_server_queue", NULL);
+
+ xpc_connection_set_event_handler(log_utility_listener, ^(xpc_object_t eventmsg) {
+ xpc_type_t type = xpc_get_type(eventmsg);
+
+ if (type == XPC_TYPE_CONNECTION) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_INFO, "C%p {action='receives connection'}", eventmsg);
+ accept_client(eventmsg);
+ } else if (type == XPC_TYPE_ERROR) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "C%p {xpc_error=\n" PUB_S "\n}", eventmsg,
+ xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
+ } else {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "C%p {error='receives unknown xpc request'}", eventmsg);
+ }
+ });
+
+ xpc_connection_resume(log_utility_listener);
+}
+
+mDNSlocal void accept_client(xpc_connection_t conn)
+{
+ xpc_retain(conn);
+ xpc_connection_set_target_queue(conn, log_utility_server_queue);
+ xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) {
+ xpc_type_t type = xpc_get_type(req_msg);
+
+ if (type == XPC_TYPE_DICTIONARY) {
+ handle_requests(req_msg);
+ } else { // We hit this case ONLY if Client Terminated Connection OR Crashed
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT, "C%p {status='client closed the connection'}", conn);
+ xpc_release(conn);
+ }
+ });
+
+ xpc_connection_resume(conn);
+}
+
+mDNSlocal mDNSs8 handle_requests(xpc_object_t req)
+{
+ mDNSs8 ret = 0;
+ xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
+
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_INFO, "C%p {action='handling log utility request'}", remote_conn);
+
+ // create the dictionary for response purpose
+ xpc_object_t response = xpc_dictionary_create_reply(req);
+ if (response == mDNSNULL) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "C%p {error='cannot create reply response dictionary'}", remote_conn);
+ return -1;
+ }
+
+ mDNSu32 reply_value;
+ ret = check_permission(remote_conn);
+ if (ret < 0) {
+ // permission error
+ reply_value = kDNSMsg_Error;
+ if (ret == -1) {
+ xpc_dictionary_set_string(response, kDNSErrorDescription, "Client must be running as root");
+ } else if (ret == -2) {
+ xpc_dictionary_set_string(response, kDNSErrorDescription, "Client is missing the entitlement");
+ }
+ } else if (xpc_dictionary_get_uint64(req, kDNSStateDump)) {
+ mDNSu32 dump_option = (mDNSs32)xpc_dictionary_get_uint64(req, kDNSStateDump);
+ char full_file_name[PATH_MAX];
+ mDNSs32 time_used;
+
+ // We do not dump state in the customer build due to privacy consideration.
+ if (IsAppleInternalBuild()) {
+ int client_fd = xpc_dictionary_dup_fd(req, kDNSStateDumpFD);
+ ret = handle_state_dump(dump_option, full_file_name, sizeof(full_file_name), client_fd, &time_used);
+ if (ret == 0) {
+ reply_value = kDNSMsg_NoError;
+ xpc_dictionary_set_int64(response, kDNSStateDumpTimeUsed, time_used);
+
+ if (dump_option != full_state_to_stdout) {
+ xpc_dictionary_set_string(response, kDNSDumpFilePath, full_file_name);
+ }
+ } else {
+ reply_value = kDNSMsg_Error;
+ xpc_dictionary_set_string(response, kDNSErrorDescription, "State dump fails");
+ }
+ close(client_fd);
+ } else {
+ reply_value = kDNSMsg_Error;
+ xpc_dictionary_set_string(response, kDNSErrorDescription, "State dump is only enabled in internal builds");
+ }
+ } else {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR,
+ "C%p {error='unknown log utility request from client'}", remote_conn);
+ reply_value = kDNSMsg_UnknownRequest;
+ xpc_dictionary_set_string(response, kDNSErrorDescription, "unknown log utility request from client");
+ }
+
+ xpc_dictionary_set_uint64(response, kDNSDaemonReply, reply_value);
+ xpc_connection_send_message(remote_conn, response);
+ xpc_release(response);
+
+ return 0;
+}
+
+mDNSlocal mDNSs8 check_permission(xpc_connection_t connection)
+{
+ uid_t client_euid = xpc_connection_get_euid(connection);
+ int client_pid = xpc_connection_get_pid(connection);
+ mDNSs8 ret = 0;
+
+ if (client_euid != 0) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+ "C%p {client_pid=%d,error='not running as root'}", connection, client_pid);
+ ret = -1;
+ }
+
+ if (!IsEntitled(connection, kDNSLogUtilityService)){
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+ "C%p {client_pid=%d,error='Client is missing entitlement'}", connection, client_pid);
+ ret = -2;
+ }
+
+ return ret;
+}
+
+/*
+ * pointers of full_file_name and time_used are passed into, when function returns, full_file_name will be filled
+ * with the full path to the dumped file, and time_used is filled with time duration(ms) when mDNSResponder is
+ * blocked. if_get_lock indicates if we should lock the kqueue before dumping the state.
+ */
+mDNSexport mDNSs8 handle_state_dump(mDNSu32 dump_option, char *full_file_name, mDNSu32 name_buffer_len,
+ int client_fd, mDNSs32 *time_ms_used)
+{
+ mDNSs8 ret;
+
+ // record the start time, and lock the kqueue
+ struct timeval time_start;
+ gettimeofday(&time_start, mDNSNULL);
+ KQueueLock();
+
+ if (dump_option == full_state_to_stdout) {
+ dump_state_to_fd(client_fd);
+ ret = 0;
+ } else {
+ // dump_option == full_state || dump_option == full_state_with_compression
+ ret = handle_state_dump_to_fd(MDSNRESPONDER_STATE_DUMP_DIR, MDSNRESPONDER_STATE_DUMP_FILE_NAME,
+ full_file_name, name_buffer_len,
+ dump_option == full_state_with_compression ? mDNStrue : mDNSfalse);
+ }
+
+ // unlock the kqueue, record the end time and calculate the duration.
+ KQueueUnlock("State Dump");
+ struct timeval time_end;
+ gettimeofday(&time_end, mDNSNULL);
+ *time_ms_used = timediff_ms(&time_end, &time_start);
+
+ return ret;
+}
+
+#define MAX_NUM_DUMP_FILES 5 // controls how many files we are allowed to created for the state dump
+mDNSlocal mDNSs8 handle_state_dump_to_fd(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 name_buffer_len,
+ mDNSBool if_compress)
+{
+ char oldest_file_name[PATH_MAX];
+ mDNSs32 dump_file_count = 0;
+ int ret;
+
+ dump_file_count = find_oldest_state_dump(dump_dir, file_name, full_file_name, name_buffer_len, oldest_file_name);
+ require_action(dump_file_count >= 0, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "find_oldest_state_dump fails"));
+
+ ret = remove_state_dump_if_too_many(dump_dir, oldest_file_name, dump_file_count, MAX_NUM_DUMP_FILES);
+ require_action(ret == 0, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "remove_state_dump_if_too_many fails"));
+
+ int fd = create_new_state_dump_file(dump_dir, file_name, full_file_name, name_buffer_len);
+ require_action(fd >= 0, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "create_new_state_dump_file fails"));
+
+ dump_state_to_fd(fd);
+ close(fd); // create_new_state_dump_file open the file, we have to close it here
+
+ if (if_compress) {
+ ret = compress_state_dump_and_delete(full_file_name, name_buffer_len);
+ require_action(ret == 0, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT, "State Dump: Error happens when trying to compress the state dump, reason: %s", strerror(errno)));
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+/*
+ * Scan the directory, find all the files that start with <mDNSResponder state dump file name>. Return the number of
+ * state dump files and the name of the oldest file created.
+ */
+mDNSlocal mDNSs32 find_oldest_state_dump(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len,
+ char *oldest_file_name)
+{
+ int ret;
+
+ full_file_name[0] = '\0';
+ full_file_name[buffer_len - 1]= '\0';
+ snprintf(full_file_name, buffer_len - 1, "%s/%s", dump_dir, file_name);
+
+ DIR *dir_p = opendir(dump_dir);
+ if (dir_p == mDNSNULL) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+ "State Dump: directory " PUB_S " cannot be opened, reason: " PUB_S, dump_dir, strerror(errno));
+ return -1;
+ }
+
+ // scan every entry under directory, if starts with <mDNSResponder state dump file name>, check its create time.
+ struct dirent *dir_entry_p = mDNSNULL;
+ mDNSu32 file_name_len = strnlen(file_name, MAXPATHLEN);
+ mDNSu8 dump_file_count = 0;
+ struct timespec oldest_time = {LONG_MAX, LONG_MAX};
+
+ while ((dir_entry_p = readdir(dir_p)) != mDNSNULL) {
+ if (dir_entry_p->d_namlen <= file_name_len)
+ continue;
+
+ if (strncmp(dir_entry_p->d_name, file_name, file_name_len) == 0) {
+ struct stat file_state;
+ snprintf(full_file_name, buffer_len - 1, "%s/%s", dump_dir, dir_entry_p->d_name);
+
+ // use stat to get creation time
+ ret = stat(full_file_name, &file_state);
+ if (ret != 0) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+ "State Dump: error when reading file properties, reason: " PUB_S, strerror(errno));
+ return -1;
+ }
+ // if the file is older than the current record
+ if (oldest_time.tv_sec > file_state.st_birthtimespec.tv_sec
+ || (oldest_time.tv_sec == file_state.st_birthtimespec.tv_sec
+ && oldest_time.tv_sec > file_state.st_birthtimespec.tv_sec)) {
+ oldest_time = file_state.st_birthtimespec;
+ strncpy(oldest_file_name, dir_entry_p->d_name, MIN(PATH_MAX - 1, dir_entry_p->d_namlen + 1));
+ }
+
+ dump_file_count++;
+ }
+ }
+ closedir(dir_p);
+
+ return dump_file_count;
+}
+
+mDNSlocal mDNSs8 remove_state_dump_if_too_many(const char *dump_dir, const char *oldest_file_name, mDNSs32 dump_file_count,
+ mDNSs32 max_allowed)
+{
+ char path_file_to_remove[PATH_MAX];
+ path_file_to_remove[PATH_MAX - 1] = '\0';
+ // If the number of state dump files has reached the maximum value, we delete the oldest one.
+ if (dump_file_count == max_allowed) {
+ // construct the full name
+ snprintf(path_file_to_remove, PATH_MAX - 1, "%s/%s", dump_dir, oldest_file_name);
+ if (remove(path_file_to_remove) != 0) {
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+ "State Dump: file " PUB_S " cannot be deleted, reason: " PUB_S, path_file_to_remove, strerror(errno));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Generate the file name of state dump with current time stamp, and return the FILE pointer, anyone who calls this
+ * function must call fclose() to release the FILE pointer.
+ */
+mDNSlocal int create_new_state_dump_file(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len)
+{
+ struct timeval now;
+ struct tm local_time;
+ char date_time_str[32];
+ char time_zone_str[32];
+
+ gettimeofday(&now, NULL);
+ localtime_r(&now.tv_sec, &local_time);
+
+ // 2008-08-08_20-00-00
+ strftime(date_time_str, sizeof(date_time_str), "%F_%H-%M-%S", &local_time);
+ // +0800
+ strftime(time_zone_str, sizeof(time_zone_str), "%z", &local_time);
+ // /private/var/log/mDNSResponder/mDNSResponder_state_dump_2008-08-08_20-00-00-000000+0800.txt
+ snprintf(full_file_name, buffer_len, "%s/%s_%s-%06lu%s." STATE_DUMP_PLAIN_SUFFIX,
+ dump_dir, file_name, date_time_str, (unsigned long)now.tv_usec, time_zone_str);
+
+ int fd = open(full_file_name, O_WRONLY | O_CREAT, 0644); // 0644 means * (owning) User: read & write * Group: read * Other: read
+ if (fd < 0) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "State Dump: file " PUB_S " cannot be opened, reason: " PUB_S, full_file_name, strerror(errno));
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * Compress the state dump from pliantext to tar.bz2, remove the original one, and change the content of input_file to
+ * newly created compressed file if compression succeeds.
+ */
+mDNSlocal mDNSs8 compress_state_dump_and_delete(char *input_file, mDNSu32 buffer_len)
+{
+ struct archive *a = mDNSNULL;
+ struct archive_entry *entry = mDNSNULL;
+ struct stat st;
+ int fd = -1;
+ char output_file[PATH_MAX];
+ void *mapped_pointer = mDNSNULL;
+ int ret;
+
+ output_file[PATH_MAX - 1] = '\0';
+
+ a = archive_write_new();
+ require_action(a != mDNSNULL, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_new fails: " PUB_S, archive_error_string(a)));
+ archive_write_add_filter_bzip2(a);
+ archive_write_set_format_ustar(a);
+
+ // remove the .txt suffix, and append .tar.bz2 suffix
+ mDNSu32 plain_file_name_len = strlen(input_file); // input_file is guaranteed to be '\0'-terminated
+ strncpy(output_file, input_file, plain_file_name_len - sizeof(STATE_DUMP_PLAIN_SUFFIX));
+ output_file[plain_file_name_len - sizeof(STATE_DUMP_PLAIN_SUFFIX)] = '\0';
+ strncat(output_file, "." STATE_DUMP_COMPRESSED_SUFFIX, 1 + sizeof(STATE_DUMP_COMPRESSED_SUFFIX));
+
+ // open/create the archive for the given path name
+ ret = archive_write_open_filename(a, output_file);
+ require_action(ret == ARCHIVE_OK, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_open_filename fails: " PUB_S, archive_error_string(a)));
+
+ // get the state of file to be compressed
+ stat(input_file, &st);
+
+ // entry is required to create an archive
+ entry = archive_entry_new();
+ require_action(entry != mDNSNULL, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_entry_new fails: " PUB_S, strerror(errno)));
+
+ // set the name of file in the compressed file
+ const char *file_name_with_timestamp = strstr(input_file, MDSNRESPONDER_STATE_DUMP_FILE_NAME);
+ if (file_name_with_timestamp == mDNSNULL) {
+ file_name_with_timestamp = MDSNRESPONDER_STATE_DUMP_FILE_NAME "." STATE_DUMP_PLAIN_SUFFIX;
+ }
+
+ // copy the original file state to entry
+ archive_entry_copy_stat(entry, &st);
+ archive_entry_set_pathname(entry, file_name_with_timestamp);
+
+ // write entry into archive
+ do {
+ ret = archive_write_header(a, entry);
+ } while (ret == ARCHIVE_RETRY);
+ require_action(ret == ARCHIVE_OK, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_header fails: " PUB_S, archive_error_string(a)));
+
+ // if the original file has something to compress, use mmap to read its content
+ if (st.st_size > 0) {
+ fd = open(input_file, O_RDONLY);
+
+ mapped_pointer = mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ require_action(mapped_pointer != MAP_FAILED, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "mmap fails: " PUB_S, strerror(errno)));
+
+ mDNSu32 amount_written = (mDNSu32)archive_write_data(a, mapped_pointer, st.st_size);
+ require_action(amount_written == (mDNSu32)st.st_size, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_data fails: amount_written(%u) != (%u)", amount_written, (mDNSu32)st.st_size));
+
+ int munmap_result = munmap(mapped_pointer, st.st_size);
+ require_action(munmap_result == 0, error,
+ LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "munmap fails: " PUB_S, strerror(errno)));
+ mapped_pointer = mDNSNULL;
+
+ close(fd);
+ fd = -1; // set the file descriptor to -1 to avoid double free
+ }
+ archive_entry_free(entry);
+ entry = mDNSNULL;
+
+ archive_write_close(a);
+ archive_write_free(a);
+ a = mDNSNULL;
+
+ // remove the original one, return the newly created compressed file name
+ remove(input_file);
+ strncpy(input_file, output_file, buffer_len);
+ input_file[buffer_len - 1] = '\0';
+
+ return 0;
+
+error:
+ if (a != mDNSNULL) {
+ archive_write_close(a);
+ archive_write_free(a);
+ }
+ if (entry != mDNSNULL) {
+ archive_entry_free(entry);
+ }
+ if (fd != -1) {
+ close(fd);
+ }
+ if (mapped_pointer != mDNSNULL) {
+ munmap(mapped_pointer, st.st_size);
+ }
+ remove(input_file);
+ return -1;
+}
+
+/*
+ * Return the time difference(ms) between two struct timeval.
+ */
+#define US_PER_S 1000000
+#define MS_PER_S 1000
+mDNSlocal mDNSs32 timediff_ms(struct timeval* t1, struct timeval* t2)
+{
+ int usec, ms, sec;
+
+ if (t1->tv_sec < t2->tv_sec || (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec))
+ return -timediff_ms(t2, t1);
+
+ sec = (int)(t1->tv_sec - t2->tv_sec);
+ if (t1->tv_usec >= t2->tv_usec)
+ usec = t1->tv_usec - t2->tv_usec;
+ else {
+ usec = t1->tv_usec + US_PER_S - t2->tv_usec;
+ sec -= 1;
+ }
+ ms = sec * MS_PER_S;
+ ms += usec / MS_PER_S;
+ return ms;
+}
--- /dev/null
+//
+// xpc_service_log_utility.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_SERVICE_LOG_UTILITY_H
+#define XPC_SERVICE_LOG_UTILITY_H
+
+#include "mDNSEmbeddedAPI.h"
+
+#define MDSNRESPONDER_STATE_DUMP_DIR "/private/var/log/mDNSResponder"
+#define MDSNRESPONDER_STATE_DUMP_FILE_NAME "mDNSResponder_state_dump"
+
+mDNSexport void init_log_utility_service(void);
+
+#endif /* XPC_SERVICE_LOG_UTILITY_H */
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "xpc_services.h"
+#include <xpc/private.h> // xpc_connection_copy_entitlement_value
+
+#include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock
+#include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
+#include "xpc_service_dns_proxy.h" // init_dnsproxy_service
+#include "xpc_service_log_utility.h" // init_dnsctl_service
+
+extern mDNS mDNSStorage;
+
+mDNSexport void xpc_server_init()
+{
+ // add XPC Services here
+ init_dnsproxy_service();
+ init_log_utility_service();
+}
+
+// Utilities
+
+mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *entitlement_name)
+{
+ mDNSBool entitled = mDNSfalse;
+ xpc_object_t entitled_obj = xpc_connection_copy_entitlement_value(conn, entitlement_name);
+
+ if (entitled_obj) {
+ if (xpc_get_type(entitled_obj) == XPC_TYPE_BOOL && xpc_bool_get_value(entitled_obj)) {
+ entitled = mDNStrue;
+ }
+ xpc_release(entitled_obj);
+ } else {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "IsEntitled: Client Entitlement is NULL");
+ }
+
+ if (!entitled) {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "IsEntitled: Client is missing Entitlement!");
+ }
+
+ return entitled;
+}
--- /dev/null
+//
+// xpc_services.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+
+#ifndef XPC_SERVICES_H
+#define XPC_SERVICES_H
+
+#include "mDNSEmbeddedAPI.h"
+#include <xpc/xpc.h>
+
+mDNSexport void xpc_server_init(void);
+mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *password);
+
+#endif // XPC_SERVICES_H
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
+#include <sys/socket.h>
#include "mDNSEmbeddedAPI.h" // Defines the interface to the mDNS core code
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include "ExampleClientApp.h"
// Globals
-static mDNS mDNSStorage; // mDNS core uses this to store its globals
+mDNSexport mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
#define RR_CACHE_SIZE 500
static CacheEntity gRRCache[RR_CACHE_SIZE];
MakeDomainNameFromDNSNameString(&type, gServiceType);
MakeDomainNameFromDNSNameString(&domain, gServiceDomain);
- status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSNULL, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, BrowseCallback, NULL);
+ status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, BrowseCallback, NULL);
// Run the platform main event loop until the user types ^C.
// The BrowseCallback routine is responsible for printing
{
int nfds = 0;
fd_set readfds;
+ fd_set writefds;
struct timeval timeout;
int result;
// This example client has no file descriptors of its own,
// but a real application would call FD_SET to add them to the set here
FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
- mDNSPosixGetFDSet(m, &nfds, &readfds, &timeout);
+ mDNSPosixGetFDSet(m, &nfds, &readfds, &writefds, &timeout);
// 4. Call select as normal
verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
- result = select(nfds, &readfds, NULL, NULL, &timeout);
+ result = select(nfds, &readfds, &writefds, NULL, &timeout);
if (result < 0)
{
else
{
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
- mDNSPosixProcessFDSet(m, &readfds);
+ mDNSPosixProcessFDSet(m, &readfds, &writefds);
// 6. This example client has no other work it needs to be doing,
// but a real client would do its work here
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2018 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.
//*************************************************************************************************************
// Globals
-static mDNS mDNSStorage; // mDNS core uses this to store its globals
+mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
#define RR_CACHE_SIZE 500
static CacheEntity gRRCache[RR_CACHE_SIZE];
while (!StopNow)
{
int nfds = 0;
- fd_set readfds;
+ fd_set readfds, writefds;
struct timeval now, remain = end;
int result;
FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
gettimeofday(&now, NULL);
if (remain.tv_usec < now.tv_usec) { remain.tv_usec += 1000000; remain.tv_sec--; }
if (remain.tv_sec < now.tv_sec)
}
remain.tv_usec -= now.tv_usec;
remain.tv_sec -= now.tv_sec;
- mDNSPosixGetFDSet(m, &nfds, &readfds, &remain);
- result = select(nfds, &readfds, NULL, NULL, &remain);
- if (result >= 0) mDNSPosixProcessFDSet(m, &readfds);
+ mDNSPosixGetFDSet(m, &nfds, &readfds, &writefds, &remain);
+ result = select(nfds, &readfds, &writefds, NULL, &remain);
+ if (result >= 0) mDNSPosixProcessFDSet(m, &readfds, &writefds);
else if (errno != EINTR) StopNow = 2;
}
}
q->ForceMCast = mDNStrue; // Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa.
q->ReturnIntermed = mDNStrue;
q->SuppressUnusable = mDNSfalse;
- q->SearchListIndex = 0;
q->AppendSearchDomains = 0;
- q->RetryWithSearchDomains = mDNSfalse;
q->TimeoutQuestion = 0;
q->ValidationRequired = 0;
q->ValidatingResponse = 0;
q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = mDNSfalse;
+ q->UseBackgroundTraffic = mDNSfalse;
q->ProxyQuestion = 0;
- q->qnameOrig = mDNSNULL;
- q->AnonInfo = mDNSNULL;
q->pid = mDNSPlatformGetPID();
q->QuestionCallback = callback;
q->QuestionContext = NULL;
# -*- tab-width: 4 -*-
#
-# Copyright (c) 2002-2004, 2015, Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2002-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
COREDIR = ../mDNSCore
SHAREDDIR ?= ../mDNSShared
+DSODIR ?= ../DSO
JDK = /usr/jdk
-CC = @cc
-BISON = @bison
-FLEX = @flex
-ST = @strip
-LD = ld -shared
+SYSTEM := $(shell uname -s)
+ifeq ($(SYSTEM), Darwin)
+ os=x
+else ifeq ($(SYSTEM), Linux)
+ os=linux
+endif
+
+CC = cc
+BISON = bison
+FLEX = flex
+ST = strip
+LD = ld
+SOOPTS = -shared
CP = cp
RM = rm
LN = ln -s -f
-CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
+CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(DSODIR) -I$(PROXYDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
CFLAGS_PTHREAD =
LINKOPTS =
LINKOPTS_PTHREAD = -lpthread
LDSUFFIX = so
JAVACFLAGS_OS = -fPIC -shared -ldns_sd
+ifeq "$(OPEN_SOURCE)" "1"
+CFLAGS_OPEN_SOURCE=-D__OPEN_SOURCE__
+else
+CFLAGS_OPEN_SOURCE=
+endif
+
# Set up diverging paths for debug vs. prod builds
-DEBUG=0
-ifeq ($(DEBUG),1)
-CFLAGS_DEBUG = -g -DMDNS_DEBUGMSGS=2
+ifeq "$(DEBUG)" "1"
+CFLAGS_DEBUGGING = -g -DMDNS_DEBUGMSGS=2
OBJDIR = objects/debug
BUILDDIR = build/debug
STRIP = echo
else
+ifeq "$(DEBUGSYMS)" "1"
+CFLAGS_DEBUGGING = -g -DMDNS_DEBUGMSGS=0
+OBJDIR = objects/prod
+BUILDDIR = build/prod
+STRIP = echo
+else
# We use -Os for two reasons:
# 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
+CFLAGS_DEBUGGING = -g -DMDNS_DEBUGMSGS=0
OBJDIR ?= objects/prod
BUILDDIR ?= build/prod
STRIP = $(ST) -S
endif
+endif
# Configure per-OS peculiarities
ifeq ($(os),solaris)
-CFLAGS_DEBUG = -O0 -DMDNS_DEBUGMSGS=0
+CFLAGS_DEBUGGING = -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 -DTARGET_OS_SOLARIS
CC = gcc
-LD = gcc -shared
+LD = gcc
+SOOPTS = -shared
LINKOPTS = -lsocket -lnsl -lresolv
JAVACFLAGS_OS += -I$(JDK)/include/solaris
ifneq ($(DEBUG),1)
# any target that contains the string "linux"
ifeq ($(findstring linux,$(os)),linux)
-CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -fno-strict-aliasing
-LD = $(CC) -shared
+CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -ftabstop=4
+LD = $(CC)
+SOOPTS = -shared
FLEXFLAGS_OS = -l
JAVACFLAGS_OS += -I$(JDK)/include/linux
# 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 \
- -DHAVE_STRLCPY=1 \
+ -DHAVE_STRLCPY=1 -DTARGET_OS_MAC \
-D__APPLE_USE_RFC_2292 #-Wunreachable-code
CC = gcc
-LD = $(CC) -dynamiclib
+LD = $(CC)
+SOOPTS = -dynamiclib
LINKOPTS = -lSystem
LDSUFFIX = dylib
JDK = /System/Library/Frameworks/JavaVM.framework/Home
# If not otherwise defined, we install into /usr/lib and /usr/include
# and our startup script is called mdns (e.g. /etc/init.d/mdns)
+ETCBASE?=/etc
INSTBASE?=/usr
STARTUPSCRIPTNAME?=mdns
endif
endif
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
+MDNSCFLAGS = $(CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUGGING) $(CFLAGS_OPEN_SOURCE)
#############################################################################
-all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder Identify NetMonitor $(OPTIONALTARG)
+all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder NetMonitor $(OPTIONALTARG)
install: setup InstalledStartup InstalledDaemon InstalledLib InstalledManPages InstalledClients $(OPTINSTALL)
# daemon target builds the daemon
DAEMONOBJS = $(OBJDIR)/PosixDaemon.c.o $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNS.c.o \
$(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/uds_daemon.c.o \
- $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/PlatformCommon.c.o \
- $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/anonymous.c.o
+ $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o \
+ $(OBJDIR)/PlatformCommon.c.o $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/ClientRequests.c.o \
+ $(OBJDIR)/dso.c.o $(OBJDIR)/dso-transport.c.o $(OBJDIR)/dnssd_clientshim.c.o \
+ $(OBJDIR)/posix_utilities.c.o
# dnsextd target build dnsextd
DNSEXTDOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/GenLinkedList.c.o $(OBJDIR)/DNSDigest.c.o \
$(BUILDDIR)/mdnsd: $(DAEMONOBJS)
$(CC) -o $@ $+ $(LINKOPTS)
- @$(STRIP) $@
+ $(STRIP) $@
# libdns_sd target builds the client library
libdns_sd: setup $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
CLIENTLIBOBJS = $(OBJDIR)/dnssd_clientlib.c.so.o $(OBJDIR)/dnssd_clientstub.c.so.o $(OBJDIR)/dnssd_ipc.c.so.o
$(BUILDDIR)/libdns_sd.$(LDSUFFIX): $(CLIENTLIBOBJS)
- @$(LD) $(LINKOPTS) -o $@ $+
- @$(STRIP) $@
+ $(LD) $(SOOPTS) $(LINKOPTS) -o $@ $+
+ $(STRIP) $@
Clients: setup libdns_sd ../Clients/build/dns-sd
@echo "Clients done"
-../Clients/build/dns-sd:
- @$(MAKE) -C ../Clients
+../Clients/build/dns-sd: ../Clients/dns-sd.c
+ $(MAKE) -C ../Clients DEBUG=$(DEBUG) SUPMAKE_CFLAGS="$(MDNSCFLAGS)"
# nss_mdns target builds the Name Service Switch module
nss_mdns: setup $(BUILDDIR)/$(NSSLIBFILE)
@echo "Name Service Switch module done"
$(BUILDDIR)/$(NSSLIBFILE): $(CLIENTLIBOBJS) $(OBJDIR)/nss_mdns.c.so.o
- @$(LD) $(LINKOPTS) -o $@ $+
- @$(STRIP) $@
+ $(LD) $(SOOPTS) $(LINKOPTS) -o $@ $+
+ $(STRIP) $@
#############################################################################
# Note: If daemon already installed, we make sure it's stopped before overwriting it
$(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME)
- @if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi
+ if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi
$(CP) $< $@
- @$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) start
+ $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) start
$(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
$(CP) $< $@
$(LN) $@ $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX)
ifdef LDCONFIG
- # -m means 'merge into existing database', -R means 'rescan directories'
+ # -m means 'merge into existing database', -R means 'rescan directories'
$(LDCONFIG) -mR
endif
/etc/nss_mdns.conf: nss_mdns.conf
$(CP) $< $@
chmod 444 $@
- # Check the nsswitch.conf file.
- # If 'mdns' does not already appear on the "hosts:" line, then add it right before 'dns'
+# Check the nsswitch.conf file.
+# If 'mdns' does not already appear on the "hosts:" line, then add it right before 'dns'
cp -f /etc/nsswitch.conf /etc/nsswitch.conf.pre-mdns
sed -e '/mdns/!s/^\(hosts:.*\)dns\(.*\)/\1mdns dns\2/' /etc/nsswitch.conf.pre-mdns > /etc/nsswitch.conf
JAVAH = $(JDK)/bin/javah
JAVADOC = $(JDK)/bin/javadoc
JAR = $(JDK)/bin/jar
-JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS) -I$(JDK)/include
+JAVACFLAGS = $(MDNSCFLAGS) $(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) $< $@
# The following targets build embedded example programs
SPECIALOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/GenLinkedList.c.o \
$(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/PlatformCommon.c.o \
- $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/anonymous.c.o
+ $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/dso.c.o $(OBJDIR)/dso-transport.c.o $(OBJDIR)/dnssd_clientshim.c.o
COMMONOBJ = $(SPECIALOBJ) $(OBJDIR)/mDNS.c.o
APPOBJ = $(COMMONOBJ) $(OBJDIR)/ExampleClientApp.c.o
SAProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
@echo "Embedded Standalone ProxyResponder done"
-Identify: setup $(BUILDDIR)/mDNSIdentify
- @echo "Identify done"
-
NetMonitor: setup $(BUILDDIR)/mDNSNetMonitor
@echo "NetMonitor done"
$(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ) $(OBJDIR)/ProxyResponder.c.o
$(CC) $+ -o $@ $(LINKOPTS)
-$(BUILDDIR)/mDNSIdentify: $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
- $(CC) $+ -o $@ $(LINKOPTS)
-
-$(OBJDIR)/Identify.c.o: $(COREDIR)/mDNS.c # Note: Identify.c textually imports mDNS.c
-
$(BUILDDIR)/mDNSNetMonitor: $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o
$(CC) $+ -o $@ $(LINKOPTS)
# Implicit rules
$(OBJDIR)/%.c.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
+ $(CC) $(MDNSCFLAGS) -c -o $@ $<
$(OBJDIR)/%.c.o: $(COREDIR)/%.c
- $(CC) $(CFLAGS) -c -o $@ $<
+ $(CC) $(MDNSCFLAGS) -c -o $@ $<
$(OBJDIR)/%.c.o: $(SHAREDDIR)/%.c
- $(CC) $(CFLAGS) -c -o $@ $<
+ $(CC) $(MDNSCFLAGS) -c -o $@ $<
+
+$(OBJDIR)/%.c.o: $(DSODIR)/%.c
+ $(CC) $(MDNSCFLAGS) -c -o $@ $<
$(OBJDIR)/%.c.threadsafe.o: %.c
- $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+ $(CC) $(MDNSCFLAGS) $(MDNSCFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
$(OBJDIR)/%.c.threadsafe.o: $(SHAREDDIR)/%.c
- $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+ $(CC) $(MDNSCFLAGS) $(MDNSCFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
$(OBJDIR)/%.c.so.o: %.c
- $(CC) $(CFLAGS) -c -fPIC -o $@ $<
+ $(CC) $(MDNSCFLAGS) -c -fPIC -o $@ $<
$(OBJDIR)/%.c.so.o: $(SHAREDDIR)/%.c
- $(CC) $(CFLAGS) -c -fPIC -o $@ $<
+ $(CC) $(MDNSCFLAGS) -c -fPIC -o $@ $<
$(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y
$(BISON) -o $(OBJDIR)/$*.c -d $<
- $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/$*.c
+ $(CC) $(MDNSCFLAGS) -c -o $@ $(OBJDIR)/$*.c
$(OBJDIR)/%.l.o: $(SHAREDDIR)/%.l
$(FLEX) $(FLEXFLAGS_OS) -i -o$(OBJDIR)/$*.l.c $<
- $(CC) $(CFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
+ $(CC) $(MDNSCFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
InterfaceID = mDNSInterface_Any; // Send query from our unicast reply socket
}
- mDNSSendDNSMessage(m, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+ mDNSSendDNSMessage(m, &query, qptr, InterfaceID, mDNSNULL, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSfalse);
}
mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
// Perhaps more (or all?) of the cases should do that?
switch(pktrr->rrtype)
{
- case kDNSType_A: n += mprintf("%.4a", &rd->ipv4); break;
- case kDNSType_PTR: n += mprintf("%##.*s", MaxWidth - n, rd->name.c); break;
+ case kDNSType_A: mprintf("%.4a", &rd->ipv4); break;
+ case kDNSType_PTR: mprintf("%##.*s", MaxWidth - n, rd->name.c); break;
case kDNSType_HINFO: // same as kDNSType_TXT below
case kDNSType_TXT: {
mDNSu8 *t = rd->txt.c;
if (t < rdend && t[0]) { *p++ = '\\'; *p++ = ' '; }
}
*p++ = 0;
- n += mprintf("%.*s", MaxWidth - n, buffer);
+ mprintf("%.*s", MaxWidth - n, buffer);
} 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_AAAA: mprintf("%.16a", &rd->ipv6); break;
+ case kDNSType_SRV: mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break;
case kDNSType_OPT: {
char b[MaxMsg];
// Quick hack: we don't want the prefix that GetRRDisplayString_rdb puts at the start of its
// length of that prefix and strip that many bytes off the beginning of the string we display.
mDNSu32 striplen = mDNS_snprintf(b, MaxMsg-1, "%4d %##s %s ", pktrr->rdlength, pktrr->name->c, DNSTypeName(pktrr->rrtype));
GetRRDisplayString_rdb(pktrr, &pktrr->rdata->u, b);
- n += mprintf("%.*s", MaxWidth - n, b + striplen);
+ mprintf("%.*s", MaxWidth - n, b + striplen);
} break;
case kDNSType_NSEC: {
char b[MaxMsg];
// See the quick hack above
mDNSu32 striplen = mDNS_snprintf(b, MaxMsg-1, "%4d %##s %s ", pktrr->rdlength, pktrr->name->c, DNSTypeName(pktrr->rrtype));
GetRRDisplayString_rdb(pktrr, &pktrr->rdata->u, b);
- n += mprintf("%s", b+striplen);
+ mprintf("%s", b+striplen);
} break;
default: {
mDNSu8 *s = rd->data;
s++;
}
*p++ = 0;
- n += mprintf("%.*s", MaxWidth - n, buffer);
+ mprintf("%.*s", MaxWidth - n, buffer);
} break;
}
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
#include <fcntl.h>
#include <pwd.h>
#include <sys/types.h>
+#include <sys/socket.h>
#if __APPLE__
#undef daemon
#include "mDNSUNP.h" // For daemon()
#include "uds_daemon.h"
#include "PlatformCommon.h"
+#include "posix_utilities.h" // For getLocalTimestamp()
#define CONFIG_FILE "/etc/mdnsd.conf"
static domainname DynDNSZone; // Default wide-area zone for service registration
mDNSlocal void DumpStateLog()
// Dump a little log of what we've been up to.
{
- LogMsg("---- BEGIN STATE LOG ----");
- udsserver_info();
- LogMsg("---- END STATE LOG ----");
+ char timestamp[64]; // 64 is enough to store the UTC timestmp
+
+ mDNSu32 major_version = _DNS_SD_H / 10000;
+ mDNSu32 minor_version1 = (_DNS_SD_H - major_version * 10000) / 100;
+ mDNSu32 minor_version2 = _DNS_SD_H % 100;
+
+ getLocalTimestamp(timestamp, sizeof(timestamp));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- BEGIN STATE LOG ---- (%s mDNSResponder Build %d.%02d.%02d)", timestamp, major_version, minor_version1, minor_version2);
+
+ udsserver_info_dump_to_fd(STDERR_FILENO);
+
+ getLocalTimestamp(timestamp, sizeof(timestamp));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- END STATE LOG ---- (%s mDNSResponder Build %d.%02d.%02d)", timestamp, major_version, minor_version1, minor_version2);
}
mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
{
const struct passwd *pw = getpwnam("nobody");
if (pw != NULL)
- setuid(pw->pw_uid);
+ {
+ if (setgid(pw->pw_gid) < 0)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "WARNING: mdnsd continuing as group root because setgid to \"nobody\" failed with " PUB_S, strerror(errno));
+ }
+ if (setuid(pw->pw_uid) < 0)
+ {
+ LogMsg("WARNING: mdnsd continuing as root because setuid to \"nobody\" failed with %s", strerror(errno));
+ }
+ }
else
+ {
LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
+ }
}
if (mStatus_NoError == err)
LogMsg("ExitCallback: udsserver_exit failed");
#if MDNS_DEBUGMSGS > 0
- printf("mDNSResponder exiting normally with %ld\n", err);
+ printf("mDNSResponder exiting normally with %d\n", err);
#endif
return err;
//*************************************************************************************************************
// Globals
-static mDNS mDNSStorage; // mDNS core uses this to store its globals
+mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
mDNSexport const char ProgramName[] = "mDNSProxyResponderPosix";
#include <errno.h> // For errno, EINTR
#include <signal.h>
#include <fcntl.h>
+#include <sys/socket.h>
#if __APPLE__
#undef daemon
#pragma mark ***** Globals
#endif
-static mDNS mDNSStorage; // mDNS core uses this to store its globals
+mDNS mDNSStorage; // mDNS core uses this to store its globals
static mDNS_PlatformSupport PlatformStorage; // Stores this platform's globals
mDNSexport const char ProgramName[] = "mDNSResponderPosix";
domainname domain;
status = mStatus_NoError;
- thisServ = (PosixService *) malloc(sizeof(*thisServ));
+ thisServ = (PosixService *) calloc(sizeof(*thisServ), 1);
if (thisServ == NULL) {
status = mStatus_NoMemoryErr;
}
static void DeregisterOurServices(void)
{
PosixService *thisServ;
- int thisServID;
while (gServiceList != NULL) {
thisServ = gServiceList;
gServiceList = thisServ->next;
- thisServID = thisServ->serviceID;
-
mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
if (gMDNSPlatformPosixVerboseLevel > 0) {
while (!gStopNow)
{
int nfds = 0;
- fd_set readfds;
+ fd_set readfds, writefds;
struct timeval timeout;
int result;
// This example client has no file descriptors of its own,
// but a real application would call FD_SET to add them to the set here
FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
// 2. Set up the timeout.
// This example client has no other work it needs to be doing,
timeout.tv_usec = 0;
// 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
- mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
+ mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &writefds, &timeout);
// 4. Call select as normal
verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
else
{
// 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
- mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
+ mDNSPosixProcessFDSet(&mDNSStorage, &readfds, &writefds);
// 6. This example client has no other work it needs to be doing,
// but a real client would do its work here
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
#include "mDNSEmbeddedAPI.h" // Defines the interface provided to the client layer above
#include "DNSCommon.h"
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
+#include "PlatformCommon.h"
#include "dns_sd.h"
#include "dnssec.h"
#include "nsec.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h> // platform support for UTC time
+#include <ifaddrs.h>
#if USES_NETLINK
#include <asm/types.h>
// ***************************************************************************
// Structures
-// We keep a list of client-supplied event sources in PosixEventSource records
-struct PosixEventSource
-{
- mDNSPosixEventCallback Callback;
- void *Context;
- int fd;
- struct PosixEventSource *Next;
-};
-typedef struct PosixEventSource PosixEventSource;
-
// Context record for interface change callback
struct IfChangeRec
{
typedef struct IfChangeRec IfChangeRec;
// Note that static data is initialized to zero in (modern) C.
-static fd_set gEventFDs;
-static int gMaxFD; // largest fd in gEventFDs
-static GenLinkedList gEventSources; // linked list of PosixEventSource's
+static PosixEventSource *gEventSources; // linked list of PosixEventSource's
static sigset_t gEventSignalSet; // Signals which event loop listens for
static sigset_t gEventSignals; // Signals which were received while inside loop
static int num_pkts_accepted = 0;
static int num_pkts_rejected = 0;
+// ***************************************************************************
+// Locals
+mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context);
+mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeSource, mDNSBool removeSource, int flags);
+mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context);
// ***************************************************************************
// Functions
+#if MDNS_MALLOC_DEBUGGING
+mDNSexport void mDNSPlatformValidateLists(void)
+{
+ // This should validate gEventSources and any other Posix-specific stuff that gets allocated.
+}
+#endif
+
int gMDNSPlatformPosixVerboseLevel = 0;
#define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
return PosixErrorToStatus(err);
}
+mDNSlocal void TCPReadCallback(int fd, void *context)
+{
+ TCPSocket *sock = context;
+ (void)fd;
+
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+ // implement
+ }
+ else
+ {
+ sock->callback(sock, sock->context, mDNSfalse, sock->err);
+ }
+}
+
+mDNSlocal void tcpConnectCallback(int fd, void *context)
+{
+ TCPSocket *sock = context;
+ mDNSBool c = !sock->connected;
+ int result;
+ socklen_t len = sizeof result;
+
+ sock->connected = mDNStrue;
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
+ {
+ LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
+ sock->events.fd, result, strerror(result));
+ sock->err = mStatus_ConnFailed;
+ }
+ else
+ {
+ if (result != 0)
+ {
+ sock->err = mStatus_ConnFailed;
+ if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
+ {
+ LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+ sock->events.fd, result, strerror(result));
+ }
+ else
+ {
+ LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+ sock->events.fd, result, strerror(result));
+ }
+ }
+ else
+ {
+ // The connection succeeded.
+ sock->connected = mDNStrue;
+ // Select for read events.
+ sock->events.fd = fd;
+ requestReadEvents(&sock->events, "mDNSPosix::tcpConnectCallback", TCPReadCallback, sock);
+ }
+ }
+
+ if (sock->callback)
+ {
+ sock->callback(sock, sock->context, c, sock->err);
+ // Here sock must be assumed to be invalid, in case the callback freed it.
+ return;
+ }
+}
+
// This routine is called when the main loop detects that data is available on a socket.
mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
{
&senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
}
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrType, mDNSIPPort * port,
+ domainname *hostname, mDNSBool useBackgroundTrafficClass)
{
- (void)flags; // Unused
- (void)port; // Unused
- (void)useBackgroundTrafficClass; // Unused
- return NULL;
+ TCPSocket *sock;
+ int len = sizeof (TCPSocket);
+
+ (void)useBackgroundTrafficClass;
+
+ if (hostname)
+ {
+ len += sizeof (domainname);
+ }
+ sock = malloc(len);
+
+ if (sock == NULL)
+ {
+ LogMsg("mDNSPlatformTCPSocket: no memory for socket");
+ return NULL;
+ }
+ memset(sock, 0, sizeof *sock);
+
+ if (hostname)
+ {
+ sock->hostname = (domainname *)(sock + 1);
+ LogMsg("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
+ AssignDomainName(sock->hostname, hostname);
+ }
+
+ sock->events.fd = -1;
+ if (!mDNSPosixTCPSocketSetup(&sock->events.fd, addrType, port, &sock->port))
+ {
+ if (sock->events.fd != -1) close(sock->events.fd);
+ free(sock);
+ return mDNSNULL;
+ }
+
+ // Set up the other fields in the structure.
+ sock->flags = flags;
+ sock->err = mStatus_NoError;
+ sock->setup = mDNSfalse;
+ sock->connected = mDNSfalse;
+ return sock;
}
-mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
{
- (void)flags; // Unused
- (void)sd; // Unused
- return NULL;
+ sock->callback = callback;
+ sock->context = context;
+ return mStatus_NoError;
+}
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
+{
+ TCPSocket *sock;
+
+ // XXX Add!
+ if (flags & kTCPSocketFlags_UseTLS)
+ {
+ return mDNSNULL; // not supported yet.
+ }
+
+ sock = (TCPSocket *) mDNSPlatformMemAllocateClear(sizeof *sock);
+ if (!sock)
+ {
+ return mDNSNULL;
+ }
+
+ sock->events.fd = fd;
+ sock->flags = flags;
+ sock->connected = mDNStrue;
+ return sock;
+}
+
+
+mDNSlocal void tcpListenCallback(int fd, void *context)
+{
+ TCPListener *listener = context;
+ TCPSocket *sock;
+
+ sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
+ listener->callback, listener->context);
+ if (sock != NULL)
+ {
+ requestReadEvents(&sock->events, "mDNSPosix::tcpListenCallback", TCPReadCallback, sock);
+ }
+}
+
+mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrType, mDNSIPPort *port, mDNSAddr *addr,
+ TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+ TCPAcceptedCallback callback, void *context)
+{
+ TCPListener *ret;
+ int fd = -1;
+
+ if (!mDNSPosixTCPListen(&fd, addrType, port, addr, reuseAddr, queueLength))
+ {
+ if (fd != -1)
+ {
+ close(fd);
+ }
+ return mDNSNULL;
+ }
+
+ // Allocate a listener structure
+ ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
+ if (ret == NULL)
+ {
+ LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
+ close(fd);
+ return mDNSNULL;
+ }
+ ret->events.fd = fd;
+ ret->callback = callback;
+ ret->context = context;
+ ret->addressType = addrType;
+ ret->socketFlags = socketFlags;
+
+ // When we get a connection, mDNSPosixListenCallback will be called, and it will invoke the
+ // callback we were passed.
+ requestReadEvents(&ret->events, "tcpListenCallback", tcpListenCallback, ret);
+ return ret;
}
mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
{
- (void)sock; // Unused
- return -1;
+ return sock->events.fd;
}
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport,
+ mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
{
- (void)sock; // Unused
- (void)dst; // Unused
- (void)dstport; // Unused
- (void)hostname; // Unused
- (void)InterfaceID; // Unused
- (void)callback; // Unused
- (void)context; // Unused
- return(mStatus_UnsupportedErr);
+ int result;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ socklen_t len;
+
+ sock->callback = callback;
+ sock->context = context;
+ sock->setup = mDNSfalse;
+ sock->connected = mDNSfalse;
+ sock->err = mStatus_NoError;
+
+ result = fcntl(sock->events.fd, F_GETFL, 0);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: F_GETFL failed: %s", strerror(errno));
+ return mStatus_UnknownErr;
+ }
+
+ result = fcntl(sock->events.fd, F_SETFL, result | O_NONBLOCK);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: F_SETFL failed: %s", strerror(errno));
+ return mStatus_UnknownErr;
+ }
+
+ // If we've been asked to bind to a single interface, do it. See comment in mDNSMacOSX.c for more info.
+ if (InterfaceID)
+ {
+ PosixNetworkInterface *iface = (PosixNetworkInterface *)InterfaceID;
+#if defined(SO_BINDTODEVICE)
+ result = setsockopt(sock->events.fd,
+ SOL_SOCKET, SO_BINDTODEVICE, iface->intfName, strlen(iface->intfName));
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: SO_BINDTODEVICE failed on %s: %s", iface->intfName, strerror(errno));
+ return mStatus_BadParamErr;
+ }
+#else
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+#if defined(IP_BOUND_IF)
+ result = setsockopt(sock->events.fd, IPPROTO_IP, IP_BOUND_IF, &iface->index, sizeof iface->index);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
+ iface->intfName, iface->index, strerror(errno));
+ return mStatus_BadParamErr;
+ }
+#else
+ (void)iface;
+#endif // IP_BOUND_IF
+ }
+ else
+ { // IPv6
+#if defined(IPV6_BOUND_IF)
+ result = setsockopt(sock->events.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface->index, sizeof iface->index);
+ if (result < 0)
+ {
+ LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
+ iface->intfName, iface->index, strerror(errno));
+ return mStatus_BadParamErr;
+ }
+#else
+ (void)iface;
+#endif // IPV6_BOUND_IF
+ }
+#endif // SO_BINDTODEVICE
+ }
+
+ memset(&addr, 0, sizeof addr);
+ if (dst->type == mDNSAddrType_IPv4)
+ {
+ addr.sa.sa_family = AF_INET;
+ addr.sin.sin_port = dstport.NotAnInteger;
+ len = sizeof (struct sockaddr_in);
+ addr.sin.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+ }
+ else
+ {
+ addr.sa.sa_family = AF_INET6;
+ len = sizeof (struct sockaddr_in6);
+ addr.sin6.sin6_port = dstport.NotAnInteger;
+ memcpy(&addr.sin6.sin6_addr.s6_addr, &dst->ip.v6, sizeof addr.sin6.sin6_addr.s6_addr);
+ }
+#ifndef NOT_HAVE_SA_LEN
+ addr.sa.sa_len = len;
+#endif
+
+ result = connect(sock->events.fd, (struct sockaddr *)&addr, len);
+ if (result < 0)
+ {
+ if (errno == EINPROGRESS)
+ {
+ requestWriteEvents(&sock->events, "mDNSPlatformConnect", tcpConnectCallback, sock);
+ return mStatus_ConnPending;
+ }
+ if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+ {
+ LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)",
+ sock->events.fd, errno, strerror(errno));
+ }
+ else
+ {
+ LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d",
+ sock->events.fd, errno, strerror(errno), len);
+ }
+ return mStatus_ConnFailed;
+ }
+
+ LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+ return mStatus_NoError;
}
mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
{
- (void)sock; // Unused
+ if (sock)
+ { // can sock really be NULL when this is called?
+ shutdown(sock->events.fd, SHUT_RDWR);
+ stopReadOrWriteEvents(sock->events.fd, mDNSfalse, mDNStrue,
+ PosixEventFlag_Read | PosixEventFlag_Write);
+ close(sock->events.fd);
+ free(sock);
+ }
}
mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
{
- (void)sock; // Unused
- (void)buf; // Unused
- (void)buflen; // Unused
- (void)closed; // Unused
- return 0;
+ ssize_t nread;
+
+ *closed = mDNSfalse;
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+ // Implement...
+ nread = -1;
+ *closed = mDNStrue;
+ } else {
+ nread = mDNSPosixReadTCP(sock->events.fd, buf, buflen, closed);
+ }
+ return nread;
+}
+
+mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
+{
+ fd_set w;
+ int nfds = sock->events.fd + 1;
+ int count;
+ struct timeval tv;
+
+ if (nfds > FD_SETSIZE)
+ {
+ LogMsg("ERROR: mDNSPlatformTCPWritable called on an fd that won't fit in an fd_set.");
+ return mDNStrue; // hope for the best?
+ }
+ FD_SET(sock->events.fd, &w);
+ tv.tv_sec = tv.tv_usec = 0;
+ count = select(nfds, NULL, &w, NULL, &tv);
+ if (count > 0)
+ {
+ return mDNStrue;
+ }
+ return mDNSfalse;
}
mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
{
- (void)sock; // Unused
- (void)msg; // Unused
- (void)len; // Unused
- return 0;
+ if (sock->flags & kTCPSocketFlags_UseTLS)
+ {
+ // implement
+ return -1;
+ }
+ else
+ {
+ return mDNSPosixWriteTCP(sock->events.fd, msg, len);
+ }
}
mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
DNameListElem **BrowseDomains, mDNSBool ackConfig)
{
(void) setservers;
- (void) fqdn;
(void) setsearch;
- (void) RegDomains;
- (void) BrowseDomains;
(void) ackConfig;
+ if (fqdn ) fqdn->c[0] = 0;
+ if (RegDomains ) *RegDomains = NULL;
+ if (BrowseDomains) *BrowseDomains = NULL;
+
return mDNStrue;
}
mDNSAddr DNSAddr;
DNSAddr.type = mDNSAddrType_IPv4;
DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
- mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+ mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
numOfServers++;
}
}
- fclose(fp);
+ fclose(fp);
return (numOfServers > 0) ? 0 : -1;
}
// ... with a shared UDP port, if it's for multicast receiving
if (err == 0 && port.NotAnInteger)
{
- // <rdar://problem/20946253>
+ // <rdar://problem/20946253> Suggestions from Jonny Törnbom at Axis Communications
// We test for SO_REUSEADDR first, as suggested by Jonny Törnbom from Axis Communications
// Linux kernel versions 3.9 introduces support for socket option
// SO_REUSEPORT, however this is not implemented the same as on *BSD
#endif
if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
+#if TARGET_OS_MAC
// Enable inbound packets on IFEF_AWDL interface.
// Only done for multicast sockets, since we don't expect unicast socket operations
// on the IFEF_AWDL interface. Operation is a no-op for other interface types.
#define SO_RECV_ANYIF 0x1104 /* unrestricted inbound processing */
#endif
if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
+#endif
}
// We want to receive destination addresses and interface identifiers.
// And make a copy of the intfName.
if (err == 0)
{
+#ifdef LINUX
+ char *s;
+ int len;
+ s = strchr(intfName, ':');
+ if (s != NULL)
+ {
+ len = (s - intfName) + 1;
+ }
+ else
+ {
+ len = strlen(intfName) + 1;
+ }
+ intf->intfName = malloc(len);
+ if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+ memcpy(intf->intfName, intfName, len - 1);
+ intfName[len - 1] = 0;
+#else
intf->intfName = strdup(intfName);
if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+#endif
}
if (err == 0)
//LogMsg("SetupOneInterface: %#a %#a", &intf->coreIntf.ip, &intf->coreIntf.mask);
strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
+
intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
intf->coreIntf.McastTxRx = mDNStrue;
{
mDNSBool foundav4 = mDNSfalse;
int err = 0;
- struct ifi_info *intfList = get_ifi_info(AF_INET, mDNStrue);
- struct ifi_info *firstLoopback = NULL;
+ struct ifaddrs *intfList;
+ struct ifaddrs *firstLoopback = NULL;
+ int firstLoopbackIndex = 0;
assert(m != NULL);
debugf("SetupInterfaceList");
- if (intfList == NULL) err = ENOENT;
-
-#if HAVE_IPV6
- if (err == 0) /* Link the IPv6 list to the end of the IPv4 list */
+ if (getifaddrs(&intfList) < 0)
{
- struct ifi_info **p = &intfList;
- while (*p) p = &(*p)->ifi_next;
- *p = get_ifi_info(AF_INET6, mDNStrue);
+ err = errno;
}
-#endif
+ if (intfList == NULL) err = ENOENT;
if (err == 0)
{
- struct ifi_info *i = intfList;
+ struct ifaddrs *i = intfList;
while (i)
{
- if ( ((i->ifi_addr->sa_family == AF_INET)
+ if ( ((i->ifa_addr->sa_family == AF_INET)
#if HAVE_IPV6
- || (i->ifi_addr->sa_family == AF_INET6)
+ || (i->ifa_addr->sa_family == AF_INET6)
#endif
- ) && (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
+ ) && (i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_POINTOPOINT))
{
- if (i->ifi_flags & IFF_LOOPBACK)
+ int ifIndex = if_nametoindex(i->ifa_name);
+ if (ifIndex == 0)
+ {
+ continue;
+ }
+ if (i->ifa_flags & IFF_LOOPBACK)
{
if (firstLoopback == NULL)
+ {
firstLoopback = i;
+ firstLoopbackIndex = ifIndex;
+ }
}
else
{
- if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
- if (i->ifi_addr->sa_family == AF_INET)
+ if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
+ {
+ if (i->ifa_addr->sa_family == AF_INET)
+ {
foundav4 = mDNStrue;
+ }
+ }
}
}
- i = i->ifi_next;
+ i = i->ifa_next;
}
// If we found no normal interfaces but we did find a loopback interface, register the
// In the interim, we skip loopback interface only if we found at least one v4 interface to use
// if ((m->HostInterfaces == NULL) && (firstLoopback != NULL))
if (!foundav4 && firstLoopback)
- (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
+ {
+ (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
+ firstLoopbackIndex);
+ }
}
// Clean up.
- if (intfList != NULL) free_ifi_info(intfList);
+ if (intfList != NULL) freeifaddrs(intfList);
// Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
PosixNetworkInterface **ri = &gRecentInterfaces;
#endif // USES_NETLINK
// Called when data appears on interface change notification socket
-mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
+mDNSlocal void InterfaceChangeCallback(int fd, void *context)
{
IfChangeRec *pChgRec = (IfChangeRec*) context;
fd_set readFDs;
struct timeval zeroTimeout = { 0, 0 };
(void)fd; // Unused
- (void)filter; // Unused
FD_ZERO(&readFDs);
FD_SET(pChgRec->NotifySD, &readFDs);
mStatus err;
IfChangeRec *pChgRec;
- pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
+ pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
if (pChgRec == NULL)
return mStatus_NoMemoryErr;
err = OpenIfNotifySocket(&pChgRec->NotifySD);
if (err == 0)
err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+ if (err)
+ mDNSPlatformMemFree(pChgRec);
return err;
}
#pragma mark ***** Strings
#endif
-// mDNS core calls this routine to copy C strings.
-// On the Posix platform this maps directly to the ANSI C strcpy.
-mDNSexport void mDNSPlatformStrCopy(void *dst, const void *src)
-{
- strcpy((char *)dst, (const char *)src);
-}
-
mDNSexport mDNSu32 mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
{
#if HAVE_STRLCPY
// mDNS core calls this routine to clear blocks of memory.
// On the Posix platform this is a simple wrapper around ANSI C memset.
-mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
+mDNSexport void mDNSPlatformMemZero(void *dst, mDNSu32 len)
{
memset(dst, 0, len);
}
-mDNSexport void * mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
-mDNSexport void * mDNSPlatformMemAllocateClear(mDNSu32 len) { return(calloc(1, len)); }
-mDNSexport void mDNSPlatformMemFree (void *mem) { free(mem); }
+#if !MDNS_MALLOC_DEBUGGING
+mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
+mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
+mDNSexport void mDNSPlatformMemFree (void *mem) { freeL("mDNSPlatformMemFree", mem); }
+#endif
#if _PLATFORM_HAS_STRONG_PRNG_
mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
{
- return(arc4random());
+ return(arc4random());
}
#else
mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
mDNSexport mDNSs32 mDNSPlatformRawTime()
{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
- // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
- // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
- // and we multiply tv.tv_usec by 16 / 15625 to get a value in the range 0-1023 to go in the bottom 10 bits.
+ struct timespec tm;
+ int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
+ assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
+
+ // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
+ // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
+ // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
+ // and we multiply tm.tv_nsec by 2 / 1953125 to get a value in the range 0-1023 to go in the bottom 10 bits.
// This gives us a proper modular (cyclic) counter that has a resolution of roughly 1ms (actually 1/1024 second)
// and correctly cycles every 2^22 seconds (4194304 seconds = approx 48 days).
- return((tv.tv_sec << 10) | (tv.tv_usec * 16 / 15625));
+
+ return ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
}
mDNSexport mDNSs32 mDNSPlatformUTC(void)
FD_SET(s, readfds);
}
-mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
+mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
{
- mDNSs32 ticks;
- struct timeval interval;
-
- // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
- mDNSs32 nextevent = mDNS_Execute(m);
+ int numFDs = *nfds;
+ PosixEventSource *iSource;
// 2. Build our list of active file descriptors
PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
- if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
+ if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
#if HAVE_IPV6
- if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
+ if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
#endif
while (info)
{
- if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
+ if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
#if HAVE_IPV6
- if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
+ if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
#endif
info = (PosixNetworkInterface *)(info->coreIntf.next);
}
+ // Copy over the event fds. We have to do it this way because client-provided event loops expect
+ // to initialize their FD sets first and then call mDNSPosixGetFDSet()
+ for (iSource = gEventSources; iSource; iSource = iSource->next)
+ {
+ if (iSource->readCallback != NULL)
+ FD_SET(iSource->fd, readfds);
+ if (iSource->writeCallback != NULL)
+ FD_SET(iSource->fd, writefds);
+ if (numFDs <= iSource->fd)
+ numFDs = iSource->fd + 1;
+ }
+ *nfds = numFDs;
+}
+
+mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
+{
+ mDNSs32 ticks;
+ struct timeval interval;
+
+ // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
+ mDNSs32 nextevent = mDNS_Execute(m);
+
// 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
ticks = nextevent - mDNS_TimeNow(m);
if (ticks < 1) ticks = 1;
*timeout = interval;
}
-mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
+mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
+{
+ mDNSPosixGetNextDNSEventTime(m, timeout);
+ mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
+}
+
+mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
{
PosixNetworkInterface *info;
+ PosixEventSource *iSource;
assert(m != NULL);
assert(readfds != NULL);
info = (PosixNetworkInterface *)(m->HostInterfaces);
#endif
info = (PosixNetworkInterface *)(info->coreIntf.next);
}
-}
-
-// update gMaxFD
-mDNSlocal void DetermineMaxEventFD(void)
-{
- PosixEventSource *iSource;
- gMaxFD = 0;
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- if (gMaxFD < iSource->fd)
- gMaxFD = iSource->fd;
+ // Now process routing socket events, discovery relay events and anything else of that ilk.
+ for (iSource = gEventSources; iSource; iSource = iSource->next)
+ {
+ if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
+ {
+ iSource->readCallback(iSource->fd, iSource->readContext);
+ break; // in case callback removed elements from gEventSources
+ }
+ else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
+ {
+ mDNSPosixEventCallback writeCallback = iSource->writeCallback;
+ // Write events are one-shot: to get another event, the consumer has to put in a new request.
+ // We reset this before calling the callback just in case the callback requests another write
+ // callback, or deletes the event context from the list.
+ iSource->writeCallback = NULL;
+ writeCallback(iSource->fd, iSource->writeContext);
+ break; // in case callback removed elements from gEventSources
+ }
+ }
}
-// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
-{
- PosixEventSource *newSource;
+mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
- if (gEventSources.LinkOffset == 0)
- InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
+mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
+ mDNSPosixEventCallback callback, void *context, int flag)
+{
+ PosixEventSource **epp = &gEventSources;
- if (fd >= (int) FD_SETSIZE || fd < 0)
- return mStatus_UnsupportedErr;
+ if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
+ {
+ LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
+ assert(0);
+ }
if (callback == NULL)
- return mStatus_BadParamErr;
-
- newSource = (PosixEventSource*) malloc(sizeof *newSource);
- if (NULL == newSource)
- return mStatus_NoMemoryErr;
+ {
+ LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
+ assert(0);
+ }
- newSource->Callback = callback;
- newSource->Context = context;
- newSource->fd = fd;
+ // See if this event context is already on the list; if it is, no need to scan the list.
+ if (!(newSource->flags & PosixEventFlag_OnList))
+ {
+ while (*epp)
+ {
+ // This should never happen.
+ if (newSource == *epp)
+ {
+ LogMsg("Event context marked not on list but is on list.");
+ assert(0);
+ }
+ epp = &(*epp)->next;
+ }
+ if (*epp == NULL)
+ {
+ *epp = newSource;
+ newSource->next = NULL;
+ newSource->flags = PosixEventFlag_OnList;
+ }
+ }
- AddToTail(&gEventSources, newSource);
- FD_SET(fd, &gEventFDs);
+ if (flag & PosixEventFlag_Read)
+ {
+ newSource->readCallback = callback;
+ newSource->readContext = context;
+ newSource->flags |= PosixEventFlag_Read;
+ newSource->readTaskName = taskName;
+ }
+ if (flag & PosixEventFlag_Write)
+ {
+ newSource->writeCallback = callback;
+ newSource->writeContext = context;
+ newSource->flags |= PosixEventFlag_Write;
+ newSource->writeTaskName = taskName;
+ }
+}
- DetermineMaxEventFD();
+mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context)
+{
+ requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
+}
- return mStatus_NoError;
+mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
+ const char *taskName, mDNSPosixEventCallback callback, void *context)
+{
+ requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
}
// Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
{
- PosixEventSource *iSource;
+ PosixEventSource *iSource, **epp = &gEventSources;
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+ while (*epp)
{
+ iSource = *epp;
if (fd == iSource->fd)
{
- FD_CLR(fd, &gEventFDs);
- RemoveFromList(&gEventSources, iSource);
- free(iSource);
- DetermineMaxEventFD();
+ if (flags & PosixEventFlag_Read)
+ {
+ iSource->readCallback = NULL;
+ iSource->readContext = NULL;
+ }
+ if (flags & PosixEventFlag_Write)
+ {
+ iSource->writeCallback = NULL;
+ iSource->writeContext = NULL;
+ }
+ if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
+ {
+ if (removeContext || freeContext)
+ *epp = iSource->next;
+ if (freeContext)
+ free(iSource);
+ }
return mStatus_NoError;
}
+ epp = &(*epp)->next;
}
return mStatus_NoSuchNameErr;
}
+// Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
+// providing storage for the event-related info. mDNSPosixAddFDToEventLoop and
+// mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
+mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
+{
+ PosixEventSource *newSource;
+
+ newSource = (PosixEventSource*) malloc(sizeof *newSource);
+ if (NULL == newSource)
+ return mStatus_NoMemoryErr;
+ memset(newSource, 0, sizeof *newSource);
+ newSource->fd = fd;
+
+ requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
+ return mStatus_NoError;
+}
+
+mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+{
+ return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
+}
+
// Simply note the received signal in gEventSignals.
mDNSlocal void NoteSignal(int signum)
{
mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
{
- fd_set listenFDs = gEventFDs;
- int fdMax = 0, numReady;
+ fd_set listenFDs;
+ fd_set writeFDs;
+ int numFDs = 0, numReady;
struct timeval timeout = *pTimeout;
- // Include the sockets that are listening to the wire in our select() set
- mDNSPosixGetFDSet(m, &fdMax, &listenFDs, &timeout); // timeout may get modified
- if (fdMax < gMaxFD)
- fdMax = gMaxFD;
+ // 1. Set up the fd_set as usual here.
+ // This example client has no file descriptors of its own,
+ // but a real application would call FD_SET to add them to the set here
+ FD_ZERO(&listenFDs);
+ FD_ZERO(&writeFDs);
+
+ // 2. Set up the timeout.
+ mDNSPosixGetNextDNSEventTime(m, &timeout);
- numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
+ // Include the sockets that are listening to the wire in our select() set
+ mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
+ numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
- // If any data appeared, invoke its callback
if (numReady > 0)
{
- PosixEventSource *iSource;
-
- (void) mDNSPosixProcessFDSet(m, &listenFDs); // call this first to process wire data for clients
-
- for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
- {
- if (FD_ISSET(iSource->fd, &listenFDs))
- {
- iSource->Callback(iSource->fd, 0, iSource->Context);
- break; // in case callback removed elements from gEventSources
- }
- }
+ mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
*pDataDispatched = mDNStrue;
}
+ else if (numReady < 0)
+ {
+ if (errno != EINTR) {
+ // This should never happen, represents a coding error, and is not recoverable, since
+ // we'll just sit here spinning and never receive another event. The usual reason for
+ // it to happen is that an FD was closed but not removed from the event list.
+ LogMsg("select failed: %s", strerror(errno));
+ abort();
+ }
+ }
else
*pDataDispatched = mDNSfalse;
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
struct PosixNetworkInterface
{
- NetworkInterfaceInfo coreIntf; // MUST be the first element in this structure
+ NetworkInterfaceInfo coreIntf; // MUST be the first element in this structure
mDNSs32 LastSeen;
const char * intfName;
PosixNetworkInterface * aliasIntf;
#endif
};
+// We keep a list of client-supplied event sources in PosixEventSource records
+// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
+#define PosixEventFlag_OnList 1
+#define PosixEventFlag_Read 2
+#define PosixEventFlag_Write 4
+
+typedef void (*mDNSPosixEventCallback)(int fd, void *context);
+struct PosixEventSource
+{
+ struct PosixEventSource *next;
+ mDNSPosixEventCallback readCallback;
+ mDNSPosixEventCallback writeCallback;
+ const char *readTaskName;
+ const char *writeTaskName;
+ void *readContext;
+ void *writeContext;
+ int fd;
+ unsigned flags;
+};
+typedef struct PosixEventSource PosixEventSource;
+
+struct TCPSocket_struct
+{
+ mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with mDNSIPPort
+ TCPSocketFlags flags; // MUST BE SECOND FIELD -- mDNSCore expects every TCPSocket_struct have TCPSocketFlags flags after mDNSIPPort
+ TCPConnectionCallback callback;
+ PosixEventSource events;
+ // SSL context goes here.
+ domainname *hostname;
+ mDNSAddr remoteAddress;
+ mDNSIPPort remotePort;
+ void *context;
+ mDNSBool setup;
+ mDNSBool connected;
+ mStatus err;
+};
+
+struct TCPListener_struct
+{
+ TCPAcceptedCallback callback;
+ PosixEventSource events;
+ void *context;
+ mDNSAddr_Type addressType;
+ TCPSocketFlags socketFlags;
+};
+
#define uDNS_SERVERS_FILE "/etc/resolv.conf"
extern int ParseDNSServers(mDNS *m, const char *filePath);
extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
// See comment in implementation.
+// Get the next upcoming mDNS (or DNS) event time as a posix timeval that can be passed to select.
+// This will only update timeout if the next mDNS event is sooner than the value that was passed.
+// Therefore, use { FutureTime, 0 } as an initializer if no other timer events are being managed.
+extern void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout);
+
+// Returns all the FDs that the posix I/O event system expects to be passed to select.
+extern void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds);
+
// Call mDNSPosixGetFDSet before calling select(), to update the parameters
// as may be necessary to meet the needs of the mDNSCore code.
// The timeout pointer MUST NOT be NULL.
// Set timeout->tv_sec to FutureTime if you want to have effectively no timeout
// After calling mDNSPosixGetFDSet(), call select(nfds, &readfds, NULL, NULL, &timeout); as usual
// After select() returns, call mDNSPosixProcessFDSet() to let mDNSCore do its work
-extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
-extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
+// mDNSPosixGetFDSet simply calls mDNSPosixGetNextDNSEventTime and then mDNSPosixGetFDSetForSelect.
+extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout);
-typedef void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
+
+extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds);
extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
+extern mStatus mDNSPosixListenForSignalInEventLoop( int signum);
+extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
+extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
+
#ifdef __cplusplus
}
#endif
#include NEED_ALIGN_MACRO
#endif
-/* Solaris defined SIOCGIFCONF etc in <sys/sockio.h> but
- other platforms don't even have that include file. So,
- if we haven't yet got a definition, let's try to find
- <sys/sockio.h>.
- */
-
-#ifndef SIOCGIFCONF
- #include <sys/sockio.h>
-#endif
-
/* sockaddr_dl is only referenced if we're using IP_RECVIF,
so only include the header in that case.
*/
#include <net/if_dl.h>
#endif
-#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
-#include <net/if_var.h>
-#include <netinet/in_var.h>
-// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-#include <netdb.h>
-#include <arpa/inet.h>
-
-/* Converts a prefix length to IPv6 network mask */
-void plen_to_mask(int plen, char *addr) {
- int i;
- int colons=7; /* Number of colons in IPv6 address */
- int bits_in_block=16; /* Bits per IPv6 block */
- for(i=0; i<=colons; i++) {
- int block, ones=0xffff, ones_in_block;
- if (plen>bits_in_block) ones_in_block=bits_in_block;
- else ones_in_block=plen;
- block = ones & (ones << (bits_in_block-ones_in_block));
- i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
- plen -= ones_in_block;
- }
-}
-
-/* Gets IPv6 interface information from the /proc filesystem in linux*/
-struct ifi_info *get_ifi_info_linuxv6(int doaliases)
-{
- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
- FILE *fp = NULL;
- int i, nitems, flags, index, plen, scope;
- struct addrinfo hints, *res0;
- int err;
- int sockfd = -1;
- struct ifreq ifr;
- char ifnameFmt[16], addrStr[32 + 7 + 1], ifname[IFNAMSIZ], lastname[IFNAMSIZ];
-
- res0=NULL;
- ifihead = NULL;
- ifipnext = &ifihead;
-
- if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
- sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- goto gotError;
- }
-
- // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>.
-
- // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The
- // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width
- // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For
- // example, it could be defined in hexadecimal or as an arithmetic expression.
-
- snprintf(ifnameFmt, sizeof(ifnameFmt), "%%%ds", IFNAMSIZ - 1);
-
- // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx".
- // The remaining 32 IPv6 address characters come from /proc/net/if_inet6.
-
- for (i = 4; i < 39; i += 5) addrStr[i] = ':';
- addrStr[39] = '\0';
-
- lastname[0] = '\0';
- for (;;) {
- nitems = fscanf(fp, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x",
- &addrStr[0], &addrStr[5], &addrStr[10], &addrStr[15],
- &addrStr[20], &addrStr[25], &addrStr[30], &addrStr[35],
- &index, &plen, &scope, &flags);
- if (nitems != 12) break;
-
- nitems = fscanf(fp, ifnameFmt, ifname);
- if (nitems != 1) break;
-
- if (strcmp(lastname, ifname) == 0) {
- if (doaliases == 0)
- continue; /* already processed this interface */
- }
- memcpy(lastname, ifname, IFNAMSIZ);
- ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
- if (ifi == NULL) {
- goto gotError;
- }
-
- ifipold = *ifipnext; /* need this later */
- ifiptr = ifipnext;
- *ifipnext = ifi; /* prev points to this new one */
- ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
-
- /* Add address of the interface */
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_INET6;
- hints.ai_flags = AI_NUMERICHOST;
- err = getaddrinfo(addrStr, NULL, &hints, &res0);
- if (err) {
- goto gotError;
- }
- ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_addr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
-
- /* Add netmask of the interface */
- char ipv6addr[INET6_ADDRSTRLEN];
- plen_to_mask(plen, ipv6addr);
- ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_netmask == NULL) {
- goto gotError;
- }
-
- ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=AF_INET6;
- ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
- inet_pton(AF_INET6, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
-
- /* Add interface name */
- memcpy(ifi->ifi_name, ifname, IFI_NAME);
-
- /* Add interface index */
- ifi->ifi_index = index;
-
- /* Add interface flags*/
- memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi->ifi_netmask);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
- ifi->ifi_flags = ifr.ifr_flags;
- freeaddrinfo(res0);
- res0=NULL;
- }
- }
- goto done;
-
-gotError:
- if (ifihead != NULL) {
- free_ifi_info(ifihead);
- ifihead = NULL;
- }
- if (res0 != NULL) {
- freeaddrinfo(res0);
- res0=NULL;
- }
-done:
- if (sockfd != -1) {
- int rv;
- rv = close(sockfd);
- assert(rv == 0);
- }
- if (fp != NULL) {
- fclose(fp);
- }
- return(ifihead); /* pointer to first structure in linked list */
-}
-#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-
-struct ifi_info *get_ifi_info(int family, int doaliases)
-{
- int junk;
- struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
- int sockfd, sockf6, len, lastlen, flags, myflags;
-#ifdef NOT_HAVE_IF_NAMETOINDEX
- int index = 200;
-#endif
- char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
- struct ifconf ifc;
- struct ifreq *ifr, ifrcopy;
- struct sockaddr_in *sinptr;
-
-#if defined(AF_INET6) && HAVE_IPV6
- struct sockaddr_in6 *sinptr6;
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
- if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
-#endif
-
- sockfd = -1;
- sockf6 = -1;
- buf = NULL;
- ifihead = NULL;
-
- sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sockfd < 0) {
- goto gotError;
- }
-
- lastlen = 0;
- len = 100 * sizeof(struct ifreq); /* initial buffer size guess */
- for ( ; ; ) {
- buf = (char*)malloc(len);
- if (buf == NULL) {
- goto gotError;
- }
- ifc.ifc_len = len;
- ifc.ifc_buf = buf;
- if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
- if (errno != EINVAL || lastlen != 0) {
- goto gotError;
- }
- } else {
- if (ifc.ifc_len == lastlen)
- break; /* success, len has not changed */
- lastlen = ifc.ifc_len;
- }
- len += 10 * sizeof(struct ifreq); /* increment */
- free(buf);
- }
- ifihead = NULL;
- ifipnext = &ifihead;
- lastname[0] = 0;
-/* end get_ifi_info1 */
-
-/* include get_ifi_info2 */
- for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
- ifr = (struct ifreq *) ptr;
-
- /* Advance to next one in buffer */
- if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
- ptr += sizeof(struct ifreq);
- else
- ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
-
-// fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
-
- if (ifr->ifr_addr.sa_family != family)
- continue; /* ignore if not desired address family */
-
- myflags = 0;
- if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL)
- *cptr = 0; /* replace colon will null */
- if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
- if (doaliases == 0)
- continue; /* already processed this interface */
- myflags = IFI_ALIAS;
- }
- memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
-
- ifrcopy = *ifr;
- if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
- goto gotError;
- }
-
- flags = ifrcopy.ifr_flags;
- if ((flags & IFF_UP) == 0)
- continue; /* ignore if interface not up */
-
- ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
- if (ifi == NULL) {
- goto gotError;
- }
- ifipold = *ifipnext; /* need this later */
- ifiptr = ifipnext;
- *ifipnext = ifi; /* prev points to this new one */
- ifipnext = &ifi->ifi_next; /* pointer to next one goes here */
-
- ifi->ifi_flags = flags; /* IFF_xxx values */
- ifi->ifi_myflags = myflags; /* IFI_xxx values */
-#ifndef NOT_HAVE_IF_NAMETOINDEX
- ifi->ifi_index = if_nametoindex(ifr->ifr_name);
-#else
- ifrcopy = *ifr;
-#ifdef SIOCGIFINDEX
- if ( 0 >= ioctl(sockfd, SIOCGIFINDEX, &ifrcopy))
- ifi->ifi_index = ifrcopy.ifr_index;
- else
-#endif
- ifi->ifi_index = index++; /* SIOCGIFINDEX is broken on Solaris 2.5ish, so fake it */
-#endif
- memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
- ifi->ifi_name[IFI_NAME-1] = '\0';
-/* end get_ifi_info2 */
-/* include get_ifi_info3 */
- switch (ifr->ifr_addr.sa_family) {
- case AF_INET:
- sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
- if (ifi->ifi_addr == NULL) {
- ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_addr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
-
-#ifdef SIOCGIFNETMASK
- if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
-
- ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_netmask == NULL) goto gotError;
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
- /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
- sinptr->sin_len = sizeof(struct sockaddr_in);
-#endif
- sinptr->sin_family = AF_INET;
- memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
-#endif
-
-#ifdef SIOCGIFBRDADDR
- if (flags & IFF_BROADCAST) {
- if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
- goto gotError;
- }
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
- /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
- sinptr->sin_len = sizeof( struct sockaddr_in );
-#endif
- sinptr->sin_family = AF_INET;
- ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_brdaddr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
- }
-#endif
-
-#ifdef SIOCGIFDSTADDR
- if (flags & IFF_POINTOPOINT) {
- if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
- goto gotError;
- }
- sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
- /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
- sinptr->sin_len = sizeof( struct sockaddr_in );
-#endif
- sinptr->sin_family = AF_INET;
- ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
- if (ifi->ifi_dstaddr == NULL) {
- goto gotError;
- }
- memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
- }
-#endif
- }
- break;
-
-#if defined(AF_INET6) && HAVE_IPV6
- case AF_INET6:
- sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
- if (ifi->ifi_addr == NULL) {
- ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_addr == NULL) {
- goto gotError;
- }
-
- /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
- /* We need to strip that out */
- if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
- sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
- memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
-
-#ifdef SIOCGIFNETMASK_IN6
- {
- struct in6_ifreq ifr6;
- if (sockf6 == -1)
- sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
- 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) {
- if (errno == EADDRNOTAVAIL) {
- /*
- * If the main interface is configured with no IP address but
- * an alias interface exists with an IP address, you get
- * EADDRNOTAVAIL for the main interface
- */
- free(ifi->ifi_addr);
- free(ifi);
- ifipnext = ifiptr;
- *ifipnext = ifipold;
- continue;
- } else {
- goto gotError;
- }
- }
- ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
- if (ifi->ifi_netmask == NULL) goto gotError;
- sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
- memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
- }
-#endif
- }
- break;
-#endif
-
- default:
- break;
- }
- }
- goto done;
-
-gotError:
- if (ifihead != NULL) {
- free_ifi_info(ifihead);
- ifihead = NULL;
- }
-
-done:
- if (buf != NULL) {
- free(buf);
- }
- if (sockfd != -1) {
- junk = close(sockfd);
- assert(junk == 0);
- }
- if (sockf6 != -1) {
- junk = close(sockf6);
- assert(junk == 0);
- }
- return(ifihead); /* pointer to first structure in linked list */
-}
-/* end get_ifi_info3 */
-
-/* include free_ifi_info */
-void
-free_ifi_info(struct ifi_info *ifihead)
-{
- struct ifi_info *ifi, *ifinext;
-
- for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
- if (ifi->ifi_addr != NULL)
- free(ifi->ifi_addr);
- if (ifi->ifi_netmask != NULL)
- free(ifi->ifi_netmask);
- if (ifi->ifi_brdaddr != NULL)
- free(ifi->ifi_brdaddr);
- if (ifi->ifi_dstaddr != NULL)
- free(ifi->ifi_dstaddr);
- ifinext = ifi->ifi_next; /* can't fetch ifi_next after free() */
- free(ifi); /* the ifi_info{} itself */
- }
-}
-/* end free_ifi_info */
-
ssize_t
recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
typedef unsigned int socklen_t;
#endif
-#if !defined(_SS_MAXSIZE)
-#if HAVE_IPV6
-#define sockaddr_storage sockaddr_in6
-#else
-#define sockaddr_storage sockaddr
-#endif // HAVE_IPV6
-#endif // !defined(_SS_MAXSIZE)
-
#ifndef NOT_HAVE_SA_LEN
#define GET_SA_LEN(X) (sizeof(struct sockaddr) > ((struct sockaddr*)&(X))->sa_len ? \
sizeof(struct sockaddr) : ((struct sockaddr*)&(X))->sa_len )
extern ssize_t recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl);
-struct ifi_info {
- char ifi_name[IFI_NAME]; /* interface name, null terminated */
- u_char ifi_haddr[IFI_HADDR]; /* hardware address */
- u_short ifi_hlen; /* #bytes in hardware address: 0, 6, 8 */
- short ifi_flags; /* IFF_xxx constants from <net/if.h> */
- short ifi_myflags; /* our own IFI_xxx flags */
- int ifi_index; /* interface index */
- struct sockaddr *ifi_addr; /* primary address */
- struct sockaddr *ifi_netmask;
- struct sockaddr *ifi_brdaddr; /* broadcast address */
- struct sockaddr *ifi_dstaddr; /* destination address */
- struct ifi_info *ifi_next; /* next of these structures */
-};
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-#define PROC_IFINET6_PATH "/proc/net/if_inet6"
-extern struct ifi_info *get_ifi_info_linuxv6(int doaliases);
-#endif
-
#if defined(AF_INET6) && HAVE_IPV6
#define INET6_ADDRSTRLEN 46 /*Maximum length of IPv6 address */
#endif
-
-
-#define IFI_ALIAS 1 /* ifi_addr is an alias */
-
-/* From the text (Stevens, section 16.6): */
-/* 'Since many programs need to know all the interfaces on a system, we will develop a */
-/* function of our own named get_ifi_info that returns a linked list of structures, one */
-/* for each interface that is currently "up."' */
-extern struct ifi_info *get_ifi_info(int family, int doaliases);
-
-/* 'The free_ifi_info function, which takes a pointer that was */
-/* returned by get_ifi_info and frees all the dynamic memory.' */
-extern void free_ifi_info(struct ifi_info *);
-
#ifdef NOT_HAVE_DAEMON
extern int daemon(int nochdir, int noclose);
#endif
--- /dev/null
+//
+// posix_utilities.c
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#include "posix_utilities.h"
+#include "mDNSEmbeddedAPI.h"
+#include <stdlib.h> // for NULL
+#include <stdio.h> // for snprintf
+#include <time.h>
+#include <sys/time.h> // for gettimeofday
+
+mDNSexport void getLocalTimestamp(char * const buffer, mDNSu32 buffer_len)
+{
+ struct timeval now;
+ struct tm local_time;
+ char date_time_str[32];
+ char time_zone_str[32];
+
+ gettimeofday(&now, NULL);
+ localtime_r(&now.tv_sec, &local_time);
+
+ strftime(date_time_str, sizeof(date_time_str), "%F %T", &local_time);
+ strftime(time_zone_str, sizeof(time_zone_str), "%z", &local_time);
+ snprintf(buffer, buffer_len, "%s.%06lu%s", date_time_str, (unsigned long)now.tv_usec, time_zone_str);
+}
--- /dev/null
+//
+// posix_utilities.h
+// mDNSResponder
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef posix_utilities_h
+#define posix_utilities_h
+
+#include "mDNSEmbeddedAPI.h"
+
+// timestamp format: "2008-08-08 20:00:00.000000+0800", a 64-byte buffer is enough to store the result
+extern void getLocalTimestamp(char * const buffer, mDNSu32 buffer_len);
+
+#endif /* posix_utilities_h */
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClientRequests.h"
+
+#include "DNSCommon.h"
+#include "uDNS.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+#include "mDNSMacOSX.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+#include <dispatch/dispatch.h>
+#include <net/if.h>
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
+
+int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
+int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
+int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
+#endif
+
+#define RecordTypeIsAddress(TYPE) (((TYPE) == kDNSType_A) || ((TYPE) == kDNSType_AAAA))
+
+extern mDNS mDNSStorage;
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+extern domainname ActiveDirectoryPrimaryDomain;
+#endif
+
+// Normally we append search domains only for queries with a single label that are not fully qualified. This can be
+// overridden to apply search domains for queries (that are not fully qualified) with any number of labels e.g., moon,
+// moon.cs, moon.cs.be, etc. - Mohan
+mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
+
+// Control enabling optimistic DNS - Phil
+mDNSBool EnableAllowExpired = mDNStrue;
+
+mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp);
+mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation);
+mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, mDNSu32 inReqID, const domainname *inQName, mDNSu16 inQType,
+ mDNSu16 inQClass, mDNSInterfaceID inInterfaceID, mDNSs32 inServiceID, mDNSu32 inFlags, mDNSBool inAppendSearchDomains,
+ mDNSs32 inPID, const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler,
+ void *inResultContext);
+mDNSlocal void QueryRecordOpStop(QueryRecordOp *op);
+mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op);
+mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer,
+ QC_result inAddRecord);
+mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
+ const domainname *inSearchDomain);
+mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID);
+mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName);
+mDNSlocal mDNSBool StringEndsWithDot(const char *inString);
+mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp);
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *domain, mDNSBool inExcludeLocal);
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID);
+#endif
+
+mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest, mDNSu32 inReqID,
+ const char *inHostnameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu32 inProtocols, mDNSs32 inPID,
+ const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler,
+ void *inResultContext)
+{
+ mStatus err;
+ domainname hostname;
+ mDNSBool appendSearchDomains;
+ mDNSInterfaceID interfaceID;
+ DNSServiceFlags flags;
+ mDNSs32 serviceID;
+
+ if (!MakeDomainNameFromDNSNameString(&hostname, inHostnameStr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] ERROR: bad hostname '" PRI_S "'", inReqID, inHostnameStr);
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ if (inProtocols & ~(kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6))
+ {
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ flags = inFlags;
+ if (!inProtocols)
+ {
+ flags |= kDNSServiceFlagsSuppressUnusable;
+ inRequest->protocols = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
+ }
+ else
+ {
+ inRequest->protocols = inProtocols;
+ }
+
+ if (flags & kDNSServiceFlagsServiceIndex)
+ {
+ // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
+ LogInfo("GetAddrInfoClientRequestStart: kDNSServiceFlagsServiceIndex is SET by the client");
+
+ // If kDNSServiceFlagsServiceIndex is SET, interpret the interfaceID as the serviceId and set the interfaceID to 0.
+ serviceID = (mDNSs32)inInterfaceIndex;
+ interfaceID = mDNSNULL;
+ }
+ else
+ {
+ serviceID = -1;
+ err = InterfaceIndexToInterfaceID(inInterfaceIndex, &interfaceID);
+ if (err) goto exit;
+ }
+ inRequest->interfaceID = interfaceID;
+
+ if (!StringEndsWithDot(inHostnameStr) && (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&hostname)))
+ {
+ appendSearchDomains = mDNStrue;
+ }
+ else
+ {
+ appendSearchDomains = mDNSfalse;
+ }
+
+ if (inRequest->protocols & kDNSServiceProtocol_IPv6)
+ {
+ err = QueryRecordOpCreate(&inRequest->op6);
+ if (err) goto exit;
+
+ err = QueryRecordOpStart(inRequest->op6, inReqID, &hostname, kDNSType_AAAA, kDNSServiceClass_IN,
+ inRequest->interfaceID, serviceID, flags, appendSearchDomains, inPID, inUUID, inUID, inResultHandler,
+ inResultContext);
+ if (err) goto exit;
+ }
+
+ if (inRequest->protocols & kDNSServiceProtocol_IPv4)
+ {
+ err = QueryRecordOpCreate(&inRequest->op4);
+ if (err) goto exit;
+
+ err = QueryRecordOpStart(inRequest->op4, inReqID, &hostname, kDNSType_A, kDNSServiceClass_IN,
+ inRequest->interfaceID, serviceID, flags, appendSearchDomains, inPID, inUUID, inUID, inResultHandler,
+ inResultContext);
+ if (err) goto exit;
+ }
+ err = mStatus_NoError;
+
+exit:
+ if (err) GetAddrInfoClientRequestStop(inRequest);
+ return err;
+}
+
+mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest)
+{
+ if (inRequest->op4) QueryRecordOpStop(inRequest->op4);
+ if (inRequest->op6) QueryRecordOpStop(inRequest->op6);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ {
+ const QueryRecordOp * const op4 = inRequest->op4;
+ const QueryRecordOp * const op6 = inRequest->op6;
+ const DNSQuestion * q4 = mDNSNULL;
+ const DNSQuestion * q6 = mDNSNULL;
+
+ if (op4)
+ {
+ if (op4->answered)
+ {
+ // If we have a v4 answer and if we timed out prematurely before, provide a trigger to the upper layer so
+ // that it can retry questions if needed. - Mohan
+ q4 = &op4->q;
+ }
+ else if (op4->q.TimeoutQuestion)
+ {
+ // If we are not delivering answers, we may be timing out prematurely. Note down the current state so that
+ // we know to retry when we see a valid response again. - Mohan
+ mDNSPlatformUpdateDNSStatus(&op4->q);
+ }
+ }
+ if (op6)
+ {
+ if (op6->answered)
+ {
+ q6 = &op6->q;
+ }
+ else if (op6->q.TimeoutQuestion)
+ {
+ mDNSPlatformUpdateDNSStatus(&op6->q);
+ }
+ }
+ mDNSPlatformTriggerDNSRetry(q4, q6);
+ }
+#endif
+
+ if (inRequest->op4)
+ {
+ QueryRecordOpFree(inRequest->op4);
+ inRequest->op4 = mDNSNULL;
+ }
+ if (inRequest->op6)
+ {
+ QueryRecordOpFree(inRequest->op6);
+ inRequest->op6 = mDNSNULL;
+ }
+}
+
+mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest)
+{
+ if (inRequest->op4) return &inRequest->op4->q.qname;
+ if (inRequest->op6) return &inRequest->op6->q.qname;
+ return (const domainname *)"";
+}
+
+mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest)
+{
+ if ((inRequest->op4 && QueryRecordOpIsMulticast(inRequest->op4)) ||
+ (inRequest->op6 && QueryRecordOpIsMulticast(inRequest->op6)))
+ {
+ return mDNStrue;
+ }
+ return mDNSfalse;
+}
+
+mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest, mDNSu32 inReqID,
+ const char *inQNameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu16 inQType, mDNSu16 inQClass,
+ mDNSs32 inPID, mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler, void *inResultContext)
+{
+ mStatus err;
+ domainname qname;
+ mDNSInterfaceID interfaceID;
+ mDNSBool appendSearchDomains;
+
+ err = InterfaceIndexToInterfaceID(inInterfaceIndex, &interfaceID);
+ if (err) goto exit;
+
+ if (!MakeDomainNameFromDNSNameString(&qname, inQNameStr))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] ERROR: bad domain name '" PRI_S "'", inReqID, inQNameStr);
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ if (RecordTypeIsAddress(inQType) && !StringEndsWithDot(inQNameStr) &&
+ (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&qname)))
+ {
+ appendSearchDomains = mDNStrue;
+ }
+ else
+ {
+ appendSearchDomains = mDNSfalse;
+ }
+
+ err = QueryRecordOpStart(&inRequest->op, inReqID, &qname, inQType, inQClass, interfaceID, -1, inFlags,
+ appendSearchDomains, inPID, inUUID, inUID, inResultHandler, inResultContext);
+
+exit:
+ if (err) QueryRecordClientRequestStop(inRequest);
+ return err;
+}
+
+mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest)
+{
+ QueryRecordOpStop(&inRequest->op);
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ if (inRequest->op.answered)
+ {
+ DNSQuestion *v4q, *v6q;
+ // If we are receiving positive answers, provide the hint to the upper layer. - Mohan
+ v4q = (inRequest->op.q.qtype == kDNSType_A) ? &inRequest->op.q : mDNSNULL;
+ v6q = (inRequest->op.q.qtype == kDNSType_AAAA) ? &inRequest->op.q : mDNSNULL;
+ mDNSPlatformTriggerDNSRetry(v4q, v6q);
+ }
+#endif
+}
+
+mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest)
+{
+ return &inRequest->op.q.qname;
+}
+
+mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest)
+{
+ return inRequest->op.q.qtype;
+}
+
+mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest)
+{
+ return (QueryRecordOpIsMulticast(&inRequest->op) ? mDNStrue : mDNSfalse);
+}
+
+mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp)
+{
+ mStatus err;
+ QueryRecordOp *op;
+
+ op = (QueryRecordOp *) mDNSPlatformMemAllocateClear(sizeof(*op));
+ if (!op)
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ *outOp = op;
+ err = mStatus_NoError;
+
+exit:
+ return err;
+}
+
+mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation)
+{
+ mDNSPlatformMemFree(operation);
+}
+
+#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)))
+
+mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, mDNSu32 inReqID, const domainname *inQName, mDNSu16 inQType,
+ mDNSu16 inQClass, mDNSInterfaceID inInterfaceID, mDNSs32 inServiceID, mDNSu32 inFlags, mDNSBool inAppendSearchDomains,
+ mDNSs32 inPID, const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler,
+ void *inResultContext)
+{
+ mStatus err;
+ DNSQuestion * const q = &inOp->q;
+ mDNSu32 len;
+
+ // Save the original qname.
+
+ len = DomainNameLength(inQName);
+ inOp->qname = (domainname *) mDNSPlatformMemAllocate(len);
+ if (!inOp->qname)
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ mDNSPlatformMemCopy(inOp->qname, inQName, len);
+
+ inOp->interfaceID = inInterfaceID;
+ inOp->reqID = inReqID;
+ inOp->resultHandler = inResultHandler;
+ inOp->resultContext = inResultContext;
+
+ // Set up DNSQuestion.
+
+ if (EnableAllowExpired && (inFlags & kDNSServiceFlagsAllowExpiredAnswers))
+ {
+ q->allowExpired = AllowExpired_AllowExpiredAnswers;
+ }
+ else
+ {
+ q->allowExpired = AllowExpired_None;
+ }
+ q->ServiceID = inServiceID;
+ q->InterfaceID = inInterfaceID;
+ q->flags = inFlags;
+ AssignDomainName(&q->qname, inQName);
+ q->qtype = inQType;
+ q->qclass = inQClass;
+ q->LongLived = (inFlags & kDNSServiceFlagsLongLivedQuery) ? mDNStrue : mDNSfalse;
+ q->ForceMCast = (inFlags & kDNSServiceFlagsForceMulticast) ? mDNStrue : mDNSfalse;
+ q->ReturnIntermed = (inFlags & kDNSServiceFlagsReturnIntermediates) ? mDNStrue : mDNSfalse;
+ q->SuppressUnusable = (inFlags & kDNSServiceFlagsSuppressUnusable) ? mDNStrue : mDNSfalse;
+ q->TimeoutQuestion = (inFlags & kDNSServiceFlagsTimeout) ? mDNStrue : mDNSfalse;
+ q->UseBackgroundTraffic = (inFlags & kDNSServiceFlagsBackgroundTrafficClass) ? mDNStrue : mDNSfalse;
+ q->AppendSearchDomains = inAppendSearchDomains;
+ q->InitialCacheMiss = mDNSfalse;
+
+ // Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet) - Mohan
+
+ q->ValidationRequired = DNSSEC_VALIDATION_NONE;
+ if (!IsLocalDomain(&q->qname) && (inQType != kDNSServiceType_RRSIG) && (inQType != kDNSServiceType_ANY))
+ {
+ if (inFlags & kDNSServiceFlagsValidate)
+ {
+ q->ValidationRequired = DNSSEC_VALIDATION_SECURE;
+ q->AppendSearchDomains = mDNSfalse;
+ }
+ else if (inFlags & kDNSServiceFlagsValidateOptional)
+ {
+ q->ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
+ }
+ }
+
+ q->pid = inPID;
+ if (inUUID) mDNSPlatformMemCopy(q->uuid, inUUID, UUID_SIZE);
+ q->euid = inUID;
+ q->request_id = inReqID;
+ q->QuestionCallback = QueryRecordOpCallback;
+ q->ResetHandler = QueryRecordOpResetHandler;
+
+ // For single label queries that are not fully qualified, look at /etc/hosts, cache and try search domains before trying
+ // them on the wire as a single label query. - Mohan
+
+ if (q->AppendSearchDomains && DomainNameIsSingleLabel(inOp->qname)) q->InterfaceID = mDNSInterface_LocalOnly;
+ err = QueryRecordOpStartQuestion(inOp, q);
+ if (err) goto exit;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
+ {
+ external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags);
+ }
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if ((RecordTypeIsAddress(q->qtype) || VALID_MSAD_SRV(&inOp->q)) && !q->ForceMCast &&
+ SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
+ {
+ DNSQuestion * q2;
+
+ q2 = (DNSQuestion *) mDNSPlatformMemAllocate((mDNSu32)sizeof(*inOp->q2));
+ if (!q2)
+ {
+ err = mStatus_NoMemoryErr;
+ goto exit;
+ }
+ inOp->q2 = q2;
+
+ *q2 = *q;
+ q2->IsUnicastDotLocal = mDNStrue;
+
+ if ((CountLabels(&q2->qname) == 2) && !SameDomainName(&q2->qname, &ActiveDirectoryPrimaryDomain)
+ && !DomainNameIsInSearchList(&q2->qname, mDNSfalse))
+ {
+ inOp->q2Type = q2->qtype;
+ inOp->q2LongLived = q2->LongLived;
+ inOp->q2ReturnIntermed = q2->ReturnIntermed;
+ inOp->q2TimeoutQuestion = q2->TimeoutQuestion;
+ inOp->q2AppendSearchDomains = q2->AppendSearchDomains;
+
+ AssignDomainName(&q2->qname, &localdomain);
+ q2->qtype = kDNSType_SOA;
+ q2->LongLived = mDNSfalse;
+ q2->ReturnIntermed = mDNStrue;
+ q2->TimeoutQuestion = mDNSfalse;
+ q2->AppendSearchDomains = mDNSfalse;
+ }
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] QueryRecordOpStart: starting parallel unicast query for " PRI_DM_NAME " " PUB_S,
+ inOp->reqID, DM_NAME_PARAM(q2->qname.c), DNSTypeName(q2->qtype));
+
+ err = QueryRecordOpStartQuestion(inOp, q2);
+ if (err) goto exit;
+ }
+#endif
+ err = mStatus_NoError;
+
+exit:
+ if (err) QueryRecordOpStop(inOp);
+ return err;
+}
+
+mDNSlocal void QueryRecordOpStop(QueryRecordOp *op)
+{
+ if (op->q.QuestionContext)
+ {
+ QueryRecordOpStopQuestion(&op->q);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+ if (callExternalHelpers(op->q.InterfaceID, op->qname, op->q.flags))
+ {
+ external_stop_browsing_for_service(op->q.InterfaceID, &op->q.qname, op->q.qtype, op->q.flags);
+ }
+#endif
+ }
+ if (op->qname)
+ {
+ mDNSPlatformMemFree(op->qname);
+ op->qname = mDNSNULL;
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if (op->q2)
+ {
+ if (op->q2->QuestionContext) QueryRecordOpStopQuestion(op->q2);
+ mDNSPlatformMemFree(op->q2);
+ op->q2 = mDNSNULL;
+ }
+#endif
+}
+
+mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op)
+{
+ return ((mDNSOpaque16IsZero(op->q.TargetQID) && (op->q.ThisQInterval > 0)) ? mDNStrue : mDNSfalse);
+}
+
+// GetTimeNow is a callback-safe alternative to mDNS_TimeNow(), which expects to be called with m->mDNS_busy == 0.
+mDNSlocal mDNSs32 GetTimeNow(mDNS *m)
+{
+ mDNSs32 time;
+ mDNS_Lock(m);
+ time = m->timenow;
+ mDNS_Unlock(m);
+ return time;
+}
+
+mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer, QC_result inAddRecord)
+{
+ mStatus resultErr;
+ QueryRecordOp *const op = (QueryRecordOp *)inQuestion->QuestionContext;
+ const domainname * domain;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if ((inQuestion == op->q2) && (inQuestion->qtype == kDNSType_SOA))
+ {
+ DNSQuestion * const q2 = op->q2;
+
+ if (inAnswer->rrtype != kDNSType_SOA) goto exit;
+ QueryRecordOpStopQuestion(q2);
+
+ // Restore DNSQuestion variables that were modified for the SOA query.
+
+ q2->qtype = op->q2Type;
+ q2->LongLived = op->q2LongLived;
+ q2->ReturnIntermed = op->q2ReturnIntermed;
+ q2->TimeoutQuestion = op->q2TimeoutQuestion;
+ q2->AppendSearchDomains = op->q2AppendSearchDomains;
+
+ if (inAnswer->RecordType != kDNSRecordTypePacketNegative)
+ {
+ QueryRecordOpRestartUnicastQuestion(op, q2, mDNSNULL);
+ }
+ else if (q2->AppendSearchDomains)
+ {
+ domain = NextSearchDomain(op);
+ if (domain) QueryRecordOpRestartUnicastQuestion(op, q2, domain);
+ }
+ goto exit;
+ }
+#endif
+
+ if (inAddRecord == QC_suppressed)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%u] QueryRecordOpCallback: Suppressed question " PRI_DM_NAME " (" PUB_S ")",
+ op->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype));
+
+ resultErr = kDNSServiceErr_NoSuchRecord;
+ }
+ else if (inAnswer->RecordType == kDNSRecordTypePacketNegative)
+ {
+ if (inQuestion->TimeoutQuestion && ((GetTimeNow(m) - inQuestion->StopTime) >= 0))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") timing out, InterfaceID %p",
+ op->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype),
+ inQuestion->InterfaceID);
+ resultErr = kDNSServiceErr_Timeout;
+ }
+ else
+ {
+ if (inQuestion->AppendSearchDomains && (op->searchListIndex >= 0) && inAddRecord && (inAddRecord != QC_dnssec))
+ {
+ domain = NextSearchDomain(op);
+ if (domain || DomainNameIsSingleLabel(op->qname))
+ {
+ QueryRecordOpStopQuestion(inQuestion);
+ QueryRecordOpRestartUnicastQuestion(op, inQuestion, domain);
+ goto exit;
+ }
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ if (!inAnswer->InterfaceID && IsLocalDomain(inAnswer->name))
+ {
+ if ((RecordTypeIsAddress(inQuestion->qtype) &&
+ (inAnswer->negativeRecordType == kNegativeRecordType_NoData)) ||
+ DomainNameIsInSearchList(&inQuestion->qname, mDNStrue))
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") answering local with negative unicast response",
+ op->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype));
+ }
+ else
+ {
+ goto exit;
+ }
+ }
+#endif
+ resultErr = kDNSServiceErr_NoSuchRecord;
+ }
+ }
+ else
+ {
+ resultErr = kDNSServiceErr_NoError;
+ }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ if ((resultErr != kDNSServiceErr_Timeout) && (inAddRecord == QC_add))
+ {
+ op->answered = mDNStrue;
+ }
+#endif
+
+ if (op->resultHandler) op->resultHandler(m, inQuestion, inAnswer, inAddRecord, resultErr, op->resultContext);
+ if (resultErr == kDNSServiceErr_Timeout) QueryRecordOpStopQuestion(inQuestion);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+ NotifyWebContentFilter(inAnswer, inQuestion->euid);
+#endif
+
+exit:
+ return;
+}
+
+mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion)
+{
+ QueryRecordOp *const op = (QueryRecordOp *)inQuestion->QuestionContext;
+
+ AssignDomainName(&inQuestion->qname, op->qname);
+ if (inQuestion->AppendSearchDomains && DomainNameIsSingleLabel(op->qname))
+ {
+ inQuestion->InterfaceID = mDNSInterface_LocalOnly;
+ }
+ else
+ {
+ inQuestion->InterfaceID = op->interfaceID;
+ }
+ op->searchListIndex = 0;
+}
+
+mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion)
+{
+ mStatus err;
+
+ inQuestion->QuestionContext = inOp;
+ err = mDNS_StartQuery(&mDNSStorage, inQuestion);
+ if (err)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] ERROR: QueryRecordOpStartQuestion mDNS_StartQuery for " PRI_DM_NAME " " PUB_S " failed with error %d",
+ inOp->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype), err);
+ inQuestion->QuestionContext = mDNSNULL;
+ }
+ return err;
+}
+
+mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion)
+{
+ mStatus err;
+
+ err = mDNS_StopQuery(&mDNSStorage, inQuestion);
+ inQuestion->QuestionContext = mDNSNULL;
+ return err;
+}
+
+mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
+ const domainname *inSearchDomain)
+{
+ mStatus err;
+
+ inQuestion->InterfaceID = inOp->interfaceID;
+ AssignDomainName(&inQuestion->qname, inOp->qname);
+ if (inSearchDomain) AppendDomainName(&inQuestion->qname, inSearchDomain);
+ if (SameDomainLabel(LastLabel(&inQuestion->qname), (const mDNSu8 *)&localdomain))
+ {
+ inQuestion->IsUnicastDotLocal = mDNStrue;
+ }
+ else
+ {
+ inQuestion->IsUnicastDotLocal = mDNSfalse;
+ }
+ err = QueryRecordOpStartQuestion(inOp, inQuestion);
+ return err;
+}
+
+mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID)
+{
+ mStatus err;
+ mDNSInterfaceID interfaceID;
+
+ interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, inInterfaceIndex);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+ // The request is scoped to a specific interface index, but the interface is not currently in our list.
+ if ((inInterfaceIndex != kDNSServiceInterfaceIndexAny) && (interfaceID == mDNSInterface_Any))
+ {
+ static dispatch_once_t getLoopbackIndexOnce = 0;
+ static mDNSu32 loopbackIndex = 0;
+
+ dispatch_once(&getLoopbackIndexOnce,
+ ^{
+ loopbackIndex = if_nametoindex("lo0");
+ });
+
+ // If it's one of the specially defined inteface index values, just return an error. Also, caller should return an
+ // error immediately if lo0 is not configured into the current active interfaces. See <rdar://problem/21967160>.
+ if ((inInterfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
+ (inInterfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
+ (inInterfaceIndex == kDNSServiceInterfaceIndexP2P) ||
+ (inInterfaceIndex == kDNSServiceInterfaceIndexBLE) ||
+ (inInterfaceIndex == loopbackIndex))
+ {
+ LogInfo("ERROR: bad interfaceIndex %d", inInterfaceIndex);
+ err = mStatus_BadParamErr;
+ goto exit;
+ }
+
+ // Otherwise, use the specified interface index value and the request will be applied to that interface when it
+ // comes up.
+ interfaceID = (mDNSInterfaceID)(uintptr_t)inInterfaceIndex;
+ LogInfo("Query pending for interface index %d", inInterfaceIndex);
+ }
+#endif
+
+ *outInterfaceID = interfaceID;
+ err = mStatus_NoError;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+exit:
+#endif
+ return err;
+}
+
+mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName)
+{
+ const mDNSu8 *const label = inName->c;
+ return (((label[0] != 0) && (label[1 + label[0]] == 0)) ? mDNStrue : mDNSfalse);
+}
+
+mDNSlocal mDNSBool StringEndsWithDot(const char *inString)
+{
+ const char * ptr;
+ mDNSu32 escapeCount;
+ mDNSBool result;
+
+ // Loop invariant: escapeCount is the number of consecutive escape characters that immediately precede *ptr.
+ // - If escapeCount is even, then *ptr is immediately preceded by escapeCount / 2 consecutive literal backslash
+ // characters, so *ptr is not escaped.
+ // - If escapeCount is odd, then *ptr is immediately preceded by (escapeCount - 1) / 2 consecutive literal backslash
+ // characters followed by an escape character, so *ptr is escaped.
+ escapeCount = 0;
+ result = mDNSfalse;
+ for (ptr = inString; *ptr != '\0'; ptr++)
+ {
+ if (*ptr == '\\')
+ {
+ escapeCount++;
+ }
+ else
+ {
+ if ((*ptr == '.') && (ptr[1] == '\0'))
+ {
+ if ((escapeCount % 2) == 0) result = mDNStrue;
+ break;
+ }
+ escapeCount = 0;
+ }
+ }
+ return result;
+}
+
+mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp)
+{
+ const domainname * domain;
+
+ while ((domain = uDNS_GetNextSearchDomain(inOp->interfaceID, &inOp->searchListIndex, mDNSfalse)) != mDNSNULL)
+ {
+ if ((DomainNameLength(inOp->qname) - 1 + DomainNameLength(domain)) <= MAX_DOMAIN_NAME) break;
+ }
+ if (!domain) inOp->searchListIndex = -1;
+ return domain;
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *inName, mDNSBool inExcludeLocal)
+{
+ const SearchListElem * item;
+ int labelCount, domainLabelCount;
+
+ labelCount = CountLabels(inName);
+ for (item = SearchList; item; item = item->next)
+ {
+ if (inExcludeLocal && SameDomainName(&item->domain, &localdomain)) continue;
+ domainLabelCount = CountLabels(&item->domain);
+ if (labelCount >= domainLabelCount)
+ {
+ if (SameDomainName(&item->domain, SkipLeadingLabels(inName, (labelCount - domainLabelCount))))
+ {
+ return mDNStrue;
+ }
+ }
+ }
+ return mDNSfalse;
+}
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID)
+{
+ if (WCFIsServerRunning)
+ {
+ const mDNS *const m = &mDNSStorage;
+
+ if (WCFIsServerRunning(m->WCF) && inAnswer->rdlength != 0)
+ {
+ struct sockaddr_storage addr;
+ addr.ss_len = 0;
+ if (inAnswer->rrtype == kDNSType_A || inAnswer->rrtype == kDNSType_AAAA)
+ {
+ if (inAnswer->rrtype == kDNSType_A)
+ {
+ struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
+ sin->sin_port = 0;
+ // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
+ // sin->sin_addr.s_addr = inAnswer->rdata->u.ipv4.NotAnInteger;
+ if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), inAnswer))
+ LogMsg("NotifyWebContentFilter: WCF AF_INET putRData failed");
+ else
+ {
+ addr.ss_len = sizeof (struct sockaddr_in);
+ addr.ss_family = AF_INET;
+ }
+ }
+ else if (inAnswer->rrtype == kDNSType_AAAA)
+ {
+ struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
+ sin6->sin6_port = 0;
+ // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = inAnswer->rdata->u.ipv6.l[0];
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = inAnswer->rdata->u.ipv6.l[1];
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = inAnswer->rdata->u.ipv6.l[2];
+ // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = inAnswer->rdata->u.ipv6.l[3];
+ if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), inAnswer))
+ LogMsg("NotifyWebContentFilter: WCF AF_INET6 putRData failed");
+ else
+ {
+ addr.ss_len = sizeof (struct sockaddr_in6);
+ addr.ss_family = AF_INET6;
+ }
+ }
+ if (addr.ss_len)
+ {
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ ConvertDomainNameToCString(inAnswer->name, name);
+
+ debugf("NotifyWebContentFilter: Name %s, uid %u, addr length %d", name, inUID, addr.ss_len);
+ if (WCFNameResolvesToAddr)
+ {
+ WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, inUID);
+ }
+ }
+ }
+ else if (inAnswer->rrtype == kDNSType_CNAME)
+ {
+ domainname cname;
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+ if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), inAnswer))
+ LogMsg("NotifyWebContentFilter: WCF CNAME putRData failed");
+ else
+ {
+ ConvertDomainNameToCString(inAnswer->name, name);
+ ConvertDomainNameToCString(&cname, cname_cstr);
+ if (WCFNameResolvesToAddr)
+ {
+ WCFNameResolvesToName(m->WCF, name, cname_cstr, inUID);
+ }
+ }
+ }
+ }
+ }
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ClientRequests_h
+#define __ClientRequests_h
+
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd_internal.h"
+
+typedef void (*QueryRecordResultHandler)(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord,
+ DNSServiceErrorType error, void *context);
+
+typedef struct
+{
+ DNSQuestion q; // DNSQuestion for record query.
+ domainname * qname; // Name of the original record.
+ mDNSInterfaceID interfaceID; // Interface over which to perform query.
+ QueryRecordResultHandler resultHandler; // Handler for query record operation results.
+ void * resultContext; // Context to pass to result handler.
+ mDNSu32 reqID; //
+ int searchListIndex; // Index that indicates the next search domain to try.
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+ DNSQuestion * q2; // DNSQuestion for unicast version of a record with a dot-local name.
+ mDNSu16 q2Type; // q2's original qtype value.
+ mDNSBool q2LongLived; // q2's original LongLived value.
+ mDNSBool q2ReturnIntermed; // q2's original ReturnIntermed value.
+ mDNSBool q2TimeoutQuestion; // q2's original TimeoutQuestion value.
+ mDNSBool q2AppendSearchDomains; // q2's original AppendSearchDomains value.
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+ mDNSBool answered; // True if the query was answered.
+#endif
+
+} QueryRecordOp;
+
+typedef struct
+{
+ mDNSInterfaceID interfaceID; // InterfaceID being used for query record operations.
+ mDNSu32 protocols; // Protocols (IPv4, IPv6) specified by client.
+ QueryRecordOp * op4; // Query record operation object for A record.
+ QueryRecordOp * op6; // Query record operation object for AAAA record.
+
+} GetAddrInfoClientRequest;
+
+typedef struct
+{
+ QueryRecordOp op; // Query record operation object.
+
+} QueryRecordClientRequest;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest, mDNSu32 inReqID,
+ const char *inHostnameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu32 inProtocols, mDNSs32 inPID,
+ const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest);
+mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest);
+mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest);
+
+mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest, mDNSu32 inReqID,
+ const char *inQNameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu16 inQType, mDNSu16 inQClass,
+ mDNSs32 inPID, mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest);
+mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest);
+mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest);
+mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ClientRequests_h
//---------------------------------------------------------------------------------------------------------------------------
/*! @header CommonServices
- Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
+ Common Services for Mac OS X, Linux, Palm, Windows, and Windows CE.
*/
#ifndef __COMMON_SERVICES__
#endif
#endif
-// VxWorks
-
-#if ( !defined( TARGET_OS_VXWORKS ) )
-
-// No predefined macro for VxWorks so just assume VxWorks if nothing else is set.
-
- #if ( !macintosh && !__MACH__ && !defined( __FreeBSD__ ) && !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
- #endif
-#endif
-
// Windows
#if ( !defined( TARGET_OS_WIN32 ) )
// Palm (no special includes yet).
-#elif ( TARGET_OS_VXWORKS )
-
-// VxWorks
-
- #include "vxWorks.h"
-
#elif ( TARGET_OS_WIN32 )
// Windows
#endif
#if ( !defined( TARGET_BUILD_MAIN ) )
- #if ( !TARGET_OS_VXWORKS )
- #define TARGET_BUILD_MAIN 1
- #endif
-#endif
-
-#if ( __GNUC__ || !TARGET_OS_VXWORKS )
- #define TARGET_LANGUAGE_C_LIKE 1
-#else
- #define TARGET_LANGUAGE_C_LIKE 0
+ #define TARGET_BUILD_MAIN 1
#endif
#if 0
#define ENOTCONN_compat WSAENOTCONN
#define IsValidSocket( X ) ( ( X ) != INVALID_SOCKET )
#define kInvalidSocketRef INVALID_SOCKET
- #if ( TARGET_LANGUAGE_C_LIKE )
typedef SOCKET SocketRef;
- #endif
#else
#define close_compat( X ) close( X )
#define errno_compat() errno
#define ENOTCONN_compat ENOTCONN
#define IsValidSocket( X ) ( ( X ) >= 0 )
#define kInvalidSocketRef -1
- #if ( TARGET_LANGUAGE_C_LIKE )
typedef int SocketRef;
- #endif
#endif
// socklen_t is not defined on the following platforms so emulate it if not defined:
//
// - Pre-Panther Mac OS X. Panther defines SO_NOADDRERR so trigger off that.
// - Windows SDK prior to 2003. 2003+ SDK's define EAI_AGAIN so trigger off that.
-// - VxWorks
-#if ( TARGET_LANGUAGE_C_LIKE )
- #if ( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) || TARGET_OS_VXWORKS )
+#if ( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) )
typedef int socklen_t;
- #endif
#endif
// ssize_t is not defined on the following platforms so emulate it if not defined:
// - Mac OS X when not building with BSD headers
// - Windows
-#if ( TARGET_LANGUAGE_C_LIKE )
- #if ( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_FREEBSD && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+#if ( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_FREEBSD && !TARGET_OS_LINUX && !TARGET_OS_MAC)
typedef int ssize_t;
- #endif
#endif
// sockaddr_storage is not supported on non-IPv6 machines so alias it to an IPv4-compatible structure.
-#if ( TARGET_LANGUAGE_C_LIKE )
- #if ( !defined( AF_INET6 ) )
+#if ( !defined( AF_INET6 ) )
#define sockaddr_storage sockaddr_in
#define ss_family sin_family
- #endif
#endif
//---------------------------------------------------------------------------------------------------------------------------
#pragma mark == Types ==
#endif
-#if ( TARGET_LANGUAGE_C_LIKE )
//===========================================================================================================================
// Standard Types
//===========================================================================================================================
typedef UINT32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
-
- #elif ( TARGET_OS_VXWORKS && ( TORNADO_VERSION < 220 ) )
-typedef long long int64_t;
-typedef unsigned long long uint64_t;
#endif
typedef int8_t int_least8_t;
@abstract 255 character null-terminated (C-style) string.
*/
-#if ( TARGET_LANGUAGE_C_LIKE )
typedef char CStr255[ 256 ];
-#endif
-
-#endif // TARGET_LANGUAGE_C_LIKE
//---------------------------------------------------------------------------------------------------------------------------
/*! @defined TYPE_LONGLONG_NATIVE
*/
#if ( !defined( TYPE_LONGLONG_NATIVE ) )
- #if ( !TARGET_OS_VXWORKS )
- #define TYPE_LONGLONG_NATIVE 1
- #else
- #define TYPE_LONGLONG_NATIVE 0
- #endif
+ #define TYPE_LONGLONG_NATIVE 1
#endif
//---------------------------------------------------------------------------------------------------------------------------
"__int64" and "unsigned __int64" equivalents so map to those types if the real long long is not supported.
*/
-#if ( TARGET_LANGUAGE_C_LIKE )
- #if ( TARGET_OS_WIN32 )
+#if ( TARGET_OS_WIN32 )
typedef __int64 long_long_compat;
typedef unsigned __int64 unsigned_long_long_compat;
- #else
+#else
typedef signed long long long_long_compat;
typedef unsigned long long unsigned_long_long_compat;
- #endif
#endif
#if 0
@constant kNoSpaceErr -6763 Not enough space to perform operation.
*/
-#if ( TARGET_LANGUAGE_C_LIKE )
- #if ( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
+#if ( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
typedef int32_t OSStatus;
- #endif
#endif
#define kNoErr 0
to wait for 5 seconds you would use "5 * kDurationSecond".
*/
-#if ( TARGET_LANGUAGE_C_LIKE )
- #if ( !TARGET_OS_MAC )
+#if ( !TARGET_OS_MAC )
typedef int32_t Duration;
- #endif
#endif
#define kDurationImmediate 0L
left = right -> 0
*/
-#if ( TARGET_LANGUAGE_C_LIKE )
int NumVersionCompare( uint32_t inLeft, uint32_t inRight );
-#endif
#if 0
#pragma mark == Binary Constants ==
*/
#if ( DEBUG )
- #if ( TARGET_LANGUAGE_C_LIKE )
OSStatus CommonServicesTest( void );
- #endif
#endif
#ifdef __cplusplus
#if ( DEBUG )
-#if ( TARGET_OS_VXWORKS )
- #include "intLib.h"
-#endif
-
#if ( TARGET_OS_WIN32 )
#include <time.h>
// Private Globals
//===========================================================================================================================
-#if ( TARGET_OS_VXWORKS )
-// TCP States for inetstatShow.
-
-extern char ** pTcpstates; // defined in tcpLib.c
-
-const char * kDebugTCPStates[] =
-{
- "(0) TCPS_CLOSED",
- "(1) TCPS_LISTEN",
- "(2) TCPS_SYN_SENT",
- "(3) TCPS_SYN_RECEIVED",
- "(4) TCPS_ESTABLISHED",
- "(5) TCPS_CLOSE_WAIT",
- "(6) TCPS_FIN_WAIT_1",
- "(7) TCPS_CLOSING",
- "(8) TCPS_LAST_ACK",
- "(9) TCPS_FIN_WAIT_2",
- "(10) TCPS_TIME_WAIT",
-};
-#endif
-
// General
static bool gDebugInitialized = false;
va_start( args, inType );
-#if ( TARGET_OS_VXWORKS )
- // Set up the TCP state strings if they are not already set up by VxWorks (normally not set up for some reason).
-
- if( !pTcpstates )
- {
- pTcpstates = (char **) kDebugTCPStates;
- }
-#endif
-
// Set up DebugLib stuff (if building with Debugging.h).
#if ( DEBUG_CORE_SERVICE_ASSERTS_ENABLED )
#elif ( DEBUG_KPRINTF_ENABLED )
type = kDebugOutputTypeKPrintF;
#endif
- #elif ( TARGET_OS_VXWORKS )
- #if ( DEBUG_FPRINTF_ENABLED )
- type = kDebugOutputTypeFPrintF;
- #else
- #error target is VxWorks, but fprintf output is disabled
- #endif
#else
#if ( DEBUG_FPRINTF_ENABLED )
type = kDebugOutputTypeFPrintF;
if( DebugTaskLevel() & kDebugInterruptLevelMask )
{
- #if ( TARGET_OS_VXWORKS )
- logMsg( "\ncannot print at interrupt time\n\n", 1, 2, 3, 4, 5, 6 );
- #endif
-
err = kExecutionStateErr;
goto exit;
}
level = 0;
-#if ( TARGET_OS_VXWORKS )
- if( intContext() )
- {
- level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
- }
-#endif
-
return( level );
}
#include "CommonServices.h"
-#if ( TARGET_OS_VXWORKS )
- #include "logLib.h"
-#endif
-
#if 0
#pragma mark == Settings ==
#endif
#endif
#endif
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @defined DebugLogMsg
-
- @abstract Debug-only macro for the VxWorks logMsg function.
- */
-
-#if ( TARGET_OS_VXWORKS )
- #if ( DEBUG )
- #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 ) \
- do \
- { \
- if( ( inLevel >= gDebugPrintLevelMin ) || ( inLevel <= gDebugPrintLevelMax ) ) \
- { \
- logMsg( ( FORMAT ), ( P1 ), ( P2 ), ( P3 ), ( P4 ), ( P5 ), ( P6 ) ); \
- } \
- \
- } while( 0 )
- #else
- #define DebugLogMsg( LEVEL, FORMAT, P1, P2, P3, P4, P5, P6 )
- #endif
-#else
- #define DebugLogMsg dlog
-#endif
-
#if 0
#pragma mark == Routines - General ==
#endif
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
{
void *iElem, *lastElem;
+ if (elem == NULL) {
+ return 0;
+ }
for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
iElem = GetOffsetLink( pList, iElem))
{
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
- * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2019 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.
* 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.
+ *
+ * This file defines functions that are common to platforms with Posix APIs.
+ * Current examples are mDNSMacOSX and mDNSPosix.
*/
#include <stdio.h> // Needed for fopen() etc.
#include <unistd.h> // Needed for close()
+#include <stdlib.h> // Needed for malloc()
#include <string.h> // Needed for strlen() etc.
#include <errno.h> // Needed for errno etc.
#include <sys/socket.h> // Needed for socket() etc.
#include <netinet/in.h> // Needed for sockaddr_in
#include <syslog.h>
+#include <sys/fcntl.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <assert.h>
#if APPLE_OSX_mDNSResponder
#include <os/log.h>
typedef unsigned int socklen_t;
#endif
+#if MDNS_MALLOC_DEBUGGING
+// We ONLY want this for malloc debugging--on a running production system we want to deal with
+// malloc failures, not just die. There is a small performance penalty for enabling these options
+// as well, so they are all only appropriate for debugging. The flags mean:
+//
+// A = warnings are errors
+// X = abort on failure
+// Z = sets J & R
+// J = allocated memory is initialized to a pattern
+// R causes realloc to always reallocate even if not needed
+
+char _malloc_options[] = "AXZ";
+
+mDNSlocal mDNSListValidator *listValidators;
+
+mDNSexport void mDNSPlatformAddListValidator(mDNSListValidator *lv, mDNSListValidationFunction *lvf,
+ const char *lvfName, void *context)
+{
+ mDNSPlatformMemZero(lv, sizeof *lv);
+ lv->validator = lvf;
+ lv->validationFunctionName = lvfName;
+ lv->context = context;
+ lv->next = listValidators;
+ listValidators = lv;
+}
+
+mDNSlocal void validateLists(void)
+{
+ mDNSListValidator *vfp;
+ // Check Unix Domain Socket client lists (uds_daemon.c)
+ for (vfp = listValidators; vfp; vfp = vfp->next)
+ {
+ vfp->validator(vfp->context);
+ }
+
+ mDNSPlatformValidateLists();
+}
+
+#define kAllocMagic 0xDEAD1234
+#define kGuardMagic 0xDEAD1234
+#define kFreeMagic 0xDEADDEAD
+#define kAllocLargeSize 32768
+
+mDNSexport void *mallocL(const char *msg, mDNSu32 size)
+{
+ // Allocate space for two words of sanity checking data before the requested block and two words after.
+ // Adjust the length for alignment.
+ mDNSu32 *mem = malloc(sizeof(mDNSu32) * 4 + size);
+ mDNSu32 guard[2];
+ if (!mem)
+ { LogMsg("malloc( %s : %u ) failed", msg, size); return(NULL); }
+ else
+ {
+ mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
+ if (size > kAllocLargeSize) LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
+ else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("malloc( %s : %lu ) @ %p", msg, size, &mem[2]);
+ mem[ 0] = kAllocMagic;
+ guard[0] = kGuardMagic;
+ mem[ 1] = size;
+ guard[1] = size;
+ memcpy(after, &guard, sizeof guard);
+ memset(&mem[2], 0xFF, size);
+ validateLists();
+ return(&mem[2]);
+ }
+}
+
+mDNSexport void *callocL(const char *msg, mDNSu32 size)
+{
+ mDNSu32 guard[2];
+ const mDNSu32 headerSize = 4 * sizeof(mDNSu32);
+
+ // Allocate space for two words of sanity checking data before the requested block and two words after.
+ // Adjust the length for alignment.
+ mDNSu32 *mem = (mDNSu32 *)calloc(1, headerSize + size);
+ if (!mem)
+ { LogMsg("calloc( %s : %u ) failed", msg, size); return(NULL); }
+ else
+ {
+ mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
+ if (size > kAllocLargeSize) LogMsg("calloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
+ else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("calloc( %s : %lu ) @ %p", msg, size, &mem[2]);
+ mem[ 0] = kAllocMagic;
+ guard[0] = kGuardMagic;
+ mem[ 1] = size;
+ guard[1] = size;
+ memcpy(after, guard, sizeof guard);
+ validateLists();
+ return(&mem[2]);
+ }
+}
+
+mDNSexport void freeL(const char *msg, void *x)
+{
+ if (!x)
+ LogMsg("free( %s @ NULL )!", msg);
+ else
+ {
+ mDNSu32 *mem = ((mDNSu32 *)x) - 2;
+ if (mem[0] == kFreeMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; }
+ if (mem[0] != kAllocMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!", msg, mem[1], &mem[2]); return; }
+ if (mem[1] > kAllocLargeSize) LogMsg("free( %s : %lu @ %p) suspiciously large", msg, mem[1], &mem[2]);
+ else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("free( %s : %ld @ %p)", msg, mem[1], &mem[2]);
+ mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)x + mem[1]);
+ mDNSu32 guard[2];
+
+ memcpy(guard, after, sizeof guard);
+ if (guard[0] != kGuardMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! END GUARD OVERWRITE !!!!",
+ msg, mem[1], &mem[2]); return; }
+ if (guard[1] != mem[1]) { LogMemCorruption("free( %s : %lu @ %p ) !!!! LENGTH MISMATCH !!!!",
+ msg, mem[1], &mem[2]); return; }
+ mem[0] = kFreeMagic;
+ memset(mem + 2, 0xFF, mem[1] + 2 * sizeof(mDNSu32));
+ validateLists();
+ free(mem);
+ }
+}
+
+#endif
+
// Bind a UDP socket to find the source address to a destination
mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
{
if (domain && domain->c[0] && buf[0])
{
- DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
+ DomainAuthInfo *info = (DomainAuthInfo*) mDNSPlatformMemAllocateClear(sizeof(*info));
// for now we assume keyname = service reg domain and we use same key for service and hostname registration
- err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, mDNSfalse);
+ err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0);
if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
}
}
#endif
+#if !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
{
#if APPLE_OSX_mDNSResponder && LogTimeStamps
{
static int log_inited = 0;
- int syslog_level = LOG_ERR;
+ int syslog_level;
switch (loglevel)
{
-#if APPLE_OSX_mDNSResponder
- case MDNS_LOG_MSG: syslog_level = OS_LOG_TYPE_DEFAULT; break;
- case MDNS_LOG_OPERATION: syslog_level = OS_LOG_TYPE_INFO; break;
- case MDNS_LOG_SPS: syslog_level = OS_LOG_TYPE_INFO; break;
- case MDNS_LOG_INFO: syslog_level = OS_LOG_TYPE_INFO; break;
- case MDNS_LOG_DEBUG: syslog_level = OS_LOG_TYPE_DEBUG; break;
- default: syslog_level = OS_LOG_TYPE_DEFAULT; break;
-#else
- 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);
-#endif
+ case MDNS_LOG_FAULT: syslog_level = LOG_ERR; break;
+ case MDNS_LOG_ERROR: syslog_level = LOG_ERR; break;
+ case MDNS_LOG_WARNING: syslog_level = LOG_WARNING; break;
+ case MDNS_LOG_DEFAULT: syslog_level = LOG_NOTICE; break;
+ case MDNS_LOG_INFO: syslog_level = LOG_INFO; break;
+ case MDNS_LOG_DEBUG: syslog_level = LOG_DEBUG; break;
+ default: syslog_level = LOG_NOTICE; break;
}
if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
else
#endif
{
-#if APPLE_OSX_mDNSResponder
- mDNSPlatformLogToFile(syslog_level, buffer);
-#else
syslog(syslog_level, "%s", buffer);
+ }
+ }
+}
+#endif // !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+
+mDNSexport mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort)
+{
+ int sa_family = (addrType == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
+ int err;
+ int sock;
+ mDNSu32 lowWater = 15384;
+
+ sock = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sock < 3)
+ {
+ if (errno != EAFNOSUPPORT)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup: socket error %d errno %d (%s)", sock, errno, strerror(errno));
+ }
+ return mDNStrue;
+ }
+ *fd = sock;
+
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } addr;
+ // If port is not NULL, bind to it.
+ if (port != NULL)
+ {
+ socklen_t len = (sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
+ mDNSPlatformMemZero(&addr, sizeof addr);
+
+ addr.sa.sa_family = sa_family;
+#ifndef NOT_HAVE_SA_LEN
+ addr.sa.sa_len = len;
#endif
+ if (sa_family == AF_INET6)
+ {
+ addr.sin6.sin6_port = port->NotAnInteger;
+ }
+ else
+ {
+ addr.sin.sin_port = port->NotAnInteger;
+ }
+ err = bind(sock, &addr.sa, len);
+ if (err < 0)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ }
+
+ socklen_t addrlen = sizeof addr;
+ err = getsockname(sock, (struct sockaddr *)&addr, &addrlen);
+ if (err < 0)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ if (sa_family == AF_INET6)
+ {
+ outTcpPort->NotAnInteger = addr.sin6.sin6_port;
+
+ } else
+ {
+ outTcpPort->NotAnInteger = addr.sin.sin_port;
+ }
+ if (port)
+ port->NotAnInteger = outTcpPort->NotAnInteger;
+
+ err = setsockopt(sock, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater);
+ if (err < 0)
+ {
+ LogMsg("mDNSPosixTCPSocketSetup: TCP_NOTSENT_LOWAT failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+
+ return mDNStrue;
+}
+
+mDNSexport TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
+ TCPAcceptedCallback callback, void *context)
+{
+ union
+ {
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
+ struct sockaddr sa;
+ } address;
+
+ socklen_t slen = sizeof address;
+ int remoteSock;
+ mDNSAddr addr;
+ mDNSIPPort port;
+ TCPSocket *sock = mDNSNULL;
+ int failed;
+ char *nbp;
+ int i;
+ mDNSu32 lowWater = 16384;
+ // When we remember our connection, we remember a name that we can print for logging. But
+ // since we are the listener in this case, we don't /have/ a name for it. This buffer
+ // is used to print the IP address into a human readable string which will serve that purpose
+ // for this case.
+ char namebuf[INET6_ADDRSTRLEN + 1 + 5 + 1];
+
+ remoteSock = accept(fd, &address.sa, &slen);
+ if (remoteSock < 0)
+ {
+ LogMsg("mDNSPosixDoTCPListenCallback: accept returned %d", remoteSock);
+ goto out;
+ }
+
+ failed = fcntl(remoteSock, F_SETFL, O_NONBLOCK);
+ if (failed < 0)
+ {
+ close(remoteSock);
+ LogMsg("mDNSPosixDoTCPListenCallback: fcntl returned %d", errno);
+ goto out;
+ }
+
+ failed = setsockopt(remoteSock, IPPROTO_TCP, TCP_NOTSENT_LOWAT,
+ &lowWater, sizeof lowWater);
+ if (failed < 0)
+ {
+ close(remoteSock);
+ LogMsg("mDNSPosixDoTCPListenCallback: TCP_NOTSENT_LOWAT returned %d", errno);
+ goto out;
+ }
+
+ if (address.sa.sa_family == AF_INET6)
+ {
+ // If we are listening on an IPv4/IPv6 socket, the incoming address might be an IPv4-in-IPv6 address
+ for (i = 0; i < 10; i++)
+ {
+ if (address.sin6.sin6_addr.s6_addr[i] != 0)
+ {
+ addr.type = mDNSAddrType_IPv6;
+ goto nope;
+ }
}
+
+ // a legit IPv4 address would be ::ffff:a.b.c.d; if there's no ::ffff bit, then it's an IPv6
+ // address with a really weird prefix.
+ if (address.sin6.sin6_addr.s6_addr[10] != 0xFF || address.sin6.sin6_addr.s6_addr[11] != 0xFF)
+ {
+ addr.type = mDNSAddrType_IPv6;
+ } else if (addressType != mDNSAddrType_None)
+ {
+ if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ LogMsg("mDNSPosixDoTCPListenCallback received an IPv4 connection from %s on an IPv6-only socket.",
+ namebuf);
+ close(remoteSock);
+ goto out;
+ }
+ else
+ {
+ addr.type = mDNSAddrType_IPv4;
+ }
+ nope:
+ if (addr.type == mDNSAddrType_IPv6)
+ {
+ if (inet_ntop(address.sin6.sin6_family, &address.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ memcpy(&addr.ip.v6, &address.sin6.sin6_addr, sizeof addr.ip.v6);
+ }
+ else
+ {
+ if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ memcpy(&addr.ip.v4, &address.sin6.sin6_addr.s6_addr[12], sizeof addr.ip.v4);
+ }
+ port.NotAnInteger = address.sin6.sin6_port;
+ }
+ else if (address.sa.sa_family == AF_INET)
+ {
+ addr.type = mDNSAddrType_IPv4;
+ memcpy(&addr.ip.v4, &address.sin.sin_addr, sizeof addr.ip.v4);
+ port.NotAnInteger = address.sin.sin_port;
+ if (inet_ntop(AF_INET, &address.sin.sin_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+ {
+ strcpy(namebuf, ":unknown:");
+ }
+ } else {
+ LogMsg("mDNSPosixDoTCPListenCallback: connection from unknown address family %d", address.sa.sa_family);
+ close(remoteSock);
+ goto out;
+ }
+ nbp = namebuf + strlen(namebuf);
+ *nbp++ = '%';
+ snprintf(nbp, 6, "%u", ntohs(port.NotAnInteger));
+
+ sock = mDNSPlatformTCPAccept(socketFlags, remoteSock);
+ if (sock == NULL)
+ {
+ LogMsg("mDNSPosixDoTCPListenCallback: mDNSPlatformTCPAccept returned NULL; dropping connection from %s",
+ namebuf);
+ close(remoteSock);
+ goto out;
+ }
+ callback(sock, &addr, &port, namebuf, context);
+out:
+ return sock;
+}
+
+mDNSexport mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ mDNSBool reuseAddr, int queueLength)
+
+{
+ union
+ {
+ struct sockaddr_in6 sin6;
+ struct sockaddr_in sin;
+ struct sockaddr sa;
+ } address;
+
+ int failed;
+ int sock;
+ int one = 1;
+ socklen_t sock_len;
+
+ // We require an addrtype parameter because addr is allowed to be null, but they have to agree.
+ if (addr != mDNSNULL && addr->type != addrtype)
+ {
+ LogMsg("mDNSPlatformTCPListen: address type conflict: %d:%d", addr->type, addrtype);
+ return mDNSfalse;
+ }
+ if (port == mDNSNULL)
+ {
+ LogMsg("mDNSPlatformTCPListen: port must not be NULL");
+ return mDNSfalse;
+ }
+
+ mDNSPlatformMemZero(&address, sizeof address);
+ if (addrtype == mDNSAddrType_None || addrtype == mDNSAddrType_IPv6)
+ {
+ // Set up DNS listener socket
+ if (addr != mDNSNULL)
+ {
+ memcpy(&address.sin6.sin6_addr.s6_addr, &addr->ip, sizeof address.sin6.sin6_addr.s6_addr);
+ }
+ address.sin6.sin6_port = port->NotAnInteger;
+
+ sock_len = sizeof address.sin6;
+ address.sin6.sin6_family = AF_INET6;
+ }
+ else if (addrtype == mDNSAddrType_IPv4)
+ {
+ if (addr != mDNSNULL)
+ {
+ memcpy(&address.sin.sin_addr.s_addr, &addr->ip, sizeof address.sin.sin_addr.s_addr);
+ }
+ address.sin.sin_port = port->NotAnInteger;
+ sock_len = sizeof address.sin;
+ address.sin.sin_family = AF_INET;
+ }
+ else
+ {
+ LogMsg("mDNSPlatformTCPListen: invalid address type: %d", addrtype);
+ return mDNSfalse;
+ }
+#ifndef NOT_HAVE_SA_LEN
+ address.sa.sa_len = sock_len;
+#endif
+ sock = socket(address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+
+ if (sock < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: socket call failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ *fd = sock;
+
+ // The reuseAddr flag is used to indicate that we want to listen on this port even if
+ // there are still lingering sockets. We will still fail if there is another listener.
+ // Note that this requires SO_REUSEADDR, not SO_REUSEPORT, which does not have special
+ // handling for lingering sockets.
+ if (reuseAddr)
+ {
+ failed = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
+ if (failed < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: SO_REUSEADDR failed %s", strerror(errno));
+ return mDNSfalse;
+ }
+ }
+
+ // Bind to the port and (if provided) address
+ failed = bind(sock, &address.sa, sock_len);
+ if (failed < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: bind failed %s", strerror(errno));
+ return mDNSfalse;
+ }
+
+ // If there was no specified listen port, we need to know what port we got.
+ if (port->NotAnInteger == 0)
+ {
+ mDNSPlatformMemZero(&address, sizeof address);
+ failed = getsockname(sock, &address.sa, &sock_len);
+ if (failed < 0)
+ {
+ LogMsg("mDNSRelay: getsockname failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ if (address.sa.sa_family == AF_INET)
+ {
+ port->NotAnInteger = address.sin.sin_port;
+ }
+ else
+ {
+ port->NotAnInteger = address.sin6.sin6_port;
+ }
+ }
+
+ failed = listen(sock, queueLength);
+ if (failed < 0)
+ {
+ LogMsg("mDNSPlatformTCPListen: listen failed: %s", strerror(errno));
+ return mDNSfalse;
+ }
+ return mDNStrue;
+}
+
+mDNSexport long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed)
+{
+ static int CLOSEDcount = 0;
+ static int EAGAINcount = 0;
+ ssize_t nread = recv(fd, buf, buflen, 0);
+
+ if (nread > 0)
+ {
+ CLOSEDcount = 0;
+ EAGAINcount = 0;
+ } // On success, clear our error counters
+ else if (nread == 0)
+ {
+ *closed = mDNStrue;
+ if ((++CLOSEDcount % 20) == 0)
+ {
+ LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got CLOSED %d times", fd, CLOSEDcount);
+ assert(CLOSEDcount < 1000);
+ // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error
+ // msg multiple times, crash mDNSResponder using assert() and restart fresh. See advantages
+ // below:
+ // 1.Better User Experience
+ // 2.CrashLogs frequency can be monitored
+ // 3.StackTrace can be used for more info
+ }
+ }
+ // else nread is negative -- see what kind of error we got
+ else if (errno == ECONNRESET)
+ {
+ nread = 0; *closed = mDNStrue;
+ }
+ else if (errno != EAGAIN)
+ {
+ LogMsg("ERROR: mDNSPosixReadFromSocket - recv: %d (%s)", errno, strerror(errno));
+ nread = -1;
+ }
+ else
+ { // errno is EAGAIN (EWOULDBLOCK) -- no data available
+ nread = 0;
+ if ((++EAGAINcount % 1000) == 0)
+ {
+ LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got EAGAIN %d times", fd, EAGAINcount);
+ sleep(1);
+ }
+ }
+ return nread;
+}
+
+mDNSexport long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len)
+{
+ ssize_t result;
+ long nsent;
+
+ result = write(fd, msg, len);
+ if (result < 0)
+ {
+ if (errno == EAGAIN)
+ {
+ nsent = 0;
+ }
+ else
+ {
+ LogMsg("ERROR: mDNSPosixWriteTCP - send %s", strerror(errno)); nsent = -1;
+ }
+ }
+ else
+ {
+ nsent = (long)result;
}
+ return nsent;
}
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
*
* Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
*
* limitations under the License.
*/
-extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
+#ifndef __PLATFORM_COMMON_H
+#define __PLATFORM_COMMON_H
+extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename,
+ domainname *const hostname, domainname *const domain,
+ mDNSBool *DomainDiscoveryDisabled);
+extern mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort);
+extern TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
+ TCPAcceptedCallback callback, void *context);
+extern mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+ mDNSBool reuseAddr, int queueLength);
+extern long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed);
+extern long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len);
+#endif
*/
#ifndef _DNS_SD_H
-#define _DNS_SD_H 8807002
+#define _DNS_SD_H 10960002
#ifdef __cplusplus
extern "C" {
kDNSServiceFlagsAutoTrigger = 0x1,
/* Valid for browses using kDNSServiceInterfaceIndexAny.
- * Will auto trigger the browse over AWDL as well once the service is discoveryed
+ * Will auto trigger the browse over AWDL as well once the service is discovered
* over BLE.
* This flag is an input value to DNSServiceBrowse(), which is why we can
* use the same value as kDNSServiceFlagsMoreComing, which is an output flag
/*
* Client guarantees that record names are unique, so we can skip sending out initial
* probe messages. Standard name conflict resolution is still done if a conflict is discovered.
- * Currently only valid for a DNSServiceRegister call.
*/
kDNSServiceFlagsReturnIntermediates = 0x1000,
* (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
*/
- kDNSServiceFlagsNonBrowsable = 0x2000,
- /* A service registered with the NonBrowsable flag set can be resolved using
- * DNSServiceResolve(), but will not be discoverable using DNSServiceBrowse().
- * This is for cases where the name is actually a GUID; it is found by other means;
- * there is no end-user benefit to browsing to find a long list of opaque GUIDs.
- * Using the NonBrowsable flag creates SRV+TXT without the cost of also advertising
- * an associated PTR record.
- */
-
kDNSServiceFlagsShareConnection = 0x4000,
/* For efficiency, clients that perform many concurrent operations may want to use a
* single Unix Domain Socket connection with the background daemon, instead of having a
* separate connection for each independent operation. To use this mode, clients first
- * call DNSServiceCreateConnection(&MainRef) to initialize the main DNSServiceRef.
+ * call DNSServiceCreateConnection(&SharedRef) to initialize the main DNSServiceRef.
* For each subsequent operation that is to share that same connection, the client copies
- * the MainRef, and then passes the address of that copy, setting the ShareConnection flag
+ * the SharedRef, and then passes the address of that copy, setting the ShareConnection flag
* to tell the library that this DNSServiceRef is not a typical uninitialized DNSServiceRef;
* it's a copy of an existing DNSServiceRef whose connection information should be reused.
*
* For example:
*
* DNSServiceErrorType error;
- * DNSServiceRef MainRef;
- * error = DNSServiceCreateConnection(&MainRef);
+ * DNSServiceRef SharedRef;
+ * error = DNSServiceCreateConnection(&SharedRef);
* if (error) ...
- * DNSServiceRef BrowseRef = MainRef; // Important: COPY the primary DNSServiceRef first...
+ * DNSServiceRef BrowseRef = SharedRef; // Important: COPY the primary DNSServiceRef first...
* error = DNSServiceBrowse(&BrowseRef, kDNSServiceFlagsShareConnection, ...); // then use the copy
* if (error) ...
* ...
* DNSServiceRefDeallocate(BrowseRef); // Terminate the browse operation
- * DNSServiceRefDeallocate(MainRef); // Terminate the shared connection
- * Also see Point 4.(Don't Double-Deallocate if the MainRef has been Deallocated) in Notes below:
+ * DNSServiceRefDeallocate(SharedRef); // Terminate the shared connection
*
* Notes:
*
* DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
* cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
*
- * 4. Don't Double-Deallocate if the MainRef has been Deallocated
- * Calling DNSServiceRefDeallocate(ref) for a particular operation's DNSServiceRef terminates
- * just that operation. Calling DNSServiceRefDeallocate(ref) for the main shared DNSServiceRef
- * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&ref))
- * automatically terminates the shared connection and all operations that were still using it.
+ * 4. Don't Double-Deallocate
+ * Calling DNSServiceRefDeallocate(OpRef) for a particular operation's DNSServiceRef terminates
+ * just that operation. Calling DNSServiceRefDeallocate(SharedRef) for the main shared DNSServiceRef
+ * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&SharedRef))
+ * automatically terminates the shared connection *and* all operations that were still using it.
* After doing this, DO NOT then attempt to deallocate any remaining subordinate DNSServiceRef's.
* The memory used by those subordinate DNSServiceRef's has already been freed, so any attempt
* to do a DNSServiceRefDeallocate (or any other operation) on them will result in accesses
* to freed memory, leading to crashes or other equally undesirable results.
+ * You can deallocate individual operations first and then deallocate the parent DNSServiceRef last,
+ * but if you deallocate the parent DNSServiceRef first, then all of the subordinate DNSServiceRef's
+ * are implicitly deallocated, and explicitly deallocating them a second time will lead to crashes.
*
* 5. Thread Safety
* The dns_sd.h API does not presuppose any particular threading model, and consequently
* If the client concurrently, from multiple threads (or contexts), calls API routines using
* the same DNSServiceRef, it is the client's responsibility to provide mutual exclusion for
* that DNSServiceRef.
-
+ *
* For example, use of DNSServiceRefDeallocate requires caution. A common mistake is as follows:
* Thread B calls DNSServiceRefDeallocate to deallocate sdRef while Thread A is processing events
* using sdRef. Doing this will lead to intermittent crashes on thread A if the sdRef is used after
* it was deallocated.
-
+ *
* A telltale sign of this crash type is to see DNSServiceProcessResult on the stack preceding the
* actual crash location.
-
+ *
* To state this more explicitly, mDNSResponder does not queue DNSServiceRefDeallocate so
* that it occurs discretely before or after an event is handled.
*/
* is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on
* input to a DNSServiceBrowse call.
*/
- kDNSServiceFlagsPrivateOne = 0x8000000,
+ kDNSServiceFlagsPrivateOne = 0x2000,
/*
* This flag is private and should not be used.
*/
- kDNSServiceFlagsPrivateTwo = 0x10000000,
+ kDNSServiceFlagsPrivateTwo = 0x8000000,
/*
* This flag is private and should not be used.
*/
- kDNSServiceFlagsPrivateThree = 0x20000000,
+ kDNSServiceFlagsPrivateThree = 0x10000000,
/*
* This flag is private and should not be used.
*/
- kDNSServiceFlagsPrivateFour = 0x40000000,
+ kDNSServiceFlagsPrivateFour = 0x20000000,
/*
* This flag is private and should not be used.
*/
+ kDNSServiceFlagsPrivateFive = 0x40000000,
+ /*
+ * This flag is private and should not be used.
+ */
+
+
+ kDNSServiceFlagAnsweredFromCache = 0x40000000,
+ /*
+ * When kDNSServiceFlagAnsweredFromCache is passed back in the flags parameter of DNSServiceQueryRecordReply or DNSServiceGetAddrInfoReply,
+ * an answer will have this flag set if it was answered from the cache.
+ */
+
kDNSServiceFlagsAllowExpiredAnswers = 0x80000000,
/*
* When kDNSServiceFlagsAllowExpiredAnswers is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo,
kDNSServiceErr_NATPortMappingDisabled = -65565, /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */
kDNSServiceErr_NoRouter = -65566, /* No router currently configured (probably no network connectivity) */
kDNSServiceErr_PollingMode = -65567,
- kDNSServiceErr_Timeout = -65568
+ kDNSServiceErr_Timeout = -65568,
+ kDNSServiceErr_DefunctConnection = -65569 /* Connection to daemon returned a SO_ISDEFUNCT error result */
/* mDNS Error codes are in the range
* FFFE FF00 (-65792) to FFFE FFFF (-65537) */
* conventional DNS escaping rules, as used by the traditional DNS res_query() API, as described below:
*
* Generally all UTF-8 characters (which includes all US ASCII characters) represent themselves,
- * with two exceptions, the dot ('.') character, which is the label separator,
- * and the backslash ('\') character, which is the escape character.
+ * with three exceptions:
+ * the dot ('.') character, which is the DNS label separator,
+ * the backslash ('\') character, which is the DNS escape character, and
+ * the ASCII NUL (0) byte value, which is the C-string terminator character.
* The escape character ('\') is interpreted as described below:
*
* '\ddd', where ddd is a three-digit decimal value from 000 to 255,
* For example, the ASCII code for 'w' is 119, and therefore '\119' is equivalent to 'w'.
* Thus the command "ping '\119\119\119.apple.com'" is the equivalent to the command "ping 'www.apple.com'".
* Nonprinting ASCII characters in the range 0-31 are often represented this way.
- * In particular, the ASCII NUL character (0) cannot appear in a C string because C uses it as the
- * string terminator character, so ASCII NUL in a domain name has to be represented in a C string as '\000'.
+ * In particular, the ASCII NUL character (0) cannot appear in a C-string because C uses it as the
+ * string terminator character, so ASCII NUL in a domain name has to be represented in a C-string as '\000'.
* Other characters like space (ASCII code 32) are sometimes represented as '\032'
- * in contexts where having an actual space character in a C string would be inconvenient.
+ * in contexts where having an actual space character in a C-string would be inconvenient.
*
* Otherwise, for all cases where a '\' is followed by anything other than a three-digit decimal value
* from 000 to 255, the character sequence '\x' represents a single literal occurrence of character 'x'.
* followed by neither a three-digit decimal value from 000 to 255 nor a single character.
* If a lone escape character ('\') does appear as the last character of a string, it is silently ignored.
*
+ * The worse-case length for an escaped domain name is calculated as follows:
+ * The longest legal domain name is 256 bytes in wire format (see RFC 6762, Appendix C, DNS Name Length).
+ * For our calculation of the longest *escaped* domain name, we use
+ * the longest legal domain name, with the most characters escaped.
+ *
+ * We consider a domain name of the form: "label63.label63.label63.label62."
+ * where "label63" is a 63-byte label and "label62" is a 62-byte label.
+ * Counting four label-length bytes, 251 bytes of label data, and the terminating zero,
+ * this makes a total of 256 bytes in wire format, the longest legal domain name.
+ *
+ * If each one of the 251 bytes of label data is represented using '\ddd',
+ * then it takes 251 * 4 = 1004 bytes to represent these in a C-string.
+ * Adding four '.' characters as shown above, plus the C-string terminating
+ * zero at the end, results in a maximum storage requirement of 1009 bytes.
+ *
* The exceptions, that do not use escaping, are the routines where the full
* DNS name of a resource is broken, for convenience, into servicename/regtype/domain.
* In these routines, the "servicename" is NOT escaped. It does not need to be, since
* is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
* functions.
*
+ * If the reference was passed to DNSServiceSetDispatchQueue(), DNSServiceRefDeallocate() must
+ * be called on the same queue originally passed as an argument to DNSServiceSetDispatchQueue().
+ *
* Note: This call is to be used only with the DNSServiceRef defined by this API.
*
* sdRef: A DNSServiceRef initialized by any of the DNSService calls.
/* DNSServiceEnumerateDomains() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the enumeration operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the enumeration operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
* flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
* kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
* kDNSServiceFlagsRegistrationDomains to enumerate domains recommended
* for registration.
/* DNSServiceRegister() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the registration will remain active indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the service registration
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Indicates the renaming behavior on name conflict (most applications
- * will pass 0). See flag definitions above for details.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * Other flags indicate the renaming behavior on name conflict
+ * (not required for most applications).
+ * See flag definitions above for details.
*
* interfaceIndex: If non-zero, specifies the interface on which to register the service
* (the index for a given interface is determined via the if_nametoindex()
*
* % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
*
- * When a service is registered, all the clients browsing for the registered
- * type ("regtype") will discover it. If the discovery should be
- * restricted to a smaller set of well known peers, the service can be
- * registered with additional data (group identifier) that is known
- * only to a smaller set of peers. The group identifier should follow primary
- * service type using a colon (":") as a delimeter. If subtypes are also present,
- * it should be given before the subtype as shown below.
- *
- * % dns-sd -R _test1 _http._tcp:mygroup1 local 1001
- * % dns-sd -R _test2 _http._tcp:mygroup2 local 1001
- * % dns-sd -R _test3 _http._tcp:mygroup3,HasFeatureA local 1001
- *
- * Now:
- * % dns-sd -B _http._tcp:"mygroup1" # will discover only test1
- * % dns-sd -B _http._tcp:"mygroup2" # will discover only test2
- * % dns-sd -B _http._tcp:"mygroup3",HasFeatureA # will discover only test3
- *
- * By specifying the group information, only the members of that group are
- * discovered.
- *
- * The group identifier itself is not sent in clear. Only a hash of the group
- * identifier is sent and the clients discover them anonymously. The group identifier
- * may be up to 256 bytes long and may contain any eight bit values except comma which
- * should be escaped.
- *
* domain: If non-NULL, specifies the domain on which to advertise the service.
* Most applications will not specify a domain, instead automatically
* registering in the default domain(s).
/* DNSServiceBrowse() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the browse operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the browse operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Currently ignored, reserved for future use.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
*
* interfaceIndex: If non-zero, specifies the interface on which to browse for services
* (the index for a given interface is determined via the if_nametoindex()
* A client may optionally specify a single subtype to perform filtered browsing:
* e.g. browsing for "_primarytype._tcp,_subtype" will discover only those
* instances of "_primarytype._tcp" that were registered specifying "_subtype"
- * in their list of registered subtypes. Additionally, a group identifier may
- * also be specified before the subtype e.g., _primarytype._tcp:GroupID, which
- * will discover only the members that register the service with GroupID. See
- * DNSServiceRegister for more details.
+ * in their list of registered subtypes.
*
* domain: If non-NULL, specifies the domain on which to browse for services.
* Most applications will not specify a domain, instead browsing on the
/* DNSServiceResolve() Parameters
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the resolve operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the resolve operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * Specifying kDNSServiceFlagsForceMulticast will cause query to be
* performed with a link-local mDNS query, even if the name is an
* apparently non-local name (i.e. a name not ending in ".local.")
*
/* DNSServiceQueryRecord() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds
- * then it initializes the DNSServiceRef, returns kDNSServiceErr_NoError,
- * and the query operation will run indefinitely until the client
- * terminates it by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the query operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
* Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
* query to a unicast DNS server that implements the protocol. This flag
* has no effect on link-local multicast queries.
/* DNSServiceGetAddrInfo() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
- * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the query
- * begins and will last indefinitely until the client terminates the query
- * by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the address query operation
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: kDNSServiceFlagsForceMulticast
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
+ * kDNSServiceFlagsForceMulticast
*
* interfaceIndex: The interface on which to issue the query. Passing 0 causes the query to be
* sent on all active interfaces via Multicast or the primary interface via Unicast.
*
* Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. Deallocating
- * the reference (via DNSServiceRefDeallocate()) severs the
- * connection and deregisters all records registered on this connection.
+ * sdRef: A pointer to an uninitialized DNSServiceRef.
+ * Deallocating the reference (via DNSServiceRefDeallocate())
+ * severs the connection and cancels all operations and
+ * deregisters all records registered on this connection.
*
* return value: Returns kDNSServiceErr_NoError on success, otherwise returns
- * an error code indicating the specific failure that occurred (in which
- * case the DNSServiceRef is not initialized).
+ * an error code indicating the specific failure that occurred
+ * (in which case the DNSServiceRef is not initialized).
*/
DNSSD_EXPORT
* and deallocate each of their corresponding DNSServiceRecordRefs, call
* DNSServiceRefDeallocate()).
*
- * flags: Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
- * (see flag type definitions for details).
+ * flags: One of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique must be set.
*
* interfaceIndex: If non-zero, specifies the interface on which to register the record
* (the index for a given interface is determined via the if_nametoindex()
/* DNSServiceNATPortMappingCreate() Parameters:
*
- * sdRef: A pointer to an uninitialized DNSServiceRef. If the call succeeds then it
- * initializes the DNSServiceRef, returns kDNSServiceErr_NoError, and the nat
- * port mapping will last indefinitely until the client terminates the port
- * mapping request by passing this DNSServiceRef to DNSServiceRefDeallocate().
+ * sdRef: A pointer to an uninitialized DNSServiceRef
+ * (or, if the kDNSServiceFlagsShareConnection flag is used,
+ * a copy of the shared connection reference that is to be used).
+ * If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ * returns kDNSServiceErr_NoError, and the NAT port mapping
+ * will remain active indefinitely until the client terminates it
+ * by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ * (or by closing the underlying shared connection, if used).
*
- * flags: Currently ignored, reserved for future use.
+ * flags: Possible values are:
+ * kDNSServiceFlagsShareConnection to use a shared connection.
*
- * interfaceIndex: The interface on which to create port mappings in a NAT gateway. Passing 0 causes
- * the port mapping request to be sent on the primary interface.
+ * interfaceIndex: The interface on which to create port mappings in a NAT gateway.
+ * Passing 0 causes the port mapping request to be sent on the primary interface.
*
* protocol: To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
* or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
*
* If the buffer parameter is NULL, or the specified storage size is not
* large enough to hold a key subsequently added using TXTRecordSetValue(),
- * then additional memory will be added as needed using malloc().
+ * then additional memory will be added as needed using malloc(). Note that
+ * an existing TXT record buffer should not be passed to TXTRecordCreate
+ * to create a copy of another TXT Record. The correct way to copy TXTRecordRef
+ * is creating an empty TXTRecordRef with TXTRecordCreate() first, and using
+ * TXTRecordSetValue to set the same value.
*
* On some platforms, when memory is low, malloc() may fail. In this
* case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this
* keyBufLen: The size of the string buffer being supplied.
*
* key: A string buffer used to store the key name.
- * On return, the buffer contains a null-terminated C string
+ * On return, the buffer contains a null-terminated C-string
* giving the key name. DNS-SD TXT keys are usually
* 9 characters or fewer. To hold the maximum possible
* key name, the buffer should be 256 bytes long.
* DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
* queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
* the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+ * Note that the call to DNSServiceRefDeallocate() must be done on the same queue originally passed
+ * as an argument to DNSServiceSetDispatchQueue().
*
* service: DNSServiceRef that was allocated and returned to the application, when the
* application calls one of the DNSService API.
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2015-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2019 Apple Inc. All rights reserved.
*/
#ifndef _DNS_SD_PRIVATE_H
#include <dns_sd.h>
-// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour) from dns_sd.h
+// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour, kDNSServiceFlagsPrivateFive) from dns_sd.h
enum
{
+ kDNSServiceFlagsDenyConstrained = 0x2000,
+ /*
+ * This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
+ * DNS resolutions on interfaces defined as constrained for that request.
+ */
+
kDNSServiceFlagsDenyCellular = 0x8000000,
/*
* This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
*/
};
-
-#if !DNSSD_NO_CREATE_DELEGATE_CONNECTION
+#if !defined(DNSSD_NO_CREATE_DELEGATE_CONNECTION) || !DNSSD_NO_CREATE_DELEGATE_CONNECTION
/* DNSServiceCreateDelegateConnection()
*
* Parameters:
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
mDNSIPPort port = zeroIPPort;
int fd;
- TCPSocket *sock = mDNSPlatformTCPSocket(0, &port, mDNSfalse );
+ TCPSocket *sock = mDNSPlatformTCPSocket(0, mDNSAddrType_IPv4, &port, NULL, mDNSfalse );
if ( !sock ) { LogErr("ConnectToServer", "socket"); return NULL; }
fd = mDNSPlatformTCPGetFD( sock );
if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
{
DNSQuestion q;
LargeCacheRecord opt;
- int i, err = -1;
+ unsigned int i;
+ int err = -1;
char addr[32];
const mDNSu8 *qptr = pkt->msg.data;
const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
for (i = 0; i < pkt->msg.h.numAdditionals; i++)
{
aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
- if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
+ if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %u", addr, i); goto end; }
if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
}
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; }
+ if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %u", addr, i); goto end; }
llq = &opt.r.resrec.rdata->u.opt[i].u.llq; // 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; }
const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
{ ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const int serviceID, const mDNSAddr *addr, const mDNSIPPort port,
- mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
-{ ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf; (void) isExpensive; (void) isCLAT46;
- (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
+ mDNSu32 scopedType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46, mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+{ ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scopedType; ( void ) timeout; (void) isCell; (void) isExpensive; (void) isConstrained; (void) isCLAT46;
+ (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
{ ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
{ ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
- const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
-{ ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; ( void ) autoTunnel; return 0; }
+ const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
+{ ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; return 0; }
mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
void TriggerEventCompletion(void);
void TriggerEventCompletion() {}
-int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) { ( void ) rr; ( void ) q; return 1;}
mDNS mDNSStorage;
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2018 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.
#define _dnsextd_h
-#include <mDNSEmbeddedAPI.h>
-#include <DNSCommon.h>
-#include <GenLinkedList.h>
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
+#include "GenLinkedList.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
#include "dns_sd.h" // Defines the interface to the client layer above
#include "mDNSEmbeddedAPI.h" // The interface we're building on top of
+#include <sys/socket.h>
+#include <netinet/in.h>
extern mDNS mDNSStorage; // We need to pass the address of this storage to the lower-layer functions
#if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
DNSQuestion q;
} mDNS_DirectOP_QueryRecord;
+typedef struct
+{
+ mDNS_DirectOP_Dispose *disposefn;
+ DNSServiceGetAddrInfoReply callback;
+ void *context;
+ mDNSu32 interfaceIndex;
+ DNSQuestion a;
+ DNSQuestion aaaa;
+} mDNS_DirectOP_GetAddrInfo;
+
dnssd_sock_t DNSServiceRefSockFD(DNSServiceRef sdRef)
{
(void)sdRef; // Unused
op->disposefn(op);
}
+static mDNSInterfaceID DNSServiceInterfaceIndexToID(mDNSu32 interfaceIndex, DNSServiceFlags *flags)
+{
+ // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
+ // flag set so that the resolve will run over P2P interfaces that are not yet created.
+ if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
+ {
+ LogOperation("handle_resolve_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
+ if (flags != mDNSNULL) *flags |= kDNSServiceFlagsIncludeP2P;
+ interfaceIndex = kDNSServiceInterfaceIndexAny;
+ }
+ return mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+}
+
//*************************************************************************************************************
// Domain Enumeration
// Allocate memory, and handle failure
if (size < txtLen)
size = txtLen;
- x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size);
+ x = (mDNS_DirectOP_Register *) mDNSPlatformMemAllocateClear(sizeof(*x) - sizeof(RDataBody) + size);
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
// Set up object
err = mDNS_RegisterService(&mDNSStorage, &x->s,
&x->name, &t, &d, // Name, type, domain
&x->host, port, // Host and port
+ mDNSNULL,
txtRecord, txtLen, // TXT data, length
SubTypes, NumSubTypes, // Subtypes
mDNSInterface_Any, // Interface ID
if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain"; goto badparam; }
// Allocate memory, and handle failure
- x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x));
+ x = (mDNS_DirectOP_Browse *) mDNSPlatformMemAllocateClear(sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
// Set up object
x->q.QuestionContext = x;
// Do the operation
- err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSNULL, mDNSInterface_Any, flags, (flags & kDNSServiceFlagsForceMulticast) != 0, (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, x);
+ err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, flags, (flags & kDNSServiceFlagsForceMulticast) != 0, (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, x);
if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
// Succeeded: Wrap up and return
domainname t, d, srv;
mDNS_DirectOP_Resolve *x;
- (void)flags; // Unused
- (void)interfaceIndex; // Unused
-
// Check parameters
if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name )) { errormsg = "Bad Instance Name"; goto badparam; }
if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; }
if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; }
// Allocate memory, and handle failure
- x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x));
+ x = (mDNS_DirectOP_Resolve *) mDNSPlatformMemAllocateClear(sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
// Set up object
x->TXT = mDNSNULL;
x->qSRV.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
- x->qSRV.InterfaceID = mDNSInterface_Any;
- x->qSRV.flags = 0;
- x->qSRV.Target = zeroAddr;
+ x->qSRV.InterfaceID = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
+ x->qSRV.flags = flags;
AssignDomainName(&x->qSRV.qname, &srv);
x->qSRV.qtype = kDNSType_SRV;
x->qSRV.qclass = kDNSClass_IN;
x->qSRV.ForceMCast = mDNSfalse;
x->qSRV.ReturnIntermed = mDNSfalse;
x->qSRV.SuppressUnusable = mDNSfalse;
- x->qSRV.SearchListIndex = 0;
x->qSRV.AppendSearchDomains = 0;
- x->qSRV.RetryWithSearchDomains = mDNSfalse;
x->qSRV.TimeoutQuestion = 0;
x->qSRV.WakeOnResolve = 0;
- x->qSRV.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+ x->qSRV.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
x->qSRV.ValidationRequired = 0;
x->qSRV.ValidatingResponse = 0;
x->qSRV.ProxyQuestion = 0;
- x->qSRV.qnameOrig = mDNSNULL;
- x->qSRV.AnonInfo = mDNSNULL;
x->qSRV.pid = mDNSPlatformGetPID();
x->qSRV.QuestionCallback = FoundServiceInfo;
x->qSRV.QuestionContext = x;
x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
- x->qTXT.InterfaceID = mDNSInterface_Any;
- x->qTXT.flags = 0;
- x->qTXT.Target = zeroAddr;
+ x->qTXT.InterfaceID = DNSServiceInterfaceIndexToID(interfaceIndex, mDNSNULL);
+ x->qTXT.flags = flags;
AssignDomainName(&x->qTXT.qname, &srv);
x->qTXT.qtype = kDNSType_TXT;
x->qTXT.qclass = kDNSClass_IN;
x->qTXT.ForceMCast = mDNSfalse;
x->qTXT.ReturnIntermed = mDNSfalse;
x->qTXT.SuppressUnusable = mDNSfalse;
- x->qTXT.SearchListIndex = 0;
x->qTXT.AppendSearchDomains = 0;
- x->qTXT.RetryWithSearchDomains = mDNSfalse;
x->qTXT.TimeoutQuestion = 0;
x->qTXT.WakeOnResolve = 0;
- x->qTXT.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+ x->qTXT.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
x->qTXT.ValidationRequired = 0;
x->qTXT.ValidatingResponse = 0;
x->qTXT.ProxyQuestion = 0;
- x->qTXT.qnameOrig = mDNSNULL;
- x->qTXT.AnonInfo = mDNSNULL;
x->qTXT.pid = mDNSPlatformGetPID();
x->qTXT.QuestionCallback = FoundServiceInfo;
x->qTXT.QuestionContext = x;
DNSServiceErrorType DNSServiceQueryRecord
(
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *fullname,
- uint16_t rrtype,
- uint16_t rrclass,
+ DNSServiceRef *sdRef,
+ DNSServiceFlags flags,
+ uint32_t interfaceIndex,
+ const char *fullname,
+ uint16_t rrtype,
+ uint16_t rrclass,
DNSServiceQueryRecordReply callback,
- void *context /* may be NULL */
+ void *context /* may be NULL */
)
{
mStatus err = mStatus_NoError;
const char *errormsg = "Unknown";
mDNS_DirectOP_QueryRecord *x;
- (void)flags; // Unused
- (void)interfaceIndex; // Unused
-
// Allocate memory, and handle failure
- x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x));
+ x = (mDNS_DirectOP_QueryRecord *) mDNSPlatformMemAllocateClear(sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
// Set up object
x->callback = callback;
x->context = context;
- x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
- x->q.InterfaceID = mDNSInterface_Any;
- x->q.flags = flags;
- x->q.Target = zeroAddr;
+ x->q.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question
+ x->q.InterfaceID = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
+ x->q.flags = flags;
MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
- x->q.qtype = rrtype;
- x->q.qclass = rrclass;
- x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
- x->q.ExpectUnique = mDNSfalse;
- x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
- x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
- x->q.SuppressUnsable = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
- x->q.SearchListIndex = 0;
- x->q.AppendSearchDomains = 0;
- x->q.RetryWithSearchDomains = mDNSfalse;
- x->q.TimeoutQuestion = 0;
- x->q.WakeOnResolve = 0;
- x->q.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- x->q.ValidationRequired = 0;
- x->q.ValidatingResponse = 0;
- x->q.ProxyQuestion = 0;
- x->q.qnameOrig = mDNSNULL;
- x->q.AnonInfo = mDNSNULL;
- x->q.pid = mDNSPlatformGetPID();
- x->q.QuestionCallback = DNSServiceQueryRecordResponse;
- x->q.QuestionContext = x;
+ x->q.qtype = rrtype;
+ x->q.qclass = rrclass;
+ x->q.LongLived = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
+ x->q.ExpectUnique = mDNSfalse;
+ x->q.ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
+ x->q.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+ x->q.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
+ x->q.AppendSearchDomains = 0;
+ x->q.TimeoutQuestion = 0;
+ x->q.WakeOnResolve = 0;
+ x->q.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+ x->q.ValidationRequired = 0;
+ x->q.ValidatingResponse = 0;
+ x->q.ProxyQuestion = 0;
+ x->q.pid = mDNSPlatformGetPID();
+ x->q.QuestionCallback = DNSServiceQueryRecordResponse;
+ x->q.QuestionContext = x;
err = mDNS_StartQuery(&mDNSStorage, &x->q);
if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
//*************************************************************************************************************
// DNSServiceGetAddrInfo
+//
static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
{
mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
- if (x->aQuery) DNSServiceRefDeallocate(x->aQuery);
+ if (x->a.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->a);
+ if (x->aaaa.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->aaaa);
mDNSPlatformMemFree(x);
}
-static void DNSSD_API DNSServiceGetAddrInfoResponse(
- DNSServiceRef inRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inErrorCode,
- const char * inFullName,
- uint16_t inRRType,
- uint16_t inRRClass,
- uint16_t inRDLen,
- const void * inRData,
- uint32_t inTTL,
- void * inContext )
-{
- mDNS_DirectOP_GetAddrInfo * x = (mDNS_DirectOP_GetAddrInfo*)inContext;
- struct sockaddr_in sa4;
-
- mDNSPlatformMemZero(&sa4, sizeof(sa4));
- if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A)
+mDNSlocal void DNSServiceGetAddrInfoResponse(mDNS *const m, DNSQuestion *question,
+ const ResourceRecord *const answer, QC_result addRecord)
+{
+ mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)question->QuestionContext;
+ char fullname[MAX_ESCAPED_DOMAIN_NAME];
+
+ struct sockaddr_storage sas;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&sas;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sas;
+ void *sa_ap = mDNSNULL;
+ int sa_as = 0;
+ mStatus err = mStatus_NoError;
+
+ (void)m; // Unused
+
+ mDNSPlatformMemZero(&sas, sizeof sas);
+
+ ConvertDomainNameToCString(answer->name, fullname);
+
+ if (addRecord == QC_suppressed || answer->RecordType == kDNSRecordTypePacketNegative)
{
- sa4.sin_family = AF_INET;
- mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4);
+ err = mStatus_NoSuchRecord;
+ }
+
+ // There are three checks here for bad data: class != IN, RRTYPE not in {A,AAAA} and wrong length.
+ // None of these should be possible, because the cache code wouldn't cache malformed data and wouldn't
+ // return records we didn't ask for, but it doesn't hurt to check.
+ if (answer->rrclass != kDNSServiceClass_IN)
+ {
+ LogMsg("DNSServiceGetAddrInfoResponse: response of class %d received, which is bogus", answer->rrclass);
+ totally_invalid:
+ if (x->a.ThisQInterval >= 0)
+ {
+ sin->sin_family = AF_INET;
+#ifndef NOT_HAVE_SA_LEN
+ sin->sin_len = sizeof *sin;
+#endif
+ x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
+ (const struct sockaddr *)&sas, 0, x->context);
+ }
+ if (x->aaaa.ThisQInterval >= 0)
+ {
+ sin6->sin6_family = AF_INET6;
+#ifndef NOT_HAVE_SA_LEN
+ sin6->sin6_len = sizeof *sin6;
+#endif
+ x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
+ (const struct sockaddr *)&sas, 0, x->context);
+ }
+ return;
+ }
+ else if (answer->rrtype == kDNSServiceType_A)
+ {
+ sin->sin_family = AF_INET;
+#ifndef NOT_HAVE_SA_LEN
+ sin->sin_len = sizeof *sin;
+#endif
+ sa_ap = &sin->sin_addr;
+ sa_as = sizeof sin->sin_addr.s_addr;
+ }
+ else if (answer->rrtype == kDNSServiceType_AAAA)
+ {
+ sin6->sin6_family = AF_INET6;
+#ifndef NOT_HAVE_SA_LEN
+ sin6->sin6_len = sizeof *sin6;
+#endif
+ sa_ap = &sin6->sin6_addr;
+ sa_as = sizeof sin6->sin6_addr.s6_addr;
+ }
+ else
+ {
+ LogMsg("DNSServiceGetAddrInfoResponse: response of type %d received, which is bogus", answer->rrtype);
+ goto totally_invalid;
+ }
+
+ if (err == kDNSServiceErr_NoError && sa_ap != mDNSNULL)
+ {
+ if (err == mStatus_NoError)
+ {
+ if (answer->rdlength == sa_as)
+ {
+ mDNSPlatformMemCopy(sa_ap, answer->rdata->u.data, answer->rdlength);
+ }
+ else
+ {
+ LogMsg("DNSServiceGetAddrInfoResponse: %s rrtype with length %d received",
+ answer->rrtype == kDNSServiceType_A ? "A" : "AAAA", answer->rdlength);
+ goto totally_invalid;
+ }
+ }
}
- x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName,
- (const struct sockaddr *) &sa4, inTTL, x->context);
+ x->callback((DNSServiceRef)x, addRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, x->interfaceIndex, err,
+ fullname, (const struct sockaddr *)&sas, answer->rroriginalttl, x->context);
}
DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo(
- DNSServiceRef * outRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceProtocol inProtocol,
- const char * inHostName,
+ DNSServiceRef *outRef,
+ DNSServiceFlags inFlags,
+ uint32_t inInterfaceIndex,
+ DNSServiceProtocol inProtocol,
+ const char *inHostName,
DNSServiceGetAddrInfoReply inCallback,
- void * inContext )
+ void *inContext )
{
- const char * errormsg = "Unknown";
- DNSServiceErrorType err;
- mDNS_DirectOP_GetAddrInfo * x;
+ const char *errormsg = "Unknown";
+ DNSServiceErrorType err;
+ mDNS_DirectOP_GetAddrInfo *x;
// Allocate memory, and handle failure
- x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x));
+ x = (mDNS_DirectOP_GetAddrInfo *) mDNSPlatformMemAllocateClear(sizeof(*x));
if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
// Set up object
- x->disposefn = DNSServiceGetAddrInfoDispose;
- x->callback = inCallback;
- x->context = inContext;
- x->aQuery = mDNSNULL;
-
- // Start the query.
- // (It would probably be more efficient to code this using mDNS_StartQuery directly,
- // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates
- // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010)
- err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A,
- kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x);
- if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; }
+ x->disposefn = DNSServiceGetAddrInfoDispose;
+ x->callback = inCallback;
+ x->context = inContext;
+ x->interfaceIndex = inInterfaceIndex;
+
+ // Validate and default the protocols.
+ if ((inProtocol & ~(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) != 0)
+ {
+ err = mStatus_BadParamErr;
+ errormsg = "Unsupported protocol";
+ goto fail;
+ }
+ // In theory this API checks to see if we have a routable IPv6 address, but
+ if ((inProtocol & (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) == 0)
+ {
+ inProtocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
+ inFlags |= kDNSServiceFlagsSuppressUnusable;
+ }
+
+ x->a.ThisQInterval = -1; // So we know whether to cancel this question
+ x->a.InterfaceID = DNSServiceInterfaceIndexToID(inInterfaceIndex, &inFlags);
+ x->a.flags = inFlags;
+ MakeDomainNameFromDNSNameString(&x->a.qname, inHostName);
+ x->a.qtype = kDNSType_A;
+ x->a.qclass = kDNSClass_IN;
+ x->a.LongLived = (inFlags & kDNSServiceFlagsLongLivedQuery) != 0;
+ x->a.ExpectUnique = mDNSfalse;
+ x->a.ForceMCast = (inFlags & kDNSServiceFlagsForceMulticast) != 0;
+ x->a.ReturnIntermed = (inFlags & kDNSServiceFlagsReturnIntermediates) != 0;
+ x->a.SuppressUnusable = (inFlags & kDNSServiceFlagsSuppressUnusable) != 0;
+ x->a.AppendSearchDomains = 0;
+ x->a.TimeoutQuestion = 0;
+ x->a.WakeOnResolve = 0;
+ x->a.UseBackgroundTraffic = (inFlags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+ x->a.ValidationRequired = 0;
+ x->a.ValidatingResponse = 0;
+ x->a.ProxyQuestion = 0;
+ x->a.pid = mDNSPlatformGetPID();
+ x->a.QuestionCallback = DNSServiceGetAddrInfoResponse;
+ x->a.QuestionContext = x;
+
+ x->aaaa = x->a;
+ x->aaaa.qtype = kDNSType_AAAA;
+
+ if (inProtocol & kDNSServiceProtocol_IPv4)
+ {
+ err = mDNS_StartQuery(&mDNSStorage, &x->a);
+ if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
+ }
+ if (inProtocol & kDNSServiceProtocol_IPv6)
+ {
+ err = mDNS_StartQuery(&mDNSStorage, &x->aaaa);
+ if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
+ }
*outRef = (DNSServiceRef)x;
return(mStatus_NoError);
return(kDNSServiceErr_Unsupported);
}
+#endif // !MDNS_BUILDINGSTUBLIBRARY
-#endif // !MDNS_BUILDINGSTUBLIBRARY
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
}
#else
- #include <sys/fcntl.h> // For O_RDWR etc.
+ #include <fcntl.h> // For O_RDWR etc.
#include <sys/time.h>
#include <sys/socket.h>
#include <syslog.h>
#endif
+#if defined(_WIN32)
// <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
#define DNSSD_CLIENT_MAXTRIES 4
+#endif // _WIN32
// Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
//#define USE_NAMED_ERROR_RETURN_SOCKET 1
}
#endif
+enum { write_all_success = 0, write_all_fail = -1, write_all_defunct = -2 };
+
// Write len bytes. Return 0 on success, -1 on error
static int write_all(dnssd_sock_t sd, char *buf, size_t len)
{
// Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
- //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
+ //if (send(sd, buf, len, MSG_WAITALL) != len) return write_all_fail;
while (len)
{
ssize_t num_written = send(sd, buf, (long)len, 0);
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
else
syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+ return defunct ? write_all_defunct : write_all_fail;
#else
syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
(long)num_written, (long)len,
(num_written < 0) ? dnssd_errno : 0,
(num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+ return write_all_fail;
#endif
- return -1;
}
buf += num_written;
len -= num_written;
}
- return 0;
+ return write_all_success;
}
-enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
+enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2, read_all_defunct = -3 };
// 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)
(num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
else if (defunct)
syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
- return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
+ return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : (defunct ? read_all_defunct : read_all_fail);
}
buf += num_read;
len -= num_read;
FD_SET(sd, fs);
ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
#else
+ // This whole thing would probably be better done using kevent() instead of select()
if (sd < FD_SETSIZE)
{
fs = &readfds;
{
int gDaemonErr = kDNSServiceErr_NoError;
+ // The comment below is wrong. The select() routine does not cause stack corruption.
+ // The use of FD_SET out of range for the bitmap is what causes stack corruption.
+ // For how to do this correctly, see the example using calloc() in more_bytes() above.
+ // Even better, both should be changed to use kevent() instead of select().
// To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
if (!gDaemonErr && sock < FD_SETSIZE)
{
// then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
if ((x->sockfd ^ x->validator) != ValidatorBits)
{
- static DNSServiceOp *op_were_not_going_to_free_but_we_need_to_fool_the_analyzer;
- syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
- op_were_not_going_to_free_but_we_need_to_fool_the_analyzer = x;
}
else
{
// Return a connected service ref (deallocate with DNSServiceRefDeallocate)
static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
{
+ #if defined(_WIN32)
int NumTries = 0;
+ #endif // _WIN32
dnssd_sockaddr_t saddr;
DNSServiceOp *sdr;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
}
// <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
- if (IsSystemServiceDisabled())
+ if (IsSystemServiceDisabled())
NumTries = DNSSD_CLIENT_MAXTRIES;
#endif
FreeDNSServiceOp(sdr);
return kDNSServiceErr_NoMemory;
}
+#if !defined(_WIN32)
+ int fcntl_flags = fcntl(sdr->sockfd, F_GETFD);
+ if (fcntl_flags != -1)
+ {
+ fcntl_flags |= FD_CLOEXEC;
+ int ret = fcntl(sdr->sockfd, F_SETFD, fcntl_flags);
+ if (ret == -1)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to set FD_CLOEXEC on socket %d %s",
+ dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+ else
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to get the file descriptor flags of socket %d %s",
+ dnssd_errno, dnssd_strerror(dnssd_errno));
+ }
+#endif // !defined(_WIN32)
#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)
}
#endif
#endif
-
+
+ #if defined(_WIN32)
while (1)
{
int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
if (!err)
break; // If we succeeded, return sdr
+
// If we failed, then it may be because the daemon is still launching.
// This can happen for processes that launch early in the boot process, while the
// daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
// then we give up and return a failure code.
if (++NumTries < DNSSD_CLIENT_MAXTRIES)
{
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
sleep(1); // Sleep a bit, then try again
}
- else
+ else
{
#if !defined(USE_TCP_LOOPBACK)
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
#endif
- dnssd_close(sdr->sockfd);
- FreeDNSServiceOp(sdr);
- return kDNSServiceErr_ServiceNotRunning;
+ dnssd_close(sdr->sockfd);
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_ServiceNotRunning;
}
}
- //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
+ #else
+ int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+ if (err)
+ {
+ #if !defined(USE_TCP_LOOPBACK)
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
+ uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
+ #endif
+ dnssd_close(sdr->sockfd);
+ FreeDNSServiceOp(sdr);
+ return kDNSServiceErr_ServiceNotRunning;
+ }
+ #endif
}
*ref = sdr;
dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
int MakeSeparateReturnSocket;
+ int ioresult;
#if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
char *data;
#endif
{
int defunct = 1;
if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
- syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
}
#endif
}
for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
{
syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
- if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
- { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
+ ioresult = write_all(sdr->sockfd, ((char *)hdr)+i, 1);
+ if (ioresult < write_all_success)
+ {
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request write_all (byte %u) failed", i);
+ err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+ goto cleanup;
+ }
usleep(10000);
}
#else
- if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
+ ioresult = write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr));
+ if (ioresult < write_all_success)
{
// write_all already prints an error message if there is an error writing to
// the socket except for DEFUNCT. Logging here is unnecessary and also wrong
// in the case of DEFUNCT sockets
syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+ err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
goto cleanup;
}
#endif
{
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)) syslog(LOG_WARNING, "dnssd_clientstub deliver_request 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));
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
}
}
#endif
#if DEBUG_64BIT_SCM_RIGHTS
- syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
}
#if DEBUG_64BIT_SCM_RIGHTS
- syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
+ syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
#endif // DEBUG_64BIT_SCM_RIGHTS
#endif
err = kDNSServiceErr_NoError;
else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
{
- if (read_all(errsd, (char*)&err, (int)sizeof(err)) < 0)
- err = kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
+ ioresult = read_all(errsd, (char*)&err, (int)sizeof(err));
+ if (ioresult < read_all_success)
+ err = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
else
err = ntohl(err);
}
if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
// The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
// Detect that and return early
- if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+ if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:Record: CallbackwithError morebytes zero"); return; }
rec = recnext;
}
break;
//
// If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
// we don't access the stack variable after we return from this function.
- if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
+ if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return; }
else {sdr->moreptr = NULL;}
sdr = sdrNext;
}
DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
{
int morebytes = 0;
+ int ioresult;
+ DNSServiceErrorType error;
if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
// where a non-blocking socket is told there is data, but it was a false positive.
// On error, read_all will write a message to syslog for us, so don't need to duplicate that here
// Note: If we want to properly support using non-blocking sockets in the future
- int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
- if (result == read_all_fail)
+ ioresult = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
+ if (ioresult == read_all_fail || ioresult == read_all_defunct)
{
+ error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+
// Set the ProcessReply to NULL before callback as the sdRef can get deallocated
// in the callback.
sdRef->ProcessReply = NULL;
dispatch_source_cancel(sdRef->disp_source);
dispatch_release(sdRef->disp_source);
sdRef->disp_source = NULL;
- CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ CallbackWithError(sdRef, error);
}
#endif
// Don't touch sdRef anymore as it might have been deallocated
- return kDNSServiceErr_ServiceNotRunning;
+ return error;
}
- else if (result == read_all_wouldblock)
+ else if (ioresult == read_all_wouldblock)
{
if (morebytes && sdRef->logcounter < 100)
{
data = malloc(cbh.ipc_hdr.datalen);
if (!data) return kDNSServiceErr_NoMemory;
- if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
+ ioresult = read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen);
+ if (ioresult < read_all_success) // On error, read_all will write a message to syslog for us
{
+ error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+
// Set the ProcessReply to NULL before callback as the sdRef can get deallocated
// in the callback.
sdRef->ProcessReply = NULL;
dispatch_source_cancel(sdRef->disp_source);
dispatch_release(sdRef->disp_source);
sdRef->disp_source = NULL;
- CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+ CallbackWithError(sdRef, error);
}
#endif
// Don't touch sdRef anymore as it might have been deallocated
free(data);
- return kDNSServiceErr_ServiceNotRunning;
+ return error;
}
else
{
ipc_msg_hdr *hdr;
DNSServiceOp *tmp;
uint32_t actualsize;
+ int ioresult;
if (!property || !result || !size)
return kDNSServiceErr_BadParam;
err = deliver_request(hdr, tmp); // Will free hdr for us
if (err) { DNSServiceRefDeallocate(tmp); return err; }
- if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ ioresult = read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize));
+ if (ioresult < read_all_success)
+ { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
actualsize = ntohl(actualsize);
- if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ ioresult = read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size);
+ if (ioresult < read_all_success)
+ { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
DNSServiceRefDeallocate(tmp);
// Swap version result back to local process byte order
ipc_msg_hdr *hdr;
DNSServiceOp *tmp = NULL;
size_t len = sizeof(int32_t);
+ int ioresult;
DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
if (err) return err;
err = deliver_request(hdr, tmp); // Will free hdr for us
if (err) { DNSServiceRefDeallocate(tmp); return err; }
- if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
- { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+ ioresult = read_all(tmp->sockfd, (char*)pid, sizeof(int32_t));
+ if (ioresult < read_all_success)
+ { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
DNSServiceRefDeallocate(tmp);
return kDNSServiceErr_NoError;
syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
}
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
static int32_t libSystemVersion = 0;
return 0;
}
-#else // TARGET_OS_EMBEDDED
+#else // TARGET_OS_IPHONE
// always return false for non iOS platforms
static int includeP2PWithIndexAny()
return 0;
}
-#endif // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_IPHONE
DNSServiceErrorType DNSSD_API DNSServiceResolve
(
// error if the record is not found.
if (!rec)
{
- syslog(LOG_INFO, "ConnectionResponse: Record not found");
+ syslog(LOG_INFO, "dnssd_clientstub ConnectionResponse: Record not found");
return;
}
if (rec->sdr != sdr)
{
- syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
+ syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
return;
}
return err;
}
-#if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_SIMULATOR
DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
{
char *ptr;
if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
{
- syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno));
// Free the hdr in case we return before calling deliver_request()
if (hdr)
free(hdr);
if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
{
- syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
// Free the hdr in case we return before calling deliver_request()
if (hdr)
free(hdr);
}
return err;
}
-#elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
+#elif TARGET_OS_SIMULATOR // This hack is for Simulator platform only
DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
{
(void) pid;
ipc_msg_hdr *hdr = NULL;
DNSRecordRef rref = NULL;
DNSRecord **p;
+ // Verify that only one of the following flags is set.
int f1 = (flags & kDNSServiceFlagsShared) != 0;
int f2 = (flags & kDNSServiceFlagsUnique) != 0;
- if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+ int f3 = (flags & kDNSServiceFlagsKnownUnique) != 0;
+ if (f1 + f2 + f3 != 1) return kDNSServiceErr_BadParam;
if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
flags |= kDNSServiceFlagsIncludeP2P;
}
if (service->disp_source)
{
- syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch source set already");
return kDNSServiceErr_BadParam;
}
service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
if (!service->disp_source)
{
- syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch_source_create failed");
return kDNSServiceErr_NoMemory;
}
service->disp_queue = queue;
(void)flags; // Unused
if (sdRef->kacontext != context)
- syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
+ syslog(LOG_WARNING, "dnssd_clientstub SleepKeepaliveCallback context mismatch");
if (ka->AppCallback)
((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
len1 = sizeof(lss);
if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getsockname %d\n", errno);
return kDNSServiceErr_BadParam;
}
len2 = sizeof(rss);
if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getpeername %d\n", errno);
return kDNSServiceErr_BadParam;
}
if (len1 != len2)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same");
return kDNSServiceErr_Unknown;
}
if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote info failed %d", errno);
return kDNSServiceErr_Unknown;
}
if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local info failed %d", errno);
return kDNSServiceErr_Unknown;
}
// Sum of all bytes in the local address and port should result in a unique
if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote6 info failed %d", errno);
return kDNSServiceErr_Unknown;
}
if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local6 info failed %d", errno);
return kDNSServiceErr_Unknown;
}
for (i = 0; i < sizeof(struct in6_addr); i++)
if (len >= (sizeof(buf) - 1))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit local/remote info");
return kDNSServiceErr_Unknown;
}
// Include the NULL byte also in the first byte. The total length of the record includes the
len = snprintf(name, sizeof(name), "%u", unique);
if (len >= sizeof(name))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit unique");
return kDNSServiceErr_Unknown;
}
len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
if (len >= sizeof(recname))
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit name");
return kDNSServiceErr_Unknown;
}
err = DNSServiceCreateConnection(sdRef);
if (err)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
free(ka);
return err;
}
kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
if (err)
{
- syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+ syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
free(ka);
return err;
}
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
int put_string(const char *str, char **ptr)
{
+ size_t len;
if (!str) str = "";
- strcpy(*ptr, str);
- *ptr += strlen(str) + 1;
+ len = strlen(str) + 1;
+ memcpy(*ptr, str, len);
+ *ptr += len;
return 0;
}
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
* limitations under the License.
*/
-#include "mDNSDebug.h"
-
#include <stdio.h>
#if defined(WIN32) || defined(EFI32) || defined(EFI64) || defined(EFIX64)
mDNSexport void verbosedebugf_(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);
+ va_list args;
+ va_start(args, format);
+ buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, args)] = 0;
+ va_end(args);
mDNSPlatformWriteDebugMsg(buffer);
}
#endif
// Log message with default "mDNSResponder" ident string at the start
-mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_list ptr)
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+mDNSlocal void LogMsgWithLevelv(os_log_t category, os_log_type_t level, const char *format, va_list args)
+{
+ char buffer[512];
+ mDNS_vsnprintf(buffer, (mDNSu32)sizeof(buffer), format, args);
+ os_log_with_type(category ? category : mDNSLogCategory_Default, level, "%{private}s", buffer);
+}
+#else
+mDNSlocal void LogMsgWithLevelv(const char *category, mDNSLogLevel_t level, const char *format, va_list args)
{
char buffer[512];
- buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
- mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel);
+ char *dst = buffer;
+ const char *const lim = &buffer[512];
+ if (category) mDNS_snprintf_add(&dst, lim, "%s: ", category);
+ mDNS_vsnprintf(dst, (mDNSu32)(lim - dst), format, args);
+ mDNSPlatformWriteLogMsg(ProgramName, buffer, level);
}
+#endif
-#define LOG_HELPER_BODY(L) \
+#define LOG_HELPER_BODY(CATEGORY, LEVEL) \
{ \
- va_list ptr; \
- va_start(ptr,format); \
- LogMsgWithLevelv(L, format, ptr); \
- va_end(ptr); \
+ va_list args; \
+ va_start(args,format); \
+ LogMsgWithLevelv(CATEGORY, LEVEL, format, args); \
+ va_end(args); \
}
// see mDNSDebug.h
#if !MDNS_HAS_VA_ARG_MACROS
-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)
-void LogDebug_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_DEBUG)
+void LogMsg_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogOperation_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogSPS_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogInfo_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogDebug_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_DEBUG)
#endif
#if MDNS_DEBUGMSGS
#endif
// Log message with default "mDNSResponder" ident string at the start
-mDNSexport void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...)
-LOG_HELPER_BODY(logLevel)
+mDNSexport void LogMsgWithLevel(mDNSLogCategory_t category, mDNSLogLevel_t level, const char *format, ...)
+LOG_HELPER_BODY(category, level)
+
+mDNSexport void LogToFD(int fd, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+#if APPLE_OSX_mDNSResponder
+ char buffer[1024];
+ buffer[mDNS_vsnprintf(buffer, (mDNSu32)sizeof(buffer), format, args)] = '\0';
+ dprintf(fd, "%s\n", buffer);
+#else
+ (void)fd;
+ LogMsgWithLevelv(NULL, MDNS_LOG_INFO, format, args);
+#endif
+ va_end(args);
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __mDNSFeatures_h
+#define __mDNSFeatures_h
+
+#if MDNSRESPONDER_PLATFORM_APPLE
+#include "ApplePlatformFeatures.h"
+#endif
+
+// Common Features
+
+#undef MDNSRESPONDER_PLATFORM_COMMON
+#define MDNSRESPONDER_PLATFORM_COMMON 1
+
+// Feature: DNS Push
+// Radar: <rdar://problem/23226275>
+// Enabled: Yes, for Apple.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH)
+ #if defined(MDNSRESPONDER_PLATFORM_APPLE) && MDNSRESPONDER_PLATFORM_APPLE
+ #define MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH 1
+ #else
+ #define MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH 0
+ #endif
+#endif
+
+#define HAS_FEATURE_CAT(A, B) A ## B
+#define HAS_FEATURE_CHECK_0 1
+#define HAS_FEATURE_CHECK_1 1
+#define HAS_FEATURE(X) ((X) / HAS_FEATURE_CAT(HAS_FEATURE_CHECK_, X))
+
+#define MDNSRESPONDER_SUPPORTS(PLATFORM, FEATURE) \
+ (defined(MDNSRESPONDER_PLATFORM_ ## PLATFORM) && MDNSRESPONDER_PLATFORM_ ## PLATFORM && \
+ HAS_FEATURE(MDNSRESPONDER_SUPPORTS_ ## PLATFORM ## _ ## FEATURE))
+
+#endif // __mDNSFeatures_h
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
#include "uds_daemon.h"
#include "dns_sd_internal.h"
-// Normally we append search domains only for queries with a single label that are not
-// fully qualified. This can be overridden to apply search domains for queries (that are
-// not fully qualified) with any number of labels e.g., moon, moon.cs, moon.cs.be, etc.
-mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
-
-// Control enabling ioptimistic DNS
-mDNSBool EnableAllowExpired = mDNStrue;
-
// Apple-specific functionality, not required for other platforms
#if APPLE_OSX_mDNSResponder
+#include <os/log.h>
#include <sys/ucred.h>
#ifndef PID_FILE
-#define PID_FILE ""
+#define NO_PID_FILE // We need to signal that this platform has no PID file, and not just that we are taking the default
#endif
#endif
#include <libproc.h> // for proc_pidinfo()
#endif //LOCAL_PEEREPID
-#ifdef UNIT_TEST
-#include "unittest.h"
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
#endif
#if APPLE_OSX_mDNSResponder
-#include <WebFilterDNS/WebFilterDNS.h>
#include "BLE.h"
-
-#if !NO_WCF
-
-int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
-int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
-int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
-
-// Do we really need to define a macro for "if"?
-#define CHECK_WCF_FUNCTION(X) if (X)
-#endif // ! NO_WCF
-
-#else
-#define NO_WCF 1
-#endif // APPLE_OSX_mDNSResponder
+#endif
// User IDs 0-500 are system-wide processes, not actual users in the usual sense
// User IDs for real user accounts start at 501 and count up from there
#define SystemUID(X) ((X) <= 500)
-#define MAX_ANONYMOUS_DATA 256
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
static mDNSu32 n_mquests; // tracks the current active mcast questions for McastLogging
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
mDNSu32 curr_num_regservices = 0;
mDNSu32 max_num_regservices = 0;
#endif
#define PID_FILE "/var/run/mDNSResponder.pid"
#endif
-mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int adstrlen);
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
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; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req->request_id, req, req->terminate);
+ return;
+ }
// First stop whatever mDNSCore operation we were doing
// If this is actually a shared connection operation, then its req->terminate function will scan
if (req->terminate) req->terminate(req);
if (!dnssd_SocketValid(req->sd))
- { LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req, req->sd); return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req->request_id, 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) LogDebug("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
- else LogDebug("%3d: Removing FD", req->sd);
+ if (req->errsd != req->sd)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%d] Removing FD %d and closing errsd %d", req->request_id, req->sd, req->errsd);
+ }
+ else
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%d] Removing FD %d", req->request_id, req->sd);
+ }
udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data); // Note: This also closes file descriptor req->sd for us
if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
}
// 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
+#if MDNS_MALLOC_DEBUGGING
+ // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MDNS_MALLOC_DEBUGGING uses
// for detecting when the memory for an object is inadvertently freed while the object is still on some list
+#ifdef WIN32
+#error This will not work on Windows, look at IsValidSocket in mDNSShared/CommonServices.h to see why
+#endif
req->sd = req->errsd = -2;
#else
req->sd = req->errsd = dnssd_InvalidSocket;
return NULL;
}
- reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
- if (!reply) FatalError("ERROR: malloc");
+ reply = (reply_state *) callocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
+ if (!reply) FatalError("ERROR: calloc");
reply->next = mDNSNULL;
reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
{
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
- char name[256];
+ char name[MAX_ESCAPED_DOMAIN_NAME];
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);
AuthRecord *rr;
mDNSInterfaceID InterfaceID;
AuthRecType artype;
+ mDNSu8 recordType;
request->flags = flags;
request->interfaceIndex = interfaceIndex;
if (validate_flags &&
!((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
- !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
+ !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique) &&
+ !((flags & kDNSServiceFlagsKnownUnique) == kDNSServiceFlagsKnownUnique))
{
- LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
+ LogMsg("ERROR: Bad resource record flags (must be one of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique)");
return NULL;
}
- rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
- if (!rr) FatalError("ERROR: malloc");
+ rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
+ if (!rr) FatalError("ERROR: calloc");
InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+
+ // The registration is scoped to a specific interface index, but the interface is not currently on our list.
+ if ((InterfaceID == mDNSInterface_Any) && (interfaceIndex != kDNSServiceInterfaceIndexAny))
+ {
+ // On Apple platforms, an interface's mDNSInterfaceID is equal to its index. Using an interface index that isn't
+ // currently valid will cause the registration to take place as soon as it becomes valid. On other platforms,
+ // mDNSInterfaceID is actually a pointer to a platform-specific interface object, but we don't know what the pointer
+ // for the interface index will be ahead of time. For now, just return NULL to indicate an error condition since the
+ // interface index is invalid. Otherwise, the registration would be performed on all interfaces.
+#if APPLE_OSX_mDNSResponder
+ InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
+#else
+ return NULL;
+#endif
+ }
if (InterfaceID == mDNSInterface_LocalOnly)
artype = AuthRecordLocalOnly;
else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
else
artype = AuthRecordAny;
- mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0,
- (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), artype, mDNSNULL, mDNSNULL);
+ if (flags & kDNSServiceFlagsShared)
+ recordType = (mDNSu8) kDNSRecordTypeShared;
+ else if (flags & kDNSServiceFlagsKnownUnique)
+ recordType = (mDNSu8) kDNSRecordTypeKnownUnique;
+ else
+ recordType = (mDNSu8) kDNSRecordTypeUnique;
+
+ mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0, recordType, artype, mDNSNULL, mDNSNULL);
if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
{
#pragma mark - external helpers
#endif
-mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags)
-{
-#if APPLE_OSX_mDNSResponder
-
- // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
- if ( (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger)))
- || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE))
- && IsLocalDomain(domain))
- {
- return mDNStrue;
- }
- else
- return mDNSfalse;
-
-#else
- (void) InterfaceID;
- (void) domain;
- (void) flags;
-
- return mDNSfalse;
-#endif // APPLE_OSX_mDNSResponder
-}
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
mDNSlocal void external_start_advertising_helper(service_instance *const instance)
{
AuthRecord *st = instance->subtypes;
external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
-
external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
for (e = instance->srs.Extras; e; e = e->next)
LogInfo("external_stop_advertising_helper: calling external_stop_advertising_service");
- for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
- external_stop_advertising_service(&st[i].resrec, instance->request->flags);
+ if (instance->request)
+ {
+ for (i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+ {
+ external_stop_advertising_service(&st[i].resrec, instance->request->flags);
+ }
- external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
- external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
- external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
+ external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
+ external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
+ external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
- for (e = instance->srs.Extras; e; e = e->next)
- external_stop_advertising_service(&e->r.resrec, instance->request->flags);
+ for (e = instance->srs.Extras; e; e = e->next)
+ {
+ external_stop_advertising_service(&e->r.resrec, instance->request->flags);
+ }
+ }
instance->external_advertise = mDNSfalse;
}
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, D2D)
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
{
ExtraResourceRecord *e = srv->srs.Extras, *tmp;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(srv);
+#endif
// clear pointers from parent struct
if (srv->request)
freeL("ServiceSubTypes", srv->subtypes);
srv->subtypes = NULL;
}
- if (srv->srs.AnonData)
- {
- freeL("Anonymous", (void *)srv->srs.AnonData);
- srv->srs.AnonData = NULL;
- }
freeL("service_instance", srv);
}
reply_state *rep;
(void)m; // Unused
- if (!srs) { LogMsg("regservice_callback: srs is NULL %d", result); return; }
+ if (!srs)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs is NULL %d", result);
+ return;
+ }
instance = srs->ServiceContext;
- if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
+ if (!instance)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs->ServiceContext is NULL %d", result);
+ return;
+ }
// don't send errors up to client for wide-area, empty-string registrations
if (instance->request &&
if (mDNS_LoggingEnabled)
{
- const char *const fmt =
- (result == mStatus_NoError) ? "%s DNSServiceRegister(%##s, %u) REGISTERED" :
- (result == mStatus_MemFree) ? "%s DNSServiceRegister(%##s, %u) DEREGISTERED" :
- (result == mStatus_NameConflict) ? "%s DNSServiceRegister(%##s, %u) NAME CONFLICT" :
- "%s DNSServiceRegister(%##s, %u) %s %d";
- char prefix[16] = "---:";
- if (instance->request) mDNS_snprintf(prefix, sizeof(prefix), "%3d:", instance->request->sd);
- LogOperation(fmt, prefix, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port),
- SuppressError ? "suppressed error" : "CALLBACK", result);
+ const char *result_description;
+ char description[32]; // 32-byte is enough for holding "suppressed error -2147483648\0"
+ mDNSu32 request_id = instance->request ? instance->request->request_id : 0;
+ switch (result) {
+ case mStatus_NoError:
+ result_description = "REGISTERED";
+ break;
+ case mStatus_MemFree:
+ result_description = "DEREGISTERED";
+ break;
+ case mStatus_NameConflict:
+ result_description = "NAME CONFLICT";
+ break;
+ default:
+ mDNS_snprintf(description, sizeof(description), "%s %d", SuppressError ? "suppressed error" : "CALLBACK", result);
+ result_description = description;
+ break;
+ }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegister(" PRI_DM_NAME ", %u) %s",
+ request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c), mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result_description);
}
- if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
+ if (!instance->request && result != mStatus_MemFree)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: instance->request is NULL %d", result);
+ return;
+ }
if (result == mStatus_NoError)
{
}
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->request->sd, srs->RR_SRV.resrec.name->c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c));
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(instance->request->u.servicereg.InterfaceID, &instance->domain, instance->request->flags))
{
- LogInfo("regservice_callback: calling external_start_advertising_helper()");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] regservice_callback: calling external_start_advertising_helper()", instance->request->request_id);
external_start_advertising_helper(instance);
}
+#endif
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
RecordUpdatedNiceLabel(0); // Successfully got new name, tell user immediately
}
else if (result == mStatus_MemFree)
{
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
curr_num_regservices--;
#endif
if (instance->request && instance->renameonmemfree)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(instance);
+#endif
instance->renameonmemfree = 0;
err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
- if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
+ if (err)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] ERROR: regservice_callback - RenameAndReregisterService returned %d", instance->request->request_id, err);
// error should never happen - safest to log and continue
}
else
{
if (instance->request->u.servicereg.autorename)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(instance);
+#endif
if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
{
// On conflict for an autoname service, rename and reregister *all* autoname services
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->request->sd, srs->RR_SRV.resrec.name->c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c));
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
}
unlink_and_free_service_instance(instance);
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->request->sd, srs->RR_SRV.resrec.name->c);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c));
else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
}
}
if (!rr->RecordContext) // parent struct already freed by termination callback
{
if (result == mStatus_NoError)
- LogMsg("Error: regrecord_callback: successful registration of orphaned record %s", ARDisplayString(m, rr));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Error: regrecord_callback: successful registration of orphaned record " PRI_S, ARDisplayString(m, rr));
else
{
- if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
+ if (result != mStatus_MemFree)
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regrecord_callback: error %d received after parent termination", result);
// We come here when the record is being deregistered either from DNSServiceRemoveRecord or connection_termination.
// If the record has been updated, we need to free the rdata. Every time we call mDNS_Update, it calls update_callback
if (mDNS_LoggingEnabled)
{
- char *fmt = (result == mStatus_NoError) ? "%3d: DNSServiceRegisterRecord(%u %s) REGISTERED" :
- (result == mStatus_MemFree) ? "%3d: DNSServiceRegisterRecord(%u %s) DEREGISTERED" :
- (result == mStatus_NameConflict) ? "%3d: DNSServiceRegisterRecord(%u %s) NAME CONFLICT" :
- "%3d: DNSServiceRegisterRecord(%u %s) %d";
- LogOperation(fmt, request->sd, re->key, RRDisplayString(m, &rr->resrec), result);
+ const char *result_description;
+ char description[16]; // 16-byte is enough for holding -2147483648\0
+ switch (result) {
+ case mStatus_NoError:
+ result_description = "REGISTERED";
+ break;
+ case mStatus_MemFree:
+ result_description = "DEREGISTERED";
+ break;
+ case mStatus_NameConflict:
+ result_description = "NAME CONFLICT";
+ break;
+ default:
+ mDNS_snprintf(description, sizeof(description), "%d", result);
+ result_description = description;
+ break;
+ }
+
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegisterRecord(%u " PRI_S ")" PUB_S,
+ request->request_id, re->key, RRDisplayString(m, &rr->resrec), result_description);
}
if (result != mStatus_MemFree)
// If this is a callback to a keepalive record, do not free it.
if (result == mStatus_BadStateErr)
{
- LogInfo("regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.", request->request_id);
}
else
{
// unlink from list, free memory
registered_record_entry **ptr = &request->u.reg_recs;
while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
- if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
+ if (!*ptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] regrecord_callback - record not in list!", request->request_id);
+ return;
+ }
*ptr = (*ptr)->next;
freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
freeL("registered_record_entry regrecord_callback", re);
}
else
{
- if (re->external_advertise) LogMsg("regrecord_callback: external_advertise already set!");
+ if (re->external_advertise)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] regrecord_callback: external_advertise already set!", request->request_id);
+ }
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(re->origInterfaceID, &rr->namestorage, request->flags))
{
- LogInfo("regrecord_callback: calling external_start_advertising_service");
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] regrecord_callback: calling external_start_advertising_service", request->request_id);
external_start_advertising_service(&rr->resrec, request->flags);
re->external_advertise = mDNStrue;
}
+#endif
}
}
}
// This accounts for 2 places (connect_callback, request_callback)
mDNSlocal void set_peer_pid(request_state *request)
{
- pid_t p = (pid_t) -1;
- socklen_t len = sizeof(p);
request->pid_name[0] = '\0';
request->process_id = -1;
#ifdef LOCAL_PEEREPID
+ pid_t p = (pid_t) -1;
+ socklen_t len = sizeof(p);
if (request->sd < 0)
return;
// to extract the effective pid value
request->process_id = p;
debugf("set_peer_pid: Client PEEREPID is %d %s", p, request->pid_name);
#else // !LOCAL_PEEREPID
- len = 0;
LogInfo("set_peer_pid: Not Supported on this version of OS");
if (request->sd < 0)
return;
// and terminate any subbordinate operations sharing this file descriptor
request_state **req = &all_requests;
- LogOperation("%3d: DNSServiceCreateConnection STOP PID[%d](%s)", request->sd, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateConnection STOP PID[%d](" PUB_S ")",
+ request->request_id, request->process_id, request->pid_name);
while (*req)
{
while (request->u.reg_recs)
{
registered_record_entry *ptr = request->u.reg_recs;
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP PID[%d](%s)", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") STOP PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id,
+ request->pid_name);
request->u.reg_recs = request->u.reg_recs->next;
ptr->rr->RecordContext = NULL;
if (ptr->external_advertise)
{
ptr->external_advertise = mDNSfalse;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_service(&ptr->rr->resrec, request->flags);
+#endif
}
LogMcastS(ptr->rr, request, reg_stop);
mDNS_Deregister(&mDNSStorage, ptr->rr); // Will free ptr->rr for us
mDNSlocal void handle_cancel_request(request_state *request)
{
request_state **req = &all_requests;
- LogDebug("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "[R%d] Cancel %08X %08X",
+ request->request_id, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
while (*req)
{
if ((*req)->primary == request &&
return (mStatus_BadParamErr);
}
// allocate registration entry, link into list
- re = mallocL("registered_record_entry", sizeof(registered_record_entry));
- if (!re)
- FatalError("ERROR: malloc");
+ re = (registered_record_entry *) callocL("registered_record_entry", sizeof(*re));
+ if (!re) FatalError("ERROR: calloc");
re->key = request->hdr.reg_index;
re->rr = rr;
re->regrec_client_context = request->hdr.client_context;
if (rr->resrec.rroriginalttl == 0)
rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START PID[%d](%s)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec),
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), request->process_id,
+ request->pid_name);
err = mDNS_Register(&mDNSStorage, rr);
if (err)
{
- LogOperation("%3d: DNSServiceRegisterRecord(%u %s) ERROR (%d)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec), err);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegisterRecord(0x%X, %d," PRI_S ") ERROR (%d)",
+ request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), err);
freeL("registered_record_entry", re);
freeL("registered_record_entry/AuthRecord", rr);
}
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 PID[%d](%s)", request->sd, p->srs.RR_SRV.resrec.name->c,
- mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRegister(" PRI_DM_NAME ", %u) STOP PID[%d](" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(p->srs.RR_SRV.resrec.name->c),
+ mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_helper(p);
+#endif
// 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
ServiceRecordSet *srs = &instance->srs;
mStatus result;
size_t size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
- ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+ ExtraResourceRecord *extra = (ExtraResourceRecord *) mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
if (!extra) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
- mDNSPlatformMemZero(extra, sizeof(ExtraResourceRecord)); // OK if oversized rdata not zero'd
+ mDNSPlatformMemZero(extra, sizeof(*extra)); // OK if oversized rdata not zero'd
extra->r.resrec.rrtype = rrtype;
extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
extra->r.resrec.rdlength = rdlen;
LogMcastS(&srs->RR_PTR, request, reg_start);
extra->ClientID = request->hdr.reg_index;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if ( instance->external_advertise
&& callExternalHelpers(request->u.servicereg.InterfaceID, &instance->domain, request->flags))
{
LogInfo("add_record_to_service: calling external_start_advertising_service");
external_start_advertising_service(&extra->r.resrec, request->flags);
}
+#endif
return result;
}
if (!ttl) ttl = DefaultTTLforRRType(rrtype);
(void)flags; // Unused
- if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ if (!request->msgptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceAddRecord(unreadable parameters)", request->request_id);
+ 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); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceAddRecord(not a registered service ref)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// For a service registered with zero port, don't allow adding records. This mostly happens due to a bug
// in the application. See radar://9165807.
if (mDNSIPPortIsZero(request->u.servicereg.port))
- { LogMsg("%3d: DNSServiceAddRecord: adding record to a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
-
- LogOperation("%3d: DNSServiceAddRecord(%X, %##s, %s, %d) PID[%d](%s)", request->sd, flags,
- (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen,
- request->process_id, request->pid_name);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceAddRecord: adding record to a service registered with zero port", request->request_id);
+ return(mStatus_BadParamErr);
+ }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceAddRecord(%X, " PRI_DM_NAME ", " PUB_S ", %d) PID[%d](" PUB_S ")",
+ request->request_id, flags,
+ DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name->c) : mDNSNULL),
+ DNSTypeName(rrtype), rdlen, request->process_id, request->pid_name);
for (i = request->u.servicereg.instances; i; i = i->next)
{
if (external_advertise)
{
ResourceRecord ext = rr->resrec;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(rr->ARType);
+#endif
if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
SetNewRData(&ext, oldrd, oldrdlen);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_service(&ext, flags);
LogInfo("update_callback: calling external_start_advertising_service");
external_start_advertising_service(&rr->resrec, flags);
+#endif
}
exit:
if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise)
{
mStatus result;
- const size_t rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
- RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
+ const size_t rdsize = (rdlen > sizeof(RDataBody)) ? rdlen : sizeof(RDataBody);
+ RData *newrd = (RData *) mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
if (!newrd) FatalError("ERROR: malloc");
newrd->MaxRDLength = (mDNSu16) rdsize;
mDNSPlatformMemCopy(&newrd->u, rdata, 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 (!request->msgptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord(unreadable parameters)", request->request_id);
+ 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 (reptr->key == hdr->reg_index)
{
result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
- LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s) PID[%d](%s)",
- request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(reptr->rr->resrec.name->c),
+ reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
+ request->process_id, request->pid_name);
goto end;
}
}
}
if (request->terminate != regservice_termination_callback)
- { LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord(not a registered service ref)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// For a service registered with zero port, only SRV record is initialized. Don't allow any updates.
if (mDNSIPPortIsZero(request->u.servicereg.port))
- { LogMsg("%3d: DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->request_id);
+ return(mStatus_BadParamErr);
+ }
// update the saved off TXT data for the service
if (hdr->reg_index == TXT_RECORD_INDEX)
e->rr->RecordContext = NULL;
if (e->external_advertise)
{
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_stop_advertising_service(&e->rr->resrec, request->flags);
+#endif
e->external_advertise = mDNSfalse;
}
LogMcastS(e->rr, request, reg_stop);
if (ptr->ClientID == request->hdr.reg_index) // found match
{
*rrtype = ptr->r.resrec.rrtype;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (serv->external_advertise) external_stop_advertising_service(&ptr->r.resrec, request->flags);
+#endif
err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
break;
}
mStatus err = mStatus_BadReferenceErr;
get_flags(&request->msgptr, request->msgend); // flags unused
- if (!request->msgptr) { LogMsg("%3d: DNSServiceRemoveRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ if (!request->msgptr)
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceRemoveRecord(unreadable parameters)", request->request_id);
+ 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); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceRemoveRecord(not a registered service ref)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
else
{
service_instance *i;
mDNSu16 rrtype = 0;
- LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s) PID[%d](%s)", request->sd,
- (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
- rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRemoveRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
+ request->request_id,
+ DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name->c) : mDNSNULL),
+ rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
for (i = request->u.servicereg.instances; i; i = i->next)
{
err = remove_extra(request, i, &rrtype);
// If there's a comma followed by another character,
// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
// Otherwise, it returns a pointer to the final nul at the end of the string
-mDNSlocal char *FindFirstSubType(char *p, char **AnonData)
+mDNSlocal char *FindFirstSubType(char *p)
{
while (*p)
{
*p++ = 0;
return(p);
}
- else if (p[0] == ':' && p[1])
- {
- *p++ = 0;
- *AnonData = p;
- }
else
{
p++;
}
// Returns -1 if illegal subtype found
-mDNSexport mDNSs32 ChopSubTypes(char *regtype, char **AnonData)
+mDNSlocal mDNSs32 ChopSubTypes(char *regtype)
{
mDNSs32 NumSubTypes = 0;
- char *stp = FindFirstSubType(regtype, AnonData);
+ char *stp = FindFirstSubType(regtype);
while (stp && *stp) // If we found a comma...
{
if (*stp == ',') return(-1);
return(NumSubTypes);
}
-mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData)
+mDNSlocal AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
{
AuthRecord *st = mDNSNULL;
- //
- // "p" is pointing at the regtype e.g., _http._tcp followed by ":<AnonData>" indicated
- // by AnonData being non-NULL which is in turn follwed by ",<SubTypes>" indicated by
- // NumSubTypes being non-zero. We need to skip the initial regtype to get to the actual
- // data that we want. When we come here, ChopSubTypes has null terminated like this e.g.,
- //
- // _http._tcp<NULL><AnonData><NULL><SubType1><NULL><SubType2><NULL> etc.
- //
- // 1. If we have Anonymous data and subtypes, skip the regtype (e.g., "_http._tcp")
- // to get the AnonData and then skip the AnonData to get to the SubType.
- //
- // 2. If we have only SubTypes, skip the regtype to get to the SubType data.
- //
- // 3. If we have only AnonData, skip the regtype to get to the AnonData.
- //
- // 4. If we don't have AnonData or NumStypes, it is a noop.
- //
- if (AnonData)
- {
- int len;
-
- // Skip the regtype
- while (*p) p++;
- p++;
-
- len = strlen(p) + 1;
- *AnonData = mallocL("Anonymous", len);
- if (!(*AnonData))
- {
- return (mDNSNULL);
- }
- mDNSPlatformMemCopy(*AnonData, p, len);
- }
if (NumSubTypes)
{
mDNSs32 i;
- st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+ st = (AuthRecord *) callocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
if (!st) return(mDNSNULL);
for (i = 0; i < NumSubTypes; i++)
{
mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
- // First time through we skip the regtype or AnonData. Subsequently, the
- // previous subtype.
while (*p) p++;
p++;
if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
{
freeL("ServiceSubTypes", st);
- if (AnonData && *AnonData)
- freeL("AnonymousData", *AnonData);
return(mDNSNULL);
}
}
}
- // If NumSubTypes is zero and AnonData is non-NULL, we still return NULL but AnonData has been
- // initialized. The caller knows how to handle this.
return(st);
}
}
}
- instance = mallocL("service_instance", sizeof(*instance) + extra_size);
- if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+ instance = (service_instance *) callocL("service_instance", sizeof(*instance) + extra_size);
+ if (!instance) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
instance->next = mDNSNULL;
instance->request = request;
instance->external_advertise = mDNSfalse;
AssignDomainName(&instance->domain, domain);
- instance->srs.AnonData = mDNSNULL;
- if (!request->u.servicereg.AnonData)
- {
- instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, mDNSNULL);
- }
- else
- {
- char *AnonData = mDNSNULL;
- instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, &AnonData);
- if (AnonData)
- instance->srs.AnonData = (const mDNSu8 *)AnonData;
- }
+ instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
if (request->u.servicereg.num_subtypes && !instance->subtypes)
{
}
}
-// Don't allow normal and anonymous registration to coexist.
-mDNSlocal mDNSBool CheckForMixedRegistrations(domainname *regtype, domainname *domain, mDNSBool AnonData)
-{
- request_state *request;
-
- // We only care about local domains where the anonymous extension is
- // implemented.
- if (!SameDomainName(domain, (const domainname *) "\x5" "local"))
- {
- return mDNStrue;
- }
-
- for (request = all_requests; request; request = request->next)
- {
- service_instance *ptr;
-
- if (request->terminate != regservice_termination_callback) continue;
- for (ptr = request->u.servicereg.instances; ptr ; ptr = ptr->next)
- {
- if (!SameDomainName(&ptr->domain, (const domainname *)"\x5" "local") ||
- !SameDomainName(&request->u.servicereg.type, regtype))
- {
- continue;
- }
-
- // If we are about to register a anonymous registraion, we dont't want to
- // allow the regular ones and vice versa.
- if (AnonData)
- {
- if (!ptr->srs.AnonData)
- {
- LogMsg("CheckForMixedRegistrations: Normal registration already exists for %##s", regtype->c);
- return mDNSfalse;
- }
- }
- else
- {
- // Allow multiple regular registrations
- if (ptr->srs.AnonData)
- {
- LogMsg("CheckForMixedRegistrations: Anonymous registration already exists for %##s", regtype->c);
- return mDNSfalse;
- }
- }
- }
- }
- return mDNStrue;
-}
-
// Returns true if the interfaceIndex value matches one of the pre-defined
// special values listed in the switch statement below.
mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
{
char name[256]; // Lots of spare space for extra-long names that we'll auto-truncate down to 63 bytes
char domain[MAX_ESCAPED_DOMAIN_NAME], host[MAX_ESCAPED_DOMAIN_NAME];
- char type_as_string[MAX_ESCAPED_DOMAIN_NAME];
+ char type_as_string[MAX_ESCAPED_DOMAIN_NAME]; // Note that this service type may include a trailing list of subtypes
domainname d, srv;
mStatus err;
- char *AnonData = mDNSNULL;
const char *msgTXTData;
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
LogInfo("handle_regservice_request: registration pending for interface index %d", interfaceIndex);
}
- if (get_string(&request->msgptr, request->msgend, name, sizeof(name)) < 0 ||
- get_string(&request->msgptr, request->msgend, type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name )) < 0 ||
+ get_string(&request->msgptr, request->msgend, type_as_string, sizeof(type_as_string)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0 ||
+ get_string(&request->msgptr, request->msgend, host, sizeof(host )) < 0)
{ LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
request->flags = flags;
}
// Check for sub-types after the service type
- request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string, &AnonData); // Note: Modifies regtype string to remove trailing subtypes
+ request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string); // Note: Modifies regtype string to remove trailing subtypes
if (request->u.servicereg.num_subtypes < 0)
{
LogMsg("ERROR: handle_regservice_request - ChopSubTypes failed %s", request->u.servicereg.type_as_string);
goto bad_param;
}
- if (AnonData)
- {
- int AnonDataLen = strlen(AnonData);
- if (AnonDataLen > MAX_ANONYMOUS_DATA)
- {
- LogMsg("ERROR: handle_regservice_request: AnonDataLen %d", AnonDataLen);
- goto bad_param;
- }
- request->u.servicereg.AnonData = mDNStrue;
- }
- else
- {
- request->u.servicereg.AnonData = mDNSfalse;
- }
// Don't try to construct "domainname t" until *after* ChopSubTypes has worked its magic
if (!*request->u.servicereg.type_as_string || !MakeDomainNameFromDNSNameString(&request->u.servicereg.type, request->u.servicereg.type_as_string))
MakeDomainNameFromDNSNameString(&d, "local.");
}
- // We don't allow the anonymous and the regular ones to coexist
- if (!CheckForMixedRegistrations(&request->u.servicereg.type, &d, request->u.servicereg.AnonData)) { goto bad_param; }
-
if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
{
LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
}
#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
- LogOperation("%3d: DNSServiceRegister(%X, %d, \"%s\", \"%s\", \"%s\", \"%s\", %u) START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
- mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceRegister(%X, %d, \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", %u) START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
+ mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
// We need to unconditionally set request->terminate, because even if we didn't successfully
// 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
+ // because the udsserver_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);
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
++curr_num_regservices;
if (curr_num_regservices > max_num_regservices)
max_num_regservices = curr_num_regservices;
validReply:
- LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s interface %d: %s",
- req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
- mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] DNSServiceBrowse(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: " PRI_S,
+ req->request_id, mDNSVal16(question->TargetQID), DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype),
+ AddRecord ? "ADD" : "RMV", mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
+ RRDisplayString(m, answer));
append_reply(req, rep);
}
{ debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
}
- b = mallocL("browser_t", sizeof(*b));
+ b = (browser_t *) callocL("browser_t", sizeof(*b));
if (!b) return mStatus_NoMemoryErr;
- mDNSPlatformMemZero(b, sizeof(*b));
AssignDomainName(&b->domain, d);
SetQuestionPolicy(&b->q, info);
- err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.AnonData, info->u.browser.interface_id, info->flags,
+ err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.interface_id, info->flags,
info->u.browser.ForceMCast, (info->flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, info);
if (err)
{
#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
LogMcastQ(&b->q, info, q_start);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(info->u.browser.interface_id, &b->domain, info->flags))
{
domainname tmp;
LogDebug("add_domain_to_browser: calling external_start_browsing_for_service()");
external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags);
}
+#endif
}
return err;
}
LogInfo("%3d: DNSServiceBrowse Cancel WAB PID[%d](%s)", info->sd, info->process_id, info->pid_name);
uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
}
- if (info->u.browser.AnonData)
- freeL("Anonymous", (void *)info->u.browser.AnonData);
while (info->u.browser.browsers)
{
browser_t *ptr = info->u.browser.browsers;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(ptr->q.InterfaceID, &ptr->domain, ptr->q.flags))
{
domainname tmp;
LogInfo("browse_termination_callback: calling external_stop_browsing_for_service()");
external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags);
}
-
- LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\") STOP PID[%d](%s)",
- info->sd, info->flags, info->interfaceIndex, ptr->q.qname.c, info->process_id, info->pid_name);
+#endif
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
+ info->request_id, info->flags, info->interfaceIndex, DM_NAME_PARAM(ptr->q.qname.c),
+ info->process_id, info->pid_name);
info->u.browser.browsers = ptr->next;
mDNS_StopBrowse(&mDNSStorage, &ptr->q); // no need to error-check result
{
// allocate/register legacy and non-legacy _browse PTR record
mStatus err;
- ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
+ ARListElem *ptr = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*ptr));
debugf("Incrementing %s refcount for %##s",
(type == mDNS_DomainTypeBrowse ) ? "browse domain " :
mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
{
- DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
+ DNameListElem *new = (DNameListElem *) mDNSPlatformMemAllocateClear(sizeof(*new));
if (!new) { LogMsg("ERROR: malloc"); return; }
AssignDomainName(&new->name, name);
new->uid = uid;
mDNSlocal mStatus handle_browse_request(request_state *request)
{
+ // Note that regtype may include a trailing subtype
char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
domainname typedn, d, temp;
mDNSs32 NumSubTypes;
- char *AnonData = mDNSNULL;
mStatus err = mStatus_NoError;
- int AnonDataLen;
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
LogInfo("handle_browse_request: browse pending for interface index %d", interfaceIndex);
}
- if (get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0) return(mStatus_BadParamErr);
+ if (get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0) return(mStatus_BadParamErr);
if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
request->flags = flags;
request->interfaceIndex = interfaceIndex;
typedn.c[0] = 0;
- NumSubTypes = ChopSubTypes(regtype, &AnonData); // Note: Modifies regtype string to remove trailing subtypes
+ NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
if (NumSubTypes < 0 || NumSubTypes > 1)
return(mStatus_BadParamErr);
- AnonDataLen = 0;
- if (AnonData)
- {
- AnonDataLen = strlen(AnonData);
- if (AnonDataLen > MAX_ANONYMOUS_DATA)
- {
- LogMsg("handle_browse_request: AnonDataLen %d", AnonDataLen);
- return(mStatus_BadParamErr);
- }
- // Account for the null byte
- AnonDataLen += 1;
- }
if (NumSubTypes == 1)
{
- if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1 + AnonDataLen))
+ if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
return(mStatus_BadParamErr);
}
request->u.browser.default_domain = !domain[0];
request->u.browser.browsers = NULL;
- LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\", \"" PRI_S "\") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, interfaceIndex, DM_NAME_PARAM(request->u.browser.regtype.c), domain,
+ request->process_id, request->pid_name);
if (request->u.browser.default_domain)
{
// Start the domain enumeration queries to discover the WAB browse domains
- LogInfo("%3d: DNSServiceBrowse Start WAB PID[%d](%s)", request->sd, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceBrowse Start WAB PID[%d](" PUB_S ")",
+ request->request_id, request->process_id, request->pid_name);
uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
}
- request->u.browser.AnonData = mDNSNULL;
- if (AnonData)
- {
- int len = strlen(AnonData) + 1;
- request->u.browser.AnonData = mallocL("Anonymous", len);
- if (!request->u.browser.AnonData)
- return mStatus_NoMemoryErr;
- else
- mDNSPlatformMemCopy((void *)request->u.browser.AnonData, AnonData, len);
- }
// 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.
put_uint16(req->u.resolve.txt->rdlength, &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));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d->Q%d] DNSServiceResolve(" PRI_S ") RESULT " PRI_S ":%d",
+ req->request_id, mDNSVal16(question->TargetQID), fullname, target,
+ mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
append_reply(req, rep);
}
mDNSlocal void resolve_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") STOP PID[%d](%s)",
- request->sd, request->flags, request->interfaceIndex, request->u.resolve.qtxt.qname.c, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, DM_NAME_PARAM(request->u.resolve.qtxt.qname.c),
+ request->process_id, request->pid_name);
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
LogMcastQ(&request->u.resolve.qsrv, request, q_stop);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (request->u.resolve.external_advertise)
external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags);
+#endif
}
mDNSlocal mStatus handle_resolve_request(request_state *request)
LogInfo("handle_resolve_request: resolve pending for interface index %d", interfaceIndex);
}
- if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
- get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name )) < 0 ||
+ get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0)
{ LogMsg("ERROR: handle_resolve_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
if (!request->msgptr) { LogMsg("%3d: DNSServiceResolve(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
// format questions
request->u.resolve.qsrv.InterfaceID = InterfaceID;
request->u.resolve.qsrv.flags = flags;
- request->u.resolve.qsrv.Target = zeroAddr;
AssignDomainName(&request->u.resolve.qsrv.qname, &fqdn);
request->u.resolve.qsrv.qtype = kDNSType_SRV;
request->u.resolve.qsrv.qclass = kDNSClass_IN;
request->u.resolve.qsrv.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
request->u.resolve.qsrv.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
request->u.resolve.qsrv.SuppressUnusable = mDNSfalse;
- request->u.resolve.qsrv.SearchListIndex = 0;
request->u.resolve.qsrv.AppendSearchDomains = 0;
- request->u.resolve.qsrv.RetryWithSearchDomains = mDNSfalse;
request->u.resolve.qsrv.TimeoutQuestion = 0;
request->u.resolve.qsrv.WakeOnResolve = (flags & kDNSServiceFlagsWakeOnResolve) != 0;
- request->u.resolve.qsrv.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+ request->u.resolve.qsrv.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
request->u.resolve.qsrv.ValidationRequired = 0;
request->u.resolve.qsrv.ValidatingResponse = 0;
request->u.resolve.qsrv.ProxyQuestion = 0;
- request->u.resolve.qsrv.qnameOrig = mDNSNULL;
- request->u.resolve.qsrv.AnonInfo = mDNSNULL;
request->u.resolve.qsrv.pid = request->process_id;
request->u.resolve.qsrv.euid = request->uid;
request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
request->u.resolve.qtxt.InterfaceID = InterfaceID;
request->u.resolve.qtxt.flags = flags;
- request->u.resolve.qtxt.Target = zeroAddr;
AssignDomainName(&request->u.resolve.qtxt.qname, &fqdn);
request->u.resolve.qtxt.qtype = kDNSType_TXT;
request->u.resolve.qtxt.qclass = kDNSClass_IN;
request->u.resolve.qtxt.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
request->u.resolve.qtxt.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
- request->u.resolve.qtxt.SearchListIndex = 0;
request->u.resolve.qtxt.AppendSearchDomains = 0;
- request->u.resolve.qtxt.RetryWithSearchDomains = mDNSfalse;
request->u.resolve.qtxt.TimeoutQuestion = 0;
request->u.resolve.qtxt.WakeOnResolve = 0;
- request->u.resolve.qtxt.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+ request->u.resolve.qtxt.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
request->u.resolve.qtxt.ValidationRequired = 0;
request->u.resolve.qtxt.ValidatingResponse = 0;
request->u.resolve.qtxt.ProxyQuestion = 0;
- request->u.resolve.qtxt.qnameOrig = mDNSNULL;
- request->u.resolve.qtxt.AnonInfo = mDNSNULL;
request->u.resolve.qtxt.pid = request->process_id;
request->u.resolve.qtxt.euid = request->uid;
request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
#endif
// ask the questions
- LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") START PID[%d](%s)", request->sd, flags, interfaceIndex,
- request->u.resolve.qsrv.qname.c, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") START PID[%d](" PUB_S ")",
+ request->request_id, flags, interfaceIndex, DM_NAME_PARAM(request->u.resolve.qsrv.qname.c),
+ request->process_id, request->pid_name);
err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
{
request->terminate = resolve_termination_callback;
LogMcastQ(&request->u.resolve.qsrv, request, q_start);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
if (callExternalHelpers(InterfaceID, &fqdn, flags))
{
request->u.resolve.external_advertise = mDNStrue;
LogInfo("handle_resolve_request: calling external_start_resolving_service()");
external_start_resolving_service(InterfaceID, &fqdn, flags);
}
+#endif
}
}
#pragma mark - DNSServiceQueryRecord
#endif
-// mDNS operation functions. Each operation has 3 associated functions - a request handler that parses
-// the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
-// to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
-// the mDNSCore operation if the client dies or closes its socket.
-
-// Returns -1 to tell the caller that it should not try to reissue the query anymore
-// Returns 1 on successfully appending a search domain and the caller should reissue the new query
-// Returns 0 when there are no more search domains and the caller should reissue the query
-mDNSlocal int AppendNewSearchDomain(DNSQuestion *question)
+mDNSlocal void queryrecord_result_reply(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord, DNSServiceErrorType error, void *context)
{
- domainname *sd;
- mStatus err;
-
- // Sanity check: The caller already checks this. We use -1 to indicate that we have searched all
- // the domains and should try the single label query directly on the wire.
- if (question->SearchListIndex == -1)
- {
- LogMsg("AppendNewSearchDomain: question %##s (%s) SearchListIndex is -1", question->qname.c, DNSTypeName(question->qtype));
- return -1;
- }
-
- if (!question->AppendSearchDomains)
- {
- LogMsg("AppendNewSearchDomain: question %##s (%s) AppendSearchDoamins is 0", question->qname.c, DNSTypeName(question->qtype));
- return -1;
- }
-
- // Save the original name, before we modify them below.
- if (!question->qnameOrig)
- {
- question->qnameOrig = mallocL("AppendNewSearchDomain", sizeof(domainname));
- if (!question->qnameOrig) { LogMsg("AppendNewSearchDomain: ERROR!! malloc failure"); return -1; }
- question->qnameOrig->c[0] = 0;
- AssignDomainName(question->qnameOrig, &question->qname);
- LogInfo("AppendSearchDomain: qnameOrig %##s", question->qnameOrig->c);
- }
-
- sd = uDNS_GetNextSearchDomain(question->InterfaceID, &question->SearchListIndex, !question->AppendLocalSearchDomains);
- // We use -1 to indicate that we have searched all the domains and should try the single label
- // query directly on the wire. uDNS_GetNextSearchDomain should never return a negative value
- if (question->SearchListIndex == -1)
- {
- LogMsg("AppendNewSearchDomain: ERROR!! uDNS_GetNextSearchDomain returned -1");
- return -1;
- }
-
- // Not a common case. Perhaps, we should try the next search domain if it exceeds ?
- if (sd && (DomainNameLength(question->qnameOrig) + DomainNameLength(sd)) > MAX_DOMAIN_NAME)
- {
- LogMsg("AppendNewSearchDomain: ERROR!! exceeding max domain length for %##s (%s) SearchDomain %##s length %d, Question name length %d", question->qnameOrig->c, DNSTypeName(question->qtype), sd->c, DomainNameLength(question->qnameOrig), DomainNameLength(sd));
- return -1;
- }
-
- // if there are no more search domains and we have already tried this question
- // without appending search domains, then we are done.
- if (!sd && !ApplySearchDomainsFirst(question))
- {
- LogInfo("AppendNewSearchDomain: No more search domains for question with name %##s (%s), not trying anymore", question->qname.c, DNSTypeName(question->qtype));
- return -1;
- }
-
- // Stop the question before changing the name as negative cache entries could be pointing at this question.
- // Even if we don't change the question in the case of returning 0, the caller is going to restart the
- // question.
- err = mDNS_StopQuery(&mDNSStorage, question);
- if (err) { LogMsg("AppendNewSearchDomain: ERROR!! %##s %s mDNS_StopQuery: %d, while retrying with search domains", question->qname.c, DNSTypeName(question->qtype), (int)err); }
+ char name[MAX_ESCAPED_DOMAIN_NAME];
+ size_t len;
+ DNSServiceFlags flags = 0;
+ reply_state *rep;
+ char *data;
+ request_state *req = (request_state *)context;
- AssignDomainName(&question->qname, question->qnameOrig);
- if (sd)
- {
- AppendDomainName(&question->qname, sd);
- LogInfo("AppnedNewSearchDomain: Returning question with name %##s, SearchListIndex %d", question->qname.c, question->SearchListIndex);
- return 1;
- }
+ ConvertDomainNameToCString(answer->name, name);
- // Try the question as single label
- LogInfo("AppnedNewSearchDomain: No more search domains for question with name %##s (%s), trying one last time", question->qname.c, DNSTypeName(question->qtype));
- return 0;
-}
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u->Q%u] DNSService" PUB_S "(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: (" PUB_S ")" PRI_S,
+ req->request_id, mDNSVal16(question->TargetQID), req->hdr.op == query_request ? "QueryRecord" : "GetAddrInfo",
+ DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
+ mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
+ MortalityDisplayString(answer->mortality), RRDisplayString(m, answer));
-#if APPLE_OSX_mDNSResponder
+ len = sizeof(DNSServiceFlags); // calculate reply data length
+ len += sizeof(mDNSu32); // interface index
+ len += sizeof(DNSServiceErrorType);
+ len += strlen(name) + 1;
+ len += 3 * sizeof(mDNSu16); // type, class, rdlen
+ len += answer->rdlength;
+ len += sizeof(mDNSu32); // TTL
-mDNSlocal mDNSBool DomainInSearchList(const domainname *domain, mDNSBool excludeLocal)
-{
- const SearchListElem *s;
- int qcount, scount;
+ rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
- qcount = CountLabels(domain);
- for (s=SearchList; s; s=s->next)
- {
- if (excludeLocal && SameDomainName(&s->domain, &localdomain))
- continue;
- scount = CountLabels(&s->domain);
- if (qcount >= scount)
- {
- // Note: When qcount == scount, we do a complete match of the domain
- // which is expected by the callers.
- const domainname *d = SkipLeadingLabels(domain, (qcount - scount));
- if (SameDomainName(&s->domain, d))
- {
- return mDNStrue;
- }
- }
- }
- return mDNSfalse;
-}
-
-// The caller already checks that this is a dotlocal question.
-mDNSlocal mDNSBool ShouldDeliverNegativeResponse(DNSQuestion *question)
-{
- mDNSu16 qtype;
-
- // If the question matches the search domain exactly or the search domain is a
- // subdomain of the question, it is most likely a valid unicast domain and hence
- // don't suppress negative responses.
- //
- // If the user has configured ".local" as a search domain, we don't want
- // to deliver a negative response for names ending in ".local" as that would
- // prevent bonjour discovery. Passing mDNStrue for the last argument excludes
- // ".local" search domains.
- if (DomainInSearchList(&question->qname, mDNStrue))
- {
- LogOperation("ShouldDeliverNegativeResponse: Question %##s (%s) in SearchList", question->qname.c, DNSTypeName(question->qtype));
- return mDNStrue;
- }
-
- // Deliver negative response for A/AAAA if there was a positive response for AAAA/A respectively.
- if (question->qtype != kDNSType_A && question->qtype != kDNSType_AAAA)
- {
- LogOperation("ShouldDeliverNegativeResponse: Question %##s (%s) not answering local question with negative unicast response",
- question->qname.c, DNSTypeName(question->qtype));
- return mDNSfalse;
- }
- qtype = (question->qtype == kDNSType_A ? kDNSType_AAAA : kDNSType_A);
- if (!mDNS_CheckForCacheRecord(&mDNSStorage, question, qtype))
- {
- LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) not answering local question with negative unicast response"
- " (can't find positive record)", question->qname.c, DNSTypeName(question->qtype));
- return mDNSfalse;
- }
- LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) answering local with negative unicast response (found positive record)",
- question->qname.c, DNSTypeName(question->qtype));
- return mDNStrue;
-}
-
-// Workaround for networks using Microsoft Active Directory using "local" as a private internal
-// top-level domain
-mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mStatus err)
-{
-#ifndef UNICAST_DISABLED
- extern domainname ActiveDirectoryPrimaryDomain;
- DNSQuestion **question2;
- #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)))
-
- question2 = mDNSNULL;
- if (request->hdr.op == query_request)
- question2 = &request->u.queryrecord.q2;
- else if (request->hdr.op == addrinfo_request)
- {
- if (q->qtype == kDNSType_A)
- question2 = &request->u.addrinfo.q42;
- else if (q->qtype == kDNSType_AAAA)
- question2 = &request->u.addrinfo.q62;
- }
- if (!question2)
- {
- LogMsg("SendAdditionalQuery: question2 NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
- return mStatus_BadParamErr;
- }
-
- // Sanity check: If we already sent an additonal query, we don't need to send one more.
- //
- // 1. When the application calls DNSServiceQueryRecord or DNSServiceGetAddrInfo with a .local name, this function
- // is called to see whether a unicast query should be sent or not.
- //
- // 2. As a result of appending search domains, the question may be end up with a .local suffix even though it
- // was not a .local name to start with. In that case, queryrecord_result_callback calls this function to
- // send the additional query.
- //
- // Thus, it should not be called more than once.
- if (*question2)
- {
- LogInfo("SendAdditionalQuery: question2 already sent for %##s (%s), no more q2", q->qname.c, DNSTypeName(q->qtype));
- return err;
- }
-
- if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
- if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q))
- {
- DNSQuestion *q2;
- int labels = CountLabels(&q->qname);
- q2 = mallocL("DNSQuestion", sizeof(DNSQuestion));
- if (!q2) FatalError("ERROR: SendAdditionalQuery malloc");
- *question2 = q2;
- *q2 = *q;
- q2->InterfaceID = mDNSInterface_Unicast;
- q2->ExpectUnique = mDNStrue;
- // Always set the QuestionContext to indicate that this question should be stopped
- // before freeing. Don't rely on "q".
- q2->QuestionContext = request;
- // If the query starts as a single label e.g., somehost, and we have search domains with .local,
- // queryrecord_result_callback calls this function when .local is appended to "somehost".
- // At that time, the name in "q" is pointing at somehost.local and its qnameOrig pointing at
- // "somehost". We need to copy that information so that when we retry with a different search
- // domain e.g., mycompany.local, we get "somehost.mycompany.local".
- if (q->qnameOrig)
- {
- (*question2)->qnameOrig = mallocL("SendAdditionalQuery", DomainNameLength(q->qnameOrig));
- if (!(*question2)->qnameOrig) { LogMsg("SendAdditionalQuery: ERROR!! malloc failure"); return mStatus_NoMemoryErr; }
- (*question2)->qnameOrig->c[0] = 0;
- AssignDomainName((*question2)->qnameOrig, q->qnameOrig);
- LogInfo("SendAdditionalQuery: qnameOrig %##s", (*question2)->qnameOrig->c);
- }
- // For names of the form "<one-or-more-labels>.bar.local." we always do a second unicast query in parallel.
- // For names of the form "<one-label>.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.
- // Note that in the "my-small-company.local" example above there will typically be an SOA record for
- // "my-small-company.local" but *not* for "local", which is why the "local SOA" check would fail in that case.
- // We need to check against both ActiveDirectoryPrimaryDomain and SearchList. If it matches against either
- // of those, we don't want do the SOA check for the local
- if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain) && !DomainInSearchList(&q->qname, mDNSfalse))
- {
- AssignDomainName(&q2->qname, &localdomain);
- q2->qtype = kDNSType_SOA;
- q2->LongLived = mDNSfalse;
- q2->ForceMCast = mDNSfalse;
- q2->ReturnIntermed = mDNStrue;
- // Don't append search domains for the .local SOA query
- q2->AppendSearchDomains = 0;
- q2->AppendLocalSearchDomains = 0;
- q2->RetryWithSearchDomains = mDNSfalse;
- q2->SearchListIndex = 0;
- q2->TimeoutQuestion = 0;
- q2->AnonInfo = mDNSNULL;
- q2->pid = request->process_id;
- q2->euid = request->uid;
- }
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
- err = mDNS_StartQuery(&mDNSStorage, q2);
- if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
- }
- return(err);
-#else // !UNICAST_DISABLED
- (void) q;
- (void) request;
- (void) err;
-
- return mStatus_NoError;
-#endif // !UNICAST_DISABLED
-}
-#endif // APPLE_OSX_mDNSResponder
-
-// This function tries to append a search domain if valid and possible. If so, returns true.
-mDNSlocal mDNSBool RetryQuestionWithSearchDomains(DNSQuestion *question, request_state *req, QC_result AddRecord)
-{
- int result;
- // RetryWithSearchDomains tells the core to call us back so that we can retry with search domains if there is no
- // answer in the cache or /etc/hosts. In the first call back from the core, we clear RetryWithSearchDomains so
- // that we don't get called back repeatedly. If we got an answer from the cache or /etc/hosts, we don't touch
- // RetryWithSearchDomains which may or may not be set.
- //
- // If we get e.g., NXDOMAIN and the query is neither suppressed nor exhausted the domain search list and
- // is a valid question for appending search domains, retry by appending domains
-
- if ((AddRecord != QC_suppressed) && question->SearchListIndex != -1 && question->AppendSearchDomains)
- {
- question->RetryWithSearchDomains = 0;
- result = AppendNewSearchDomain(question);
- // As long as the result is either zero or 1, we retry the question. If we exahaust the search
- // domains (result is zero) we try the original query (as it was before appending the search
- // domains) as such on the wire as a last resort if we have not tried them before. For queries
- // with more than one label, we have already tried them before appending search domains and
- // hence don't retry again
- if (result != -1)
- {
- mStatus err;
- err = mDNS_StartQuery(&mDNSStorage, question);
- if (!err)
- {
- LogOperation("%3d: RetryQuestionWithSearchDomains(%##s, %s), retrying after appending search domain", req->sd, question->qname.c, DNSTypeName(question->qtype));
- // If the result was zero, it meant that there are no search domains and we just retried the question
- // as a single label and we should not retry with search domains anymore.
- if (!result) question->SearchListIndex = -1;
- return mDNStrue;
- }
- else
- {
- LogMsg("%3d: ERROR: RetryQuestionWithSearchDomains %##s %s mDNS_StartQuery: %d, while retrying with search domains", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
- // We have already stopped the query and could not restart. Reset the appropriate pointers
- // so that we don't call stop again when the question terminates
- question->QuestionContext = mDNSNULL;
- }
- }
- }
- else
- {
- LogDebug("%3d: RetryQuestionWithSearchDomains: Not appending search domains - SuppressQuery %d, SearchListIndex %d, AppendSearchDomains %d", req->sd, AddRecord, question->SearchListIndex, question->AppendSearchDomains);
- }
- return mDNSfalse;
-}
-
-mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord,
- DNSServiceErrorType error)
-{
- char name[MAX_ESCAPED_DOMAIN_NAME];
- size_t len;
- DNSServiceFlags flags = 0;
- reply_state *rep;
- char *data;
-
- ConvertDomainNameToCString(answer->name, name);
-
- LogOperation("%3d: %s(%##s, %s) RESULT %s interface %d: (%s)%s", req->sd,
- req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
- question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
- mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
- MortalityDisplayString(answer->mortality), RRDisplayString(m, answer));
-
- len = sizeof(DNSServiceFlags); // calculate reply data length
- len += sizeof(mDNSu32); // interface index
- len += sizeof(DNSServiceErrorType);
- len += strlen(name) + 1;
- len += 3 * sizeof(mDNSu16); // type, class, rdlen
- len += answer->rdlength;
- len += sizeof(mDNSu32); // TTL
-
- rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
-
- if (AddRecord)
- flags |= kDNSServiceFlagsAdd;
- if (answer->mortality == Mortality_Ghost)
- flags |= kDNSServiceFlagsExpiredAnswer;
- if (question->ValidationStatus != 0)
+ if (AddRecord)
+ flags |= kDNSServiceFlagsAdd;
+ if (answer->mortality == Mortality_Ghost)
+ flags |= kDNSServiceFlagsExpiredAnswer;
+ if (!question->InitialCacheMiss)
+ flags |= kDNSServiceFlagAnsweredFromCache;
+ if (question->ValidationStatus != 0)
{
error = kDNSServiceErr_NoError;
if (question->ValidationRequired && question->ValidationState == DNSSECValDone)
put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
append_reply(req, rep);
- // Stop the question, if we just timed out
- if (error == kDNSServiceErr_Timeout)
- {
- mDNS_StopQuery(m, question);
- // Reset the pointers so that we don't call stop on termination
- question->QuestionContext = mDNSNULL;
- }
- else if ((AddRecord == QC_add) && req->hdr.op == addrinfo_request)
- {
- // Note: We count all answers including LocalOnly e.g., /etc/hosts. If we
- // exclude that, v4ans/v6ans will be zero and we would wrongly think that
- // we did not answer questions and setup the status to deliver triggers.
- if (question->qtype == kDNSType_A)
- req->u.addrinfo.v4ans = 1;
- if (question->qtype == kDNSType_AAAA)
- req->u.addrinfo.v6ans = 1;
- }
- else if ((AddRecord == QC_add) && req->hdr.op == query_request)
- {
- if (question->qtype == kDNSType_A || question->qtype == kDNSType_AAAA)
- req->u.queryrecord.ans = 1;
- }
-
-#if APPLE_OSX_mDNSResponder
-#if !NO_WCF
- CHECK_WCF_FUNCTION(WCFIsServerRunning)
- {
- struct xucred x;
- socklen_t xucredlen = sizeof(x);
-
- if (WCFIsServerRunning((WCFConnection *)m->WCF) && answer->rdlength != 0)
- {
- if (getsockopt(req->sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 &&
- (x.cr_version == XUCRED_VERSION))
- {
- struct sockaddr_storage addr;
- addr.ss_len = 0;
- if (answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA)
- {
- if (answer->rrtype == kDNSType_A)
- {
- struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
- sin->sin_port = 0;
- // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
- // sin->sin_addr.s_addr = answer->rdata->u.ipv4.NotAnInteger;
- if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), answer))
- LogMsg("queryrecord_result_reply: WCF AF_INET putRData failed");
- else
- {
- addr.ss_len = sizeof (struct sockaddr_in);
- addr.ss_family = AF_INET;
- }
- }
- else if (answer->rrtype == kDNSType_AAAA)
- {
- struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
- sin6->sin6_port = 0;
- // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
- // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = answer->rdata->u.ipv6.l[0];
- // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = answer->rdata->u.ipv6.l[1];
- // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = answer->rdata->u.ipv6.l[2];
- // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = answer->rdata->u.ipv6.l[3];
- if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), answer))
- LogMsg("queryrecord_result_reply: WCF AF_INET6 putRData failed");
- else
- {
- addr.ss_len = sizeof (struct sockaddr_in6);
- addr.ss_family = AF_INET6;
- }
- }
- if (addr.ss_len)
- {
- debugf("queryrecord_result_reply: Name %s, uid %u, addr length %d", name, x.cr_uid, addr.ss_len);
- CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
- {
- WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, x.cr_uid);
- }
- }
- }
- else if (answer->rrtype == kDNSType_CNAME)
- {
- domainname cname;
- char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
- if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), answer))
- LogMsg("queryrecord_result_reply: WCF CNAME putRData failed");
- else
- {
- ConvertDomainNameToCString(&cname, cname_cstr);
- CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
- {
- WCFNameResolvesToName(m->WCF, name, cname_cstr, x.cr_uid);
- }
- }
- }
- }
- else my_perror("queryrecord_result_reply: ERROR: getsockopt LOCAL_PEERCRED");
- }
- }
-#endif
-#endif
-}
-
-mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
- request_state *req = question->QuestionContext;
- DNSServiceErrorType error = kDNSServiceErr_NoError;
- DNSQuestion *q = mDNSNULL;
-
-#if APPLE_OSX_mDNSResponder
- {
- // Sanity check: QuestionContext is set to NULL after we stop the question and hence we should not
- // get any callbacks from the core after this.
- if (!req)
- {
- LogMsg("queryrecord_result_callback: ERROR!! QuestionContext NULL for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- return;
- }
- if (req->hdr.op == query_request && question == req->u.queryrecord.q2)
- q = &req->u.queryrecord.q;
- else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q42)
- q = &req->u.addrinfo.q4;
- else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q62)
- q = &req->u.addrinfo.q6;
-
- if (q && question->qtype != q->qtype && !SameDomainName(&question->qname, &q->qname))
- {
- mStatus err;
- domainname *orig = question->qnameOrig;
-
- LogInfo("queryrecord_result_callback: Stopping q2 local %##s", question->qname.c);
- mDNS_StopQuery(m, question);
- question->QuestionContext = mDNSNULL;
-
- // We got a negative response for the SOA record indicating that .local does not exist.
- // But we might have other search domains (that does not end in .local) that can be
- // appended to this question. In that case, we want to retry the question. Otherwise,
- // we don't want to try this question as unicast.
- if (answer->RecordType == kDNSRecordTypePacketNegative && !q->AppendSearchDomains)
- {
- LogInfo("queryrecord_result_callback: question %##s AppendSearchDomains zero", q->qname.c);
- return;
- }
-
- // If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
- //
- // Note: When we copy the original question, we copy everything including the AppendSearchDomains,
- // RetryWithSearchDomains except for qnameOrig which can be non-NULL if the original question is
- // e.g., somehost and then we appended e.g., ".local" and retried that question. See comment in
- // SendAdditionalQuery as to how qnameOrig gets initialized.
- *question = *q;
- question->InterfaceID = mDNSInterface_Unicast;
- question->ExpectUnique = mDNStrue;
- question->qnameOrig = orig;
-
- LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast, context %p", req->sd, question->qname.c, DNSTypeName(question->qtype), question->QuestionContext);
-
- // If the original question timed out, its QuestionContext would already be set to NULL and that's what we copied above.
- // Hence, we need to set it explicitly here.
- question->QuestionContext = req;
- err = mDNS_StartQuery(m, question);
- if (err) LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
-
- // If we got a positive response to local SOA, then try the .local question as unicast
- if (answer->RecordType != kDNSRecordTypePacketNegative) return;
-
- // Fall through and get the next search domain. The question is pointing at .local
- // and we don't want to try that. Try the next search domain. Don't try with local
- // search domains for the unicast question anymore.
- //
- // Note: we started the question above which will be stopped immediately (never sent on the wire)
- // before we pick the next search domain below. RetryQuestionWithSearchDomains assumes that the
- // question has already started.
- question->AppendLocalSearchDomains = 0;
- }
-
- if (q && AddRecord && AddRecord != QC_dnssec && (question->InterfaceID == mDNSInterface_Unicast) && !answer->rdlength)
- {
- // If we get a negative response to the unicast query that we sent above, retry after appending search domains
- // Note: We could have appended search domains below (where do it for regular unicast questions) instead of doing it here.
- // As we ignore negative unicast answers below, we would never reach the code where the search domains are appended.
- // To keep things simple, we handle unicast ".local" separately here.
- LogInfo("queryrecord_result_callback: Retrying .local question %##s (%s) as unicast after appending search domains", question->qname.c, DNSTypeName(question->qtype));
- if (RetryQuestionWithSearchDomains(question, req, AddRecord))
- return;
- if (question->AppendSearchDomains && !question->AppendLocalSearchDomains && IsLocalDomain(&question->qname))
- {
- // If "local" is the last search domain, we need to stop the question so that we don't send the "local"
- // question on the wire as we got a negative response for the local SOA. But, we can't stop the question
- // yet as we may have to timeout the question (done by the "core") for which we need to leave the question
- // in the list. We leave it disabled so that it does not hit the wire.
- LogInfo("queryrecord_result_callback: Disabling .local question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- question->ThisQInterval = 0;
- }
- }
- // If we are here it means that either "question" is not "q2" OR we got a positive response for "q2" OR we have no more search
- // domains to append for "q2". In all cases, fall through and deliver the response
- }
-#endif // APPLE_OSX_mDNSResponder
-
- // If a query is being suppressed for some reason, we don't have to do any other
- // processing.
- //
- // Note: We don't check for "SuppressQuery" and instead use QC_suppressed because
- // the "core" needs to temporarily turn off SuppressQuery to answer this query.
- if (AddRecord == QC_suppressed)
- {
- LogDebug("queryrecord_result_callback: Suppressed question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
- queryrecord_result_reply(m, req, question, answer, AddRecord, kDNSServiceErr_NoSuchRecord);
- return;
- }
-
- if (answer->RecordType == kDNSRecordTypePacketNegative)
- {
- // If this question needs to be timed out and we have reached the stop time, mark
- // the error as timeout. It is possible that we might get a negative response from an
- // external DNS server at the same time when this question reaches its stop time. We
- // can't tell the difference as there is no indication in the callback. This should
- // be okay as we will be timing out this query anyway.
- mDNS_Lock(m);
- if (question->TimeoutQuestion)
- {
- if ((m->timenow - question->StopTime) >= 0)
- {
- LogInfo("queryrecord_result_callback:Question %##s (%s) timing out, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
- error = kDNSServiceErr_Timeout;
- }
- }
- mDNS_Unlock(m);
- // 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 we are timing out this query, we need to deliver the negative answer to the application
- if (error != kDNSServiceErr_Timeout)
- {
- if (!answer->InterfaceID && IsLocalDomain(answer->name))
- {
- // Sanity check: "q" will be set only if "question" is the .local unicast query.
- if (!q)
- {
- LogMsg("queryrecord_result_callback: ERROR!! answering multicast question %s with unicast cache record",
- RRDisplayString(m, answer));
- return;
- }
-#if APPLE_OSX_mDNSResponder
- if (!ShouldDeliverNegativeResponse(question))
- {
- return;
- }
-#endif // APPLE_OSX_mDNSResponder
- LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with negative unicast response", question->qname.c,
- DNSTypeName(question->qtype));
- }
- error = kDNSServiceErr_NoSuchRecord;
- }
- }
- // If we get a negative answer, try appending search domains. Don't append search domains
- // - if we are timing out this question
- // - if the negative response was received as a result of a multicast query
- // - if this is an additional query (q2), we already appended search domains above (indicated by "!q" below)
- // - if this response is forced e.g., dnssec validation result
- if (error != kDNSServiceErr_Timeout)
- {
- if (!q && !answer->InterfaceID && !answer->rdlength && AddRecord && AddRecord != QC_dnssec)
- {
- // If the original question did not end in .local, we did not send an SOA query
- // to figure out whether we should send an additional unicast query or not. If we just
- // appended .local, we need to see if we need to send an additional query. This should
- // normally happen just once because after we append .local, we ignore all negative
- // responses for .local above.
- LogDebug("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype));
- if (RetryQuestionWithSearchDomains(question, req, AddRecord))
- {
- // Note: We need to call SendAdditionalQuery every time after appending a search domain as .local could
- // be anywhere in the search domain list.
-#if APPLE_OSX_mDNSResponder
- mStatus err = mStatus_NoError;
- err = SendAdditionalQuery(question, req, err);
- if (err) LogMsg("queryrecord_result_callback: Sending .local SOA query failed, after appending domains");
-#endif // APPLE_OSX_mDNSResponder
- return;
- }
- }
- }
- queryrecord_result_reply(m, req, question, answer, AddRecord, error);
}
mDNSlocal void queryrecord_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) STOP PID[%d](%s)",
- request->sd, request->flags, request->interfaceIndex, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name);
- if (request->u.queryrecord.q.QuestionContext)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q); // no need to error check
- LogMcastQ(&request->u.queryrecord.q, request, q_stop);
- request->u.queryrecord.q.QuestionContext = mDNSNULL;
- }
- else
- {
- DNSQuestion *question = &request->u.queryrecord.q;
- LogInfo("queryrecord_termination_callback: question %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
- }
-
- if (request->u.queryrecord.q.qnameOrig)
- {
- freeL("QueryTermination", request->u.queryrecord.q.qnameOrig);
- request->u.queryrecord.q.qnameOrig = mDNSNULL;
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceQueryRecord(%X, %d, " PRI_DM_NAME ", " PUB_S ") STOP PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex,
+ DM_NAME_PARAM(QueryRecordClientRequestGetQName(&request->u.queryrecord)->c),
+ DNSTypeName(QueryRecordClientRequestGetType(&request->u.queryrecord)), request->process_id, request->pid_name);
- if (callExternalHelpers(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.flags))
- {
- LogInfo("queryrecord_termination_callback: calling external_stop_browsing_for_service()");
- external_stop_browsing_for_service(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype, request->u.queryrecord.q.flags);
- }
- if (request->u.queryrecord.q2)
- {
- if (request->u.queryrecord.q2->QuestionContext)
- {
- LogInfo("queryrecord_termination_callback: Stopping q2 %##s", request->u.queryrecord.q2->qname.c);
- mDNS_StopQuery(&mDNSStorage, request->u.queryrecord.q2);
- LogMcastQ(request->u.queryrecord.q2, request, q_stop);
- }
- else
- {
- DNSQuestion *question = request->u.queryrecord.q2;
- LogInfo("queryrecord_termination_callback: q2 %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
- }
- if (request->u.queryrecord.q2->qnameOrig)
- {
- LogInfo("queryrecord_termination_callback: freeing q2 qnameOrig %##s", request->u.queryrecord.q2->qnameOrig->c);
- freeL("QueryTermination q2", request->u.queryrecord.q2->qnameOrig);
- request->u.queryrecord.q2->qnameOrig = mDNSNULL;
- }
- freeL("queryrecord Q2", request->u.queryrecord.q2);
- request->u.queryrecord.q2 = mDNSNULL;
- }
-#if APPLE_OSX_mDNSResponder
- {
- if (request->u.queryrecord.ans)
- {
- DNSQuestion *v4q, *v6q;
- // If we are receiving poisitive answers, provide the hint to the
- // upper layer.
- v4q = v6q = mDNSNULL;
- if (request->u.queryrecord.q.qtype == kDNSType_A)
- v4q = &request->u.queryrecord.q;
- else if (request->u.queryrecord.q.qtype == kDNSType_AAAA)
- v6q = &request->u.queryrecord.q;
- mDNSPlatformTriggerDNSRetry(v4q, v6q);
- }
- }
-#endif // APPLE_OSX_mDNSResponder
+ QueryRecordClientRequestStop(&request->u.queryrecord);
}
mDNSlocal mStatus handle_queryrecord_request(request_state *request)
{
- DNSQuestion *const q = &request->u.queryrecord.q;
- char name[256];
- size_t nameLen;
- mDNSu16 rrtype, rrclass;
- mStatus err;
-
- DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
- mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
- mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+ mStatus err;
+ DNSServiceFlags flags;
+ mDNSu32 interfaceIndex;
+ mDNSu16 qtype, qclass;
+ char qname[MAX_ESCAPED_DOMAIN_NAME];
- // The request is scoped to a specific interface index, but the
- // interface is not currently in our list.
- if (interfaceIndex && !InterfaceID)
+ flags = get_flags(&request->msgptr, request->msgend);
+ interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ if (get_string(&request->msgptr, request->msgend, qname, sizeof(qname)) < 0)
{
- if (interfaceIndex > 1)
- LogMsg("handle_queryrecord_request: interfaceIndex %d is currently inactive requested by client[%d][%s]",
- interfaceIndex, request->process_id, request->pid_name);
- // If it's one of the specially defined inteface index values, just return an error.
- // Also, caller should return an error immediately if lo0 (index 1) is not configured
- // into the current active interfaces. See background in Radar 21967160.
- if (PreDefinedInterfaceIndex(interfaceIndex) || interfaceIndex == 1)
- {
- LogInfo("handle_queryrecord_request: bad interfaceIndex %d", interfaceIndex);
- return(mStatus_BadParamErr);
- }
-
- // Otherwise, use the specified interface index value and the request will
- // be applied to that interface when it comes up.
- InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
- LogInfo("handle_queryrecord_request: query pending for interface index %d", interfaceIndex);
+ err = mStatus_BadParamErr;
+ goto exit;
}
-
- if (get_string(&request->msgptr, request->msgend, name, 256) < 0) return(mStatus_BadParamErr);
- rrtype = get_uint16(&request->msgptr, request->msgend);
- rrclass = get_uint16(&request->msgptr, request->msgend);
+ qtype = get_uint16(&request->msgptr, request->msgend);
+ qclass = get_uint16(&request->msgptr, request->msgend);
if (!request->msgptr)
- { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
-
- request->flags = flags;
- request->interfaceIndex = interfaceIndex;
- mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord));
-
- q->InterfaceID = InterfaceID;
- q->flags = flags;
- 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->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
- q->TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0;
- q->allowExpired = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None;
- q->WakeOnResolve = 0;
- q->UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- if ((flags & kDNSServiceFlagsValidate) != 0)
- q->ValidationRequired = DNSSEC_VALIDATION_SECURE;
- else if ((flags & kDNSServiceFlagsValidateOptional) != 0)
- q->ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
- q->ValidatingResponse = 0;
- q->ProxyQuestion = 0;
- q->AnonInfo = mDNSNULL;
- q->QuestionCallback = queryrecord_result_callback;
- q->QuestionContext = request;
- q->SearchListIndex = 0;
- q->StopTime = 0;
-
- q->DNSSECAuthInfo = mDNSNULL;
- q->DAIFreeCallback = mDNSNULL;
-
- //Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet)
- if ((IsLocalDomain(&q->qname)) || (q->qtype == kDNSServiceType_RRSIG) || (q->qtype == kDNSServiceType_ANY))
- q->ValidationRequired = 0;
-
- // Don't append search domains for fully qualified domain names including queries
- // such as e.g., "abc." that has only one label. We convert all names to FQDNs as internally
- // we only deal with FQDNs. Hence, we cannot look at qname to figure out whether we should
- // append search domains or not. So, we record that information in AppendSearchDomains.
- //
- // We append search domains only for queries that are a single label. If overriden using command line
- // argument "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified.
- // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set.
-
- nameLen = strlen(name);
- if ((!(q->ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(q->ValidationRequired == DNSSEC_VALIDATION_INSECURE))
- && (rrtype == kDNSType_A || rrtype == kDNSType_AAAA) && ((nameLen == 0) || (name[nameLen - 1] != '.')) &&
- (AlwaysAppendSearchDomains || CountLabels(&q->qname) == 1))
- {
- q->AppendSearchDomains = 1;
- q->AppendLocalSearchDomains = 1;
- }
- else
{
- q->AppendSearchDomains = 0;
- q->AppendLocalSearchDomains = 0;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceQueryRecord(unreadable parameters)", request->request_id);
+ err = mStatus_BadParamErr;
+ goto exit;
}
- // For single label queries that are not fully qualified, look at /etc/hosts, cache and try
- // search domains before trying them on the wire as a single label query. RetryWithSearchDomains
- // tell the core to call back into the UDS layer if there is no valid response in /etc/hosts or
- // the cache
- q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
- q->qnameOrig = mDNSNULL;
- SetQuestionPolicy(q, request);
+ request->flags = flags;
+ request->interfaceIndex = interfaceIndex;
-#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
- // Determine if this request should be promoted to use BLE triggered discovery.
- if (shouldUseBLE(InterfaceID, rrtype, (domainname *)SkipLeadingLabels(&q->qname, 1), &q->qname))
- {
- q->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
- request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
- LogInfo("handle_queryrecord_request: request promoted to use kDNSServiceFlagsAutoTrigger");
- }
-#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceQueryRecord(%X, %d, " PRI_S ", " PUB_S ") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, qname, DNSTypeName(qtype), request->process_id,
+ request->pid_name);
- LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START PID[%d](%s)",
- request->sd, request->flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name);
- err = mDNS_StartQuery(&mDNSStorage, q);
+ mDNSPlatformMemZero(&request->u.queryrecord, (mDNSu32)sizeof(request->u.queryrecord));
- 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;
- LogMcastQ(q, request, q_start);
- if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
- {
- LogDebug("handle_queryrecord_request: calling external_start_browsing_for_service()");
- external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags);
- }
- }
+ err = QueryRecordClientRequestStart(&request->u.queryrecord, request->request_id, qname, interfaceIndex, flags, qtype,
+ qclass, request->validUUID ? 0 : request->process_id, request->validUUID ? request->uuid : mDNSNULL, request->uid,
+ queryrecord_result_reply, request);
+ if (err) goto exit;
-#if APPLE_OSX_mDNSResponder
- err = SendAdditionalQuery(q, request, err);
-#endif // APPLE_OSX_mDNSResponder
+ request->terminate = queryrecord_termination_callback;
+exit:
return(err);
}
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);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d->Q%d] DNSServiceEnumerateDomains(%2.*s) RESULT " PUB_S ": " PRI_S,
+ request->request_id, mDNSVal16(question->TargetQID), question->qname.c[0], &question->qname.c[1],
+ AddRecord ? "ADD" : "RMV", domain);
append_reply(request, reply);
}
// extract the data from the message
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
- if (get_string(&request->msgptr, request->msgend, name, 256) < 0 ||
- get_string(&request->msgptr, request->msgend, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
- get_string(&request->msgptr, request->msgend, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
+ if (get_string(&request->msgptr, request->msgend, name, sizeof(name )) < 0 ||
+ get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+ get_string(&request->msgptr, request->msgend, domain, sizeof(domain )) < 0)
{
LogMsg("ERROR: handle_release_request - Couldn't read name/regtype/domain");
return(mStatus_BadParamErr);
return(mStatus_BadParamErr);
}
- LogOperation("%3d: PeerConnectionRelease(%X %##s) START PID[%d](%s)",
- request->sd, flags, instance.c, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] PeerConnectionRelease(%X " PRI_DM_NAME ") START PID[%d](" PUB_S ")",
+ request->request_id, flags, DM_NAME_PARAM(instance.c), request->process_id, request->pid_name);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
external_connection_release(&instance);
+#endif
return(err);
}
domainname domain;
DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
(void)flags; // Unused
- if (get_string(&request->msgptr, request->msgend, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
+ if (get_string(&request->msgptr, request->msgend, domainstr, sizeof(domainstr)) < 0 ||
!MakeDomainNameFromDNSNameString(&domain, domainstr))
{ LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
char prop[256];
if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
{
- LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceGetProperty(" PUB_S ")", request->request_id, prop);
if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
{
DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
mDNSs32 pid;
socklen_t len;
- LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
- request->sd, request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PUB_S ")",
+ request->request_id, request->process_id, request->pid_name);
request->terminate = connection_termination;
len = 0;
mDNSs32 pid;
} PIDInfo;
-mDNSlocal void handle_getpid_request(request_state *request)
-{
- const request_state *req;
- mDNSs32 pid = -1;
- mDNSu16 srcport = get_uint16(&request->msgptr, request->msgend);
- const DNSQuestion *q = NULL;
- PIDInfo pi;
-
- LogMsg("%3d: DNSServiceGetPID START", request->sd);
-
- for (req = all_requests; req; req=req->next)
- {
- if (req->hdr.op == query_request)
- q = &req->u.queryrecord.q;
- else if (req->hdr.op == addrinfo_request)
- q = &req->u.addrinfo.q4;
- else if (req->hdr.op == addrinfo_request)
- q = &req->u.addrinfo.q6;
-
- if (q && q->LocalSocket != NULL)
- {
- mDNSu16 port = mDNSPlatformGetUDPPort(q->LocalSocket);
- if (port == srcport)
- {
- pid = req->process_id;
- LogMsg("DNSServiceGetPID: srcport %d, pid %d [%s] question %##s", htons(srcport), pid, req->pid_name, q->qname.c);
- break;
- }
- }
- }
- // If we cannot find in the client requests, look to see if this was
- // started by mDNSResponder.
- if (pid == -1)
- {
- for (q = mDNSStorage.Questions; q; q = q->next)
- {
- if (q && q->LocalSocket != NULL)
- {
- mDNSu16 port = mDNSPlatformGetUDPPort(q->LocalSocket);
- if (port == srcport)
- {
-#if APPLE_OSX_mDNSResponder
- pid = getpid();
-#endif // APPLE_OSX_mDNSResponder
- LogMsg("DNSServiceGetPID: srcport %d, pid %d [%s], question %##s", htons(srcport), pid, "_mDNSResponder", q->qname.c);
- break;
- }
- }
- }
- }
-
- pi.err = 0;
- pi.pid = pid;
- send_all(request->sd, (const char *)&pi, sizeof(PIDInfo));
- LogMsg("%3d: DNSServiceGetPID STOP", request->sd);
-}
-
// ***************************************************************************
#if COMPILER_LIKES_PRAGMA_MARK
#pragma mark -
mDNSlocal void port_mapping_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](%s)", request->sd,
- DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
- mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](" PUB_S ")",
+ request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+ mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+ request->process_id, request->pid_name);
+
mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
}
*data++ = request->u.pm.NATinfo.ExternalPort.b[1];
put_uint32(request->u.pm.NATinfo.Lifetime, &data);
- LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT %.4a:%u TTL %u", request->sd,
- DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
- mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
- &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort), request->u.pm.NATinfo.Lifetime);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT " PRI_IPv4_ADDR ":%u TTL %u",
+ request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+ mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+ &request->u.pm.NATinfo.ExternalAddress, mDNSVal16(request->u.pm.NATinfo.ExternalPort),
+ request->u.pm.NATinfo.Lifetime);
append_reply(request, rep);
}
}
if (!request->msgptr)
- { LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%d] DNSServiceNATPortMappingCreate(unreadable parameters)", request->request_id);
+ return(mStatus_BadParamErr);
+ }
if (protocol == 0) // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
{
request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
request->u.pm.NATinfo.clientContext = request;
- LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](%s)", request->sd,
- protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
- request->process_id, request->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](" PUB_S ")",
+ request->request_id, protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt),
+ request->u.pm.NATinfo.NATLease, request->process_id, request->pid_name);
err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
else request->terminate = port_mapping_termination_callback;
mDNSlocal void addrinfo_termination_callback(request_state *request)
{
- LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP PID[%d](%s)", request->sd, request->u.addrinfo.q4.qname.c,
- request->process_id, request->pid_name);
-
- if (request->u.addrinfo.q4.QuestionContext)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
- LogMcastQ(&request->u.addrinfo.q4, request, q_stop);
- request->u.addrinfo.q4.QuestionContext = mDNSNULL;
-
- if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, request->flags))
- {
- LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for A record");
- external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, kDNSServiceType_A, request->flags);
- }
- }
- if (request->u.addrinfo.q4.qnameOrig)
- {
- freeL("QueryTermination", request->u.addrinfo.q4.qnameOrig);
- request->u.addrinfo.q4.qnameOrig = mDNSNULL;
- }
- if (request->u.addrinfo.q42)
- {
- if (request->u.addrinfo.q42->QuestionContext)
- {
- LogInfo("addrinfo_termination_callback: Stopping q42 %##s", request->u.addrinfo.q42->qname.c);
- mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q42);
- LogMcastQ(request->u.addrinfo.q42, request, q_stop);
- }
- if (request->u.addrinfo.q42->qnameOrig)
- {
- LogInfo("addrinfo_termination_callback: freeing q42 qnameOrig %##s", request->u.addrinfo.q42->qnameOrig->c);
- freeL("QueryTermination q42", request->u.addrinfo.q42->qnameOrig);
- request->u.addrinfo.q42->qnameOrig = mDNSNULL;
- }
- freeL("addrinfo Q42", request->u.addrinfo.q42);
- request->u.addrinfo.q42 = mDNSNULL;
- }
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceGetAddrInfo(" PRI_DM_NAME ") STOP PID[%d](" PUB_S ")",
+ request->request_id, DM_NAME_PARAM(GetAddrInfoClientRequestGetQName(&request->u.addrinfo)->c),
+ request->process_id, request->pid_name);
- if (request->u.addrinfo.q6.QuestionContext)
- {
- mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
- LogMcastQ(&request->u.addrinfo.q6, request, q_stop);
- request->u.addrinfo.q6.QuestionContext = mDNSNULL;
-
- if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, request->flags))
- {
- LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record");
- external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, kDNSServiceType_AAAA, request->flags);
- }
- }
- if (request->u.addrinfo.q6.qnameOrig)
- {
- freeL("QueryTermination", request->u.addrinfo.q6.qnameOrig);
- request->u.addrinfo.q6.qnameOrig = mDNSNULL;
- }
- if (request->u.addrinfo.q62)
- {
- if (request->u.addrinfo.q62->QuestionContext)
- {
- LogInfo("addrinfo_termination_callback: Stopping q62 %##s", request->u.addrinfo.q62->qname.c);
- mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q62);
- LogMcastQ(request->u.addrinfo.q62, request, q_stop);
- }
- if (request->u.addrinfo.q62->qnameOrig)
- {
- LogInfo("addrinfo_termination_callback: freeing q62 qnameOrig %##s", request->u.addrinfo.q62->qnameOrig->c);
- freeL("QueryTermination q62", request->u.addrinfo.q62->qnameOrig);
- request->u.addrinfo.q62->qnameOrig = mDNSNULL;
- }
- freeL("addrinfo Q62", request->u.addrinfo.q62);
- request->u.addrinfo.q62 = mDNSNULL;
- }
-#if APPLE_OSX_mDNSResponder
- {
- DNSQuestion *v4q, *v6q;
- v4q = v6q = mDNSNULL;
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
- {
- // If we are not delivering answers, we may be timing out prematurely.
- // Note down the current state so that we know to retry when we see a
- // valid response again.
- if (request->u.addrinfo.q4.TimeoutQuestion && !request->u.addrinfo.v4ans)
- {
- mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q4);
- }
- // If we have a v4 answer and if we timed out prematurely before, provide
- // a trigger to the upper layer so that it can retry questions if needed.
- if (request->u.addrinfo.v4ans)
- v4q = &request->u.addrinfo.q4;
- }
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
- {
- if (request->u.addrinfo.q6.TimeoutQuestion && !request->u.addrinfo.v6ans)
- {
- mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q6);
- }
- if (request->u.addrinfo.v6ans)
- v6q = &request->u.addrinfo.q6;
- }
- mDNSPlatformTriggerDNSRetry(v4q, v6q);
- }
-#endif // APPLE_OSX_mDNSResponder
+ GetAddrInfoClientRequestStop(&request->u.addrinfo);
}
mDNSlocal mStatus handle_addrinfo_request(request_state *request)
{
- char hostname[256];
- size_t hostnameLen;
- domainname d;
- mStatus err = 0;
- mDNSs32 serviceIndex = -1; // default unscoped value for ServiceID is -1
- mDNSInterfaceID InterfaceID;
-
- DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
-
- mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ mStatus err;
+ DNSServiceFlags flags;
+ mDNSu32 interfaceIndex;
+ mDNSu32 protocols;
+ char hostname[MAX_ESCAPED_DOMAIN_NAME];
- if (flags & kDNSServiceFlagsServiceIndex)
+ flags = get_flags(&request->msgptr, request->msgend);
+ interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+ protocols = get_uint32(&request->msgptr, request->msgend);
+ if (get_string(&request->msgptr, request->msgend, hostname, sizeof(hostname)) < 0)
{
- // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
- LogInfo("DNSServiceGetAddrInfo: kDNSServiceFlagsServiceIndex is SET by the client");
- // if kDNSServiceFlagsServiceIndex is SET,
- // interpret the interfaceID as the serviceId and set the interfaceID to 0.
- serviceIndex = interfaceIndex;
- interfaceIndex = 0;
+ err = mStatus_BadParamErr;
+ goto exit;
}
-
- mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
-
- InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-
- // The request is scoped to a specific interface index, but the
- // interface is not currently in our list.
- if (interfaceIndex && !InterfaceID)
+ if (!request->msgptr)
{
- if (interfaceIndex > 1)
- LogMsg("handle_addrinfo_request: interfaceIndex %d is currently inactive requested by client[%d][%s]",
- interfaceIndex, request->process_id, request->pid_name);
- // If it's one of the specially defined inteface index values, just return an error.
- if (PreDefinedInterfaceIndex(interfaceIndex))
- {
- LogInfo("handle_addrinfo_request: bad interfaceIndex %d", interfaceIndex);
- return(mStatus_BadParamErr);
- }
-
- // Otherwise, use the specified interface index value and the request will
- // be applied to that interface when it comes up.
- InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
- LogInfo("handle_addrinfo_request: query pending for interface index %d", interfaceIndex);
+ LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd);
+ err = mStatus_BadParamErr;
+ goto exit;
}
- request->flags = flags;
- request->interfaceIndex = interfaceIndex;
- request->u.addrinfo.interface_id = InterfaceID;
- 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 (get_string(&request->msgptr, request->msgend, hostname, 256) < 0) return(mStatus_BadParamErr);
-
- if (!request->msgptr) { LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
-
- 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)
- {
- flags |= kDNSServiceFlagsSuppressUnusable;
- request->u.addrinfo.protocol = (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
- }
-
- request->u.addrinfo.q4.InterfaceID = request->u.addrinfo.q6.InterfaceID = request->u.addrinfo.interface_id;
- request->u.addrinfo.q4.ServiceID = request->u.addrinfo.q6.ServiceID = serviceIndex;
- request->u.addrinfo.q4.flags = request->u.addrinfo.q6.flags = flags;
- request->u.addrinfo.q4.Target = request->u.addrinfo.q6.Target = zeroAddr;
- request->u.addrinfo.q4.qname = request->u.addrinfo.q6.qname = d;
- request->u.addrinfo.q4.qclass = request->u.addrinfo.q6.qclass = kDNSServiceClass_IN;
- request->u.addrinfo.q4.LongLived = request->u.addrinfo.q6.LongLived = (flags & kDNSServiceFlagsLongLivedQuery ) != 0;
- request->u.addrinfo.q4.ExpectUnique = request->u.addrinfo.q6.ExpectUnique = mDNSfalse;
- request->u.addrinfo.q4.ForceMCast = request->u.addrinfo.q6.ForceMCast = (flags & kDNSServiceFlagsForceMulticast ) != 0;
- request->u.addrinfo.q4.ReturnIntermed = request->u.addrinfo.q6.ReturnIntermed = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
- request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable ) != 0;
- request->u.addrinfo.q4.TimeoutQuestion = request->u.addrinfo.q6.TimeoutQuestion = (flags & kDNSServiceFlagsTimeout ) != 0;
- request->u.addrinfo.q4.allowExpired = request->u.addrinfo.q6.allowExpired = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None;
- request->u.addrinfo.q4.WakeOnResolve = request->u.addrinfo.q6.WakeOnResolve = 0;
- request->u.addrinfo.q4.UseBackgroundTrafficClass = request->u.addrinfo.q6.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
- if ((flags & kDNSServiceFlagsValidate) != 0)
- request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE;
- else if ((flags & kDNSServiceFlagsValidateOptional) != 0)
- request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
- request->u.addrinfo.q4.ValidatingResponse = request->u.addrinfo.q6.ValidatingResponse = 0;
- request->u.addrinfo.q4.ProxyQuestion = request->u.addrinfo.q6.ProxyQuestion = 0;
- request->u.addrinfo.q4.qnameOrig = request->u.addrinfo.q6.qnameOrig = mDNSNULL;
- request->u.addrinfo.q4.AnonInfo = request->u.addrinfo.q6.AnonInfo = mDNSNULL;
-
- SetQuestionPolicy(&request->u.addrinfo.q4, request);
- SetQuestionPolicy(&request->u.addrinfo.q6, request);
-
- request->u.addrinfo.q4.StopTime = request->u.addrinfo.q6.StopTime = 0;
-
- request->u.addrinfo.q4.DNSSECAuthInfo = request->u.addrinfo.q6.DNSSECAuthInfo = mDNSNULL;
- request->u.addrinfo.q4.DAIFreeCallback = request->u.addrinfo.q6.DAIFreeCallback = mDNSNULL;
-
- //Turn off dnssec validation for local domains
- if (IsLocalDomain(&d))
- request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = 0;
-
- hostnameLen = strlen(hostname);
-
- LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START PID[%d](%s)",
- request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c, request->process_id, request->pid_name);
-
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
- {
- request->u.addrinfo.q6.qtype = kDNSServiceType_AAAA;
- request->u.addrinfo.q6.SearchListIndex = 0;
- // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set
- if ((!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_INSECURE))
- && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
- {
- request->u.addrinfo.q6.AppendSearchDomains = 1;
- request->u.addrinfo.q6.AppendLocalSearchDomains = 1;
- }
- else
- {
- request->u.addrinfo.q6.AppendSearchDomains = 0;
- request->u.addrinfo.q6.AppendLocalSearchDomains = 0;
- }
- request->u.addrinfo.q6.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q6) ? 1 : 0);
- request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
- request->u.addrinfo.q6.QuestionContext = request;
- err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
- if (err != mStatus_NoError)
- {
- LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
- request->u.addrinfo.q6.QuestionContext = mDNSNULL;
- }
- #if APPLE_OSX_mDNSResponder
- err = SendAdditionalQuery(&request->u.addrinfo.q6, request, err);
- #endif // APPLE_OSX_mDNSResponder
- if (!err)
- {
- request->terminate = addrinfo_termination_callback;
- LogMcastQ(&request->u.addrinfo.q6, request, q_start);
- if (callExternalHelpers(InterfaceID, &d, flags))
- {
- LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for AAAA record");
- external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
- }
- }
- }
+ request->flags = flags;
+ request->interfaceIndex = interfaceIndex;
- if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4))
- {
- request->u.addrinfo.q4.qtype = kDNSServiceType_A;
- request->u.addrinfo.q4.SearchListIndex = 0;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] DNSServiceGetAddrInfo(%X, %d, %u, " PRI_S ") START PID[%d](" PUB_S ")",
+ request->request_id, request->flags, request->interfaceIndex, protocols, hostname, request->process_id,
+ request->pid_name);
- // We append search domains only for queries that are a single label. If overriden using cmd line arg
- // "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified.
- // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set.
+ mDNSPlatformMemZero(&request->u.addrinfo, (mDNSu32)sizeof(request->u.addrinfo));
- if ((!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_INSECURE))
- && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
- {
- request->u.addrinfo.q4.AppendSearchDomains = 1;
- request->u.addrinfo.q4.AppendLocalSearchDomains = 1;
- }
- else
- {
- request->u.addrinfo.q4.AppendSearchDomains = 0;
- request->u.addrinfo.q4.AppendLocalSearchDomains = 0;
- }
- request->u.addrinfo.q4.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q4) ? 1 : 0);
- request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
- request->u.addrinfo.q4.QuestionContext = request;
- err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
- if (err != mStatus_NoError)
- {
- LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
- request->u.addrinfo.q4.QuestionContext = mDNSNULL;
- if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
- {
- // If we started a query for IPv6, we need to cancel it
- mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
- request->u.addrinfo.q6.QuestionContext = mDNSNULL;
+ err = GetAddrInfoClientRequestStart(&request->u.addrinfo, request->request_id, hostname, interfaceIndex, flags,
+ protocols, request->validUUID ? 0 : request->process_id, request->validUUID ? request->uuid : mDNSNULL,
+ request->uid, queryrecord_result_reply, request);
+ if (err) goto exit;
- if (callExternalHelpers(InterfaceID, &d, flags))
- {
- LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record");
- external_stop_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
- }
- }
- }
- #if APPLE_OSX_mDNSResponder
- err = SendAdditionalQuery(&request->u.addrinfo.q4, request, err);
- #endif // APPLE_OSX_mDNSResponder
- if (!err)
- {
- request->terminate = addrinfo_termination_callback;
- LogMcastQ(&request->u.addrinfo.q4, request, q_start);
- if (callExternalHelpers(InterfaceID, &d, flags))
- {
- LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for A record");
- external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags);
- }
- }
- }
+ request->terminate = addrinfo_termination_callback;
+exit:
return(err);
}
mDNSlocal request_state *NewRequest(void)
{
+ request_state *request;
request_state **p = &all_requests;
- while (*p)
- p=&(*p)->next;
- *p = mallocL("request_state", sizeof(request_state));
- if (!*p)
- FatalError("ERROR: malloc");
- mDNSPlatformMemZero(*p, sizeof(request_state));
- return(*p);
+ request = (request_state *) callocL("request_state", sizeof(*request));
+ if (!request) FatalError("ERROR: calloc");
+ while (*p) p = &(*p)->next;
+ *p = request;
+ return(request);
}
// read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
mDNSlocal void read_msg(request_state *req)
{
if (req->ts == t_terminated || req->ts == t_error)
- { LogMsg("%3d: ERROR: read_msg called with transfer state terminated or error", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg called with transfer state terminated or error", req->request_id);
+ req->ts = t_error;
+ return;
+ }
if (req->ts == t_complete) // this must be death or something is wrong
{
int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
if (!nread) { req->ts = t_terminated; return; }
if (nread < 0) goto rerror;
- LogMsg("%3d: ERROR: read data from a completed request", req->sd);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read data from a completed request", req->request_id);
req->ts = t_error;
return;
}
if (req->ts != t_morecoming)
- { LogMsg("%3d: ERROR: read_msg called with invalid transfer state (%d)", req->sd, req->ts); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg called with invalid transfer state (%d)", req->request_id, req->ts);
+ req->ts = t_error;
+ return;
+ }
if (req->hdr_bytes < sizeof(ipc_msg_hdr))
{
if (nread < 0) goto rerror;
req->hdr_bytes += nread;
if (req->hdr_bytes > sizeof(ipc_msg_hdr))
- { LogMsg("%3d: ERROR: read_msg - read too many header bytes", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg - read too many header bytes", req->request_id);
+ req->ts = t_error;
+ return;
+ }
// only read data if header is complete
if (req->hdr_bytes == sizeof(ipc_msg_hdr))
{
ConvertHeaderBytes(&req->hdr);
if (req->hdr.version != VERSION)
- { LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: client version 0x%08X daemon version 0x%08X", req->request_id, req->hdr.version, VERSION);
+ req->ts = t_error;
+ return;
+ }
// Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
// 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 %u (0x%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
- req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
- if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->request_id, req->hdr.datalen, req->hdr.datalen);
+ req->ts = t_error;
+ return;
+ }
+ req->msgbuf = (char *) callocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
+ if (!req->msgbuf) { my_perror("ERROR: calloc"); req->ts = t_error; return; }
req->msgptr = req->msgbuf;
req->msgend = req->msgbuf + req->hdr.datalen;
- mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
}
}
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; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg - read too many data bytes", req->request_id);
+ 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->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] Expecting %d %d %d %d", req->request_id, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] Got %d %d %d %d", req->request_id, msg.msg_controllen, cmsg ? cmsg->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
#endif // DEBUG_64BIT_SCM_RIGHTS
if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
{
if (req->hdr.op == send_bpf)
{
dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
- LogOperation("%3d: Got len %d, BPF %d", req->sd, cmsg->cmsg_len, x);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] Got len %d, BPF %d", req->request_id, cmsg->cmsg_len, x);
mDNSPlatformReceiveBPF_fd(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);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+ "[R%u] read req->errsd %d", req->request_id, req->errsd);
#endif // DEBUG_64BIT_SCM_RIGHTS
if (req->data_bytes < req->hdr.datalen)
{
- LogMsg("%3d: Client(PID [%d](%s)) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
- req->sd, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+ "[R%u] Client(PID [%d](" PUB_S ")) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
+ req->request_id, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
req->ts = t_error;
return;
}
if (ctrl_path[0] == 0)
{
if (req->errsd == req->sd)
- { LogMsg("%3d: read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return; }
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->request_id);
+ req->ts = t_error;
+ return;
+ }
goto got_errfd;
}
#endif
{
#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));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: Couldn't connect to error return path socket " PUB_S " errno %d (" PUB_S ")",
+ req->request_id, 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));
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: stat failed " PUB_S " errno %d (" PUB_S ")",
+ req->request_id, 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);
+ {
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] read_msg: file " PUB_S " mode %o (octal) uid %d gid %d",
+ req->request_id, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+ }
#endif
req->ts = t_error;
return;
#if !defined(USE_TCP_LOOPBACK)
got_errfd:
#endif
- LogDebug("%3d: Result code 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));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: could not set control socket to non-blocking mode errno %d (" PUB_S ")",
+ req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
req->ts = t_error;
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));
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+ "[R%u] ERROR: read_msg errno %d (" PUB_S ")", req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
req->ts = t_error;
}
{
// These are all operations that have their own first-class request_state object
case connection_request:
- LogOperation("%3d: DNSServiceCreateConnection START PID[%d](%s)",
- req->sd, req->process_id, req->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateConnection START PID[%d](" PUB_S ")",
+ req->request_id, req->process_id, req->pid_name);
req->terminate = connection_termination;
break;
case connection_delegate_request:
- LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
- req->sd, req->process_id, req->pid_name);
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PRI_S ")",
+ req->request_id, req->process_id, req->pid_name);
req->terminate = connection_termination;
handle_connection_delegate_request(req);
break;
case reconfirm_record_request: err = handle_reconfirm_request (req); break;
case setdomain_request: err = handle_setdomain_request (req); break;
case getproperty_request: handle_getproperty_request (req); break;
- case getpid_request: handle_getpid_request (req); break;
case port_mapping_request: err = handle_port_mapping_request(req); break;
case addrinfo_request: err = handle_addrinfo_request (req); break;
case send_bpf: /* Do nothing for send_bpf */ break;
// The lightweight operations are the ones that don't need a dedicated request_state structure allocated for them
#define LightweightOp(X) (RecordOrientedOp(X) || (X) == cancel_request)
-mDNSlocal void request_callback(int fd, short filter, void *info)
+mDNSlocal void request_callback(int fd, void *info)
{
mStatus err = 0;
request_state *req = info;
mDNSs32 min_size = sizeof(DNSServiceFlags);
(void)fd; // Unused
- (void)filter; // Unused
for (;;)
{
case reconfirm_record_request: min_size += sizeof(mDNSu32) + 1 /* name */ + 6 /* type, class, rdlen */; break;
case setdomain_request: min_size += 1 /* domain */; break;
case getproperty_request: min_size = 2; break;
- case getpid_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
newreq->msgbuf = req->msgbuf;
newreq->msgptr = req->msgptr;
newreq->msgend = req->msgend;
+ newreq->request_id = mDNSStorage.next_request_id++;
// if the parent request is a delegate connection, copy the
// relevant bits
if (req->validUUID)
send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
if (req->errsd != req->sd)
{
- LogDebug("%3d: Result code 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 subordinate operation
}
}
-mDNSlocal void connect_callback(int fd, short filter, void *info)
+mDNSlocal void connect_callback(int fd, void *info)
{
dnssd_sockaddr_t cliaddr;
dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
unsigned long optval = 1;
#endif
- (void)filter; // Unused
(void)info; // Unused
if (!dnssd_SocketValid(sd))
request->ts = t_morecoming;
request->sd = sd;
request->errsd = sd;
+ request->request_id = mDNSStorage.next_request_id++;
set_peer_pid(request);
#if APPLE_OSX_mDNSResponder
struct xucred x;
return mDNStrue;
}
+#if MDNS_MALLOC_DEBUGGING
+mDNSlocal void udsserver_validatelists(void *context);
+#endif
+
mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
{
dnssd_sockaddr_t laddr;
int ret;
mDNSu32 i = 0;
- LogInfo("udsserver_init: %d %d", _DNS_SD_H, mDNSStorage.mDNS_plat);
-
- // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
- if (PID_FILE[0])
+#ifndef NO_PID_FILE
+ FILE *fp = fopen(PID_FILE, "w");
+ if (fp != NULL)
{
- FILE *fp = fopen(PID_FILE, "w");
- if (fp != NULL)
- {
- fprintf(fp, "%d\n", getpid());
- fclose(fp);
- }
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
}
+#endif
+
+#if MDNS_MALLOC_DEBUGGING
+ static mDNSListValidator validator;
+ mDNSPlatformAddListValidator(&validator, udsserver_validatelists, "udsserver_validatelists", NULL);
+#endif
if (skts)
{
#endif
}
- if (PID_FILE[0]) unlink(PID_FILE);
+#ifndef NO_PID_FILE
+ unlink(PID_FILE);
+#endif
return 0;
}
-mDNSlocal void LogClientInfo(request_state *req)
+mDNSlocal void LogClientInfoToFD(int fd, request_state *req)
{
- char prefix[16];
- if (req->primary)
- mDNS_snprintf(prefix, sizeof(prefix), " -> ");
+ char reqIDStr[14];
+ char prefix[18];
+
+ mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
+
+ mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
+
+ if (!req->terminate)
+ LogToFD(fd, "%s No operation yet on this socket", prefix);
+ else if (req->terminate == connection_termination)
+ {
+ int num_records = 0, num_ops = 0;
+ const registered_record_entry *p;
+ request_state *r;
+ for (p = req->u.reg_recs; p; p=p->next) num_records++;
+ for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
+ LogToFD(fd, "%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
+ prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "",
+ req->process_id, req->pid_name);
+ for (p = req->u.reg_recs; p; p=p->next)
+ LogToFD(fd, " -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
+ req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+ for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfoToFD(fd, r);
+ }
+ else if (req->terminate == regservice_termination_callback)
+ {
+ service_instance *ptr;
+ for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
+ LogToFD(fd, "%-9s DNSServiceRegister 0x%08X %2d %##s %u/%u PID[%d](%s)",
+ (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
+ mDNSVal16(req->u.servicereg.port),
+ SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
+ }
+ else if (req->terminate == browse_termination_callback)
+ {
+ browser_t *blist;
+ for (blist = req->u.browser.browsers; blist; blist = blist->next)
+ LogToFD(fd, "%-9s DNSServiceBrowse 0x%08X %2d %##s PID[%d](%s)",
+ (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
+ req->process_id, req->pid_name);
+ }
+ else if (req->terminate == resolve_termination_callback)
+ LogToFD(fd, "%s DNSServiceResolve 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
+ else if (req->terminate == queryrecord_termination_callback)
+ LogToFD(fd, "%s DNSServiceQueryRecord 0x%08X %2d %##s (%s) PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
+ else if (req->terminate == enum_termination_callback)
+ LogToFD(fd, "%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
+ else if (req->terminate == port_mapping_termination_callback)
+ LogToFD(fd, "%s DNSServiceNATPortMapping 0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
+ prefix,
+ req->flags,
+ req->interfaceIndex,
+ req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
+ req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
+ mDNSVal16(req->u.pm.NATinfo.IntPort),
+ mDNSVal16(req->u.pm.ReqExt),
+ &req->u.pm.NATinfo.ExternalAddress,
+ mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+ req->u.pm.NATinfo.NATLease,
+ req->u.pm.NATinfo.Lifetime,
+ req->process_id, req->pid_name);
+ else if (req->terminate == addrinfo_termination_callback)
+ LogToFD(fd, "%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex,
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
else
- mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd);
+ LogToFD(fd, "%s Unrecognized operation %p", prefix, req->terminate);
+}
+
+mDNSlocal void LogClientInfo(request_state *req)
+{
+ char reqIDStr[14];
+ char prefix[18];
+
+ mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
+
+ mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
if (!req->terminate)
- LogMsgNoIdent("%s No operation yet on this socket", prefix);
+ LogMsgNoIdent("%s No operation yet on this socket", prefix);
else if (req->terminate == connection_termination)
{
int num_records = 0, num_ops = 0;
for (p = req->u.reg_recs; p; p=p->next) num_records++;
for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
- prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "",
- req->process_id, req->pid_name);
+ prefix, num_records, num_records != 1 ? "s" : "", num_ops, num_ops != 1 ? "s" : "",
+ req->process_id, req->pid_name);
for (p = req->u.reg_recs; p; p=p->next)
- LogMsgNoIdent(" -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
- req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+ LogMsgNoIdent(" -> DNSServiceRegisterRecord 0x%08X %2d %3d %s PID[%d](%s)",
+ req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(r);
}
else if (req->terminate == regservice_termination_callback)
{
service_instance *ptr;
- char anonstr[256];
for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
- LogMsgNoIdent("%s DNSServiceRegister 0x%08X %2d %##s%s %u/%u PID[%d](%s)",
- (ptr == req->u.servicereg.instances) ? prefix : " ", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
- AnonDataToString(ptr->srs.AnonData, 0, anonstr, sizeof(anonstr)), mDNSVal16(req->u.servicereg.port),
- SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
+ LogMsgNoIdent("%-9s DNSServiceRegister 0x%08X %2d %##s %u/%u PID[%d](%s)",
+ (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
+ mDNSVal16(req->u.servicereg.port),
+ SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
}
else if (req->terminate == browse_termination_callback)
{
browser_t *blist;
- char anonstr[256];
for (blist = req->u.browser.browsers; blist; blist = blist->next)
- LogMsgNoIdent("%s DNSServiceBrowse 0x%08X %2d %##s%s PID[%d](%s)",
- (blist == req->u.browser.browsers) ? prefix : " ", req->flags, req->interfaceIndex, blist->q.qname.c,
- AnonDataToString(req->u.browser.AnonData, 0, anonstr, sizeof(anonstr)), req->process_id, req->pid_name);
+ LogMsgNoIdent("%-9s DNSServiceBrowse 0x%08X %2d %##s PID[%d](%s)",
+ (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
+ req->process_id, req->pid_name);
}
else if (req->terminate == resolve_termination_callback)
- LogMsgNoIdent("%s DNSServiceResolve 0x%08X %2d %##s PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceResolve 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
else if (req->terminate == queryrecord_termination_callback)
- LogMsgNoIdent("%s DNSServiceQueryRecord 0x%08X %2d %##s (%s) PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype), req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceQueryRecord 0x%08X %2d %##s (%s) PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
else if (req->terminate == enum_termination_callback)
- LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
else if (req->terminate == port_mapping_termination_callback)
- LogMsgNoIdent("%s DNSServiceNATPortMapping 0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
- prefix,
- req->flags,
- req->interfaceIndex,
- req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
- req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
- mDNSVal16(req->u.pm.NATinfo.IntPort),
- mDNSVal16(req->u.pm.ReqExt),
- &req->u.pm.NATinfo.ExternalAddress,
- mDNSVal16(req->u.pm.NATinfo.ExternalPort),
- req->u.pm.NATinfo.NATLease,
- req->u.pm.NATinfo.Lifetime,
- req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceNATPortMapping 0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
+ prefix,
+ req->flags,
+ req->interfaceIndex,
+ req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : " ",
+ req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : " ",
+ mDNSVal16(req->u.pm.NATinfo.IntPort),
+ mDNSVal16(req->u.pm.ReqExt),
+ &req->u.pm.NATinfo.ExternalAddress,
+ mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+ req->u.pm.NATinfo.NATLease,
+ req->u.pm.NATinfo.Lifetime,
+ req->process_id, req->pid_name);
else if (req->terminate == addrinfo_termination_callback)
- LogMsgNoIdent("%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)",
- prefix, req->flags, req->interfaceIndex,
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
- req->u.addrinfo.q4.qname.c, req->process_id, req->pid_name);
+ LogMsgNoIdent("%s DNSServiceGetAddrInfo 0x%08X %2d %s%s %##s PID[%d](%s)",
+ prefix, req->flags, req->interfaceIndex,
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
else
- LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
+ LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
}
mDNSlocal void GetMcastClients(request_state *req)
}
else if (req->terminate == queryrecord_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0))
+ if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
n_mquests++;
}
else if (req->terminate == addrinfo_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.addrinfo.q4.TargetQID)) && (req->u.addrinfo.q4.ThisQInterval > 0))
+ if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
n_mquests++;
}
else
}
else if (req->terminate == queryrecord_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0))
- LogMcastNoIdent("Q: DNSServiceQueryRecord %##s %s PID[%d](%s)", req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype),
+ if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
+ {
+ LogMcastNoIdent("Q: DNSServiceQueryRecord %##s %s PID[%d](%s)",
+ QueryRecordClientRequestGetQName(&req->u.queryrecord),
+ DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)),
req->process_id, req->pid_name, i_mcount++);
+ }
}
else if (req->terminate == addrinfo_termination_callback)
{
- if ((mDNSOpaque16IsZero(req->u.addrinfo.q4.TargetQID)) && (req->u.addrinfo.q4.ThisQInterval > 0))
+ if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
+ {
LogMcastNoIdent("Q: DNSServiceGetAddrInfo %s%s %##s PID[%d](%s)",
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : " ",
- req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : " ",
- req->u.addrinfo.q4.qname.c, req->process_id, req->pid_name, i_mcount++);
- }
- else
- {
- return;
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : " ",
+ req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : " ",
+ GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name, i_mcount++);
+ }
}
-
}
mDNSlocal char *RecordTypeName(mDNSu8 rtype)
}
}
-mDNSlocal int LogEtcHosts(mDNS *const m)
+mDNSlocal int LogEtcHostsToFD(int fd, mDNS *const m)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
for (ar = ag->members; ar; ar = ar->next)
{
if (ar->RecordCallback != FreeEtcHosts) continue;
- if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" State Interface"); }
+ if (showheader) { showheader = mDNSfalse; LogToFD(fd, " State Interface"); }
// Print a maximum of 50 records
if (count++ >= 50) { truncated = mDNStrue; continue; }
if (ar->ARType == AuthRecordLocalOnly)
{
if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
- LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
else
{
mDNSu32 scopeid = (mDNSu32)(uintptr_t)ar->resrec.InterfaceID;
- LogMsgNoIdent(" %s %u %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
+ LogToFD(fd, " %s %u %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
}
}
}
}
- if (showheader) LogMsgNoIdent("<None>");
- else if (truncated) LogMsgNoIdent("<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
+ if (showheader) LogToFD(fd, "<None>");
+ else if (truncated) LogToFD(fd, "<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
return count;
}
-mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
+mDNSlocal void LogLocalOnlyAuthRecordsToFD(int fd, mDNS *const m)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
for (ar = ag->members; ar; ar = ar->next)
{
if (ar->RecordCallback == FreeEtcHosts) continue;
- if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" State Interface"); }
+ if (showheader) { showheader = mDNSfalse; LogToFD(fd, " State Interface"); }
// Print a maximum of 400 records
if (ar->ARType == AuthRecordLocalOnly)
- LogMsgNoIdent(" %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
else if (ar->ARType == AuthRecordP2P)
{
if (ar->resrec.InterfaceID == mDNSInterface_BLE)
- LogMsgNoIdent(" %s BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
else
- LogMsgNoIdent(" %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+ LogToFD(fd, " %s PP %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
}
}
}
- if (showheader) LogMsgNoIdent("<None>");
-}
-
-mDNSlocal char *AnonInfoToString(AnonymousInfo *ai, char *anonstr, int anstrlen)
-{
- anonstr[0] = 0;
- if (ai && ai->AnonData)
- {
- return (AnonDataToString(ai->AnonData, ai->AnonDataLen, anonstr, anstrlen));
- }
- return anonstr;
+ if (showheader) LogToFD(fd, "<None>");
}
-mDNSlocal void LogOneAuthRecord(const AuthRecord *ar, mDNSs32 now, const char *const ifname)
+mDNSlocal void LogOneAuthRecordToFD(int fd, const AuthRecord *ar, mDNSs32 now, const char *ifname)
{
- char anstr[256];
if (AuthRecord_uDNS(ar))
{
- LogMsgNoIdent("%7d %7d %7d %-7s %4d %s %s",
- ar->ThisAPInterval / mDNSPlatformOneSecond,
- (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
- ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
- "-U-",
- ar->state,
- ar->AllowRemoteQuery ? "☠" : " ",
- ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, "%7d %7d %7d %-7s %4d %s %s",
+ ar->ThisAPInterval / mDNSPlatformOneSecond,
+ (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
+ ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
+ "-U-",
+ ar->state,
+ ar->AllowRemoteQuery ? "☠" : " ",
+ ARDisplayString(&mDNSStorage, ar));
}
else
{
- LogMsgNoIdent("%7d %7d %7d %-7s 0x%02X %s %s%s",
- ar->ThisAPInterval / mDNSPlatformOneSecond,
- ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
- ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
- ifname ? ifname : "ALL",
- ar->resrec.RecordType,
- ar->AllowRemoteQuery ? "☠" : " ",
- ARDisplayString(&mDNSStorage, ar), AnonInfoToString(ar->resrec.AnonInfo, anstr, sizeof(anstr)));
+ LogToFD(fd, "%7d %7d %7d %-7s 0x%02X %s %s",
+ ar->ThisAPInterval / mDNSPlatformOneSecond,
+ ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
+ ar->TimeExpire ? (ar->TimeExpire - now) / mDNSPlatformOneSecond : 0,
+ ifname ? ifname : "ALL",
+ ar->resrec.RecordType,
+ ar->AllowRemoteQuery ? "☠" : " ",
+ ARDisplayString(&mDNSStorage, ar));
}
}
-mDNSlocal void LogAuthRecords(const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
+mDNSlocal void LogAuthRecordsToFD(int fd,
+ const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
{
mDNSBool showheader = mDNStrue;
const AuthRecord *ar;
const char *const ifname = InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID);
if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
{
- if (showheader) { showheader = mDNSfalse; LogMsgNoIdent(" Int Next Expire if State"); }
+ if (showheader) { showheader = mDNSfalse; LogToFD(fd, " Int Next Expire if State"); }
if (proxy) (*proxy)++;
if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
{
owner = ar->WakeUp;
if (owner.password.l[0])
- LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
+ LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
- LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d", &owner.HMAC, &owner.IMAC, owner.seq);
+ LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a seq %d", &owner.HMAC, &owner.IMAC, owner.seq);
else
- LogMsgNoIdent("Proxying for %.6a seq %d", &owner.HMAC, owner.seq);
+ LogToFD(fd, "Proxying for %.6a seq %d", &owner.HMAC, owner.seq);
}
if (AuthRecord_uDNS(ar))
{
- LogOneAuthRecord(ar, now, ifname);
+ LogOneAuthRecordToFD(fd, ar, now, ifname);
}
else if (ar->ARType == AuthRecordLocalOnly)
{
- LogMsgNoIdent(" LO %s", ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, " LO %s", ARDisplayString(&mDNSStorage, ar));
}
else if (ar->ARType == AuthRecordP2P)
{
if (ar->resrec.InterfaceID == mDNSInterface_BLE)
- LogMsgNoIdent(" BLE %s", ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, " BLE %s", ARDisplayString(&mDNSStorage, ar));
else
- LogMsgNoIdent(" PP %s", ARDisplayString(&mDNSStorage, ar));
+ LogToFD(fd, " PP %s", ARDisplayString(&mDNSStorage, ar));
}
else
{
- LogOneAuthRecord(ar, now, ifname);
- if (ar->resrec.AnonInfo)
- {
- ResourceRecord *nsec3 = ar->resrec.AnonInfo->nsec3RR;
- // We just print the values from the AuthRecord to keep it nicely aligned though
- // all we want here is the nsec3 information.
- 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,
- ifname ? ifname : "ALL",
- RRDisplayString(&mDNSStorage, nsec3));
- }
+ LogOneAuthRecordToFD(fd, ar, now, ifname);
}
}
}
- if (showheader) LogMsgNoIdent("<None>");
+ if (showheader) LogToFD(fd, "<None>");
}
-mDNSlocal void PrintOneCacheRecord(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintOneCacheRecordToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
{
- LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
- slot,
- cr->CRActiveQuestion ? "*" : " ",
- remain,
- ifname ? ifname : "-U-",
- (cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
- (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
- DNSTypeName(cr->resrec.rrtype),
- CRDisplayString(&mDNSStorage, cr));
+ LogToFD(fd, "%3d %s%8d %-7s%s %-6s%s",
+ slot,
+ cr->CRActiveQuestion ? "*" : " ",
+ remain,
+ ifname ? ifname : "-U-",
+ (cr->resrec.RecordType == kDNSRecordTypePacketNegative) ? "-" :
+ (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
+ DNSTypeName(cr->resrec.rrtype),
+ CRDisplayString(&mDNSStorage, cr));
(*CacheUsed)++;
}
-mDNSlocal void PrintCachedRecords(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintCachedRecordsToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
{
CacheRecord *nsec;
CacheRecord *soa;
// their own lifetime. If the main cache record expires, they also expire.
while (nsec)
{
- PrintOneCacheRecord(nsec, slot, remain, ifname, CacheUsed);
+ PrintOneCacheRecordToFD(fd, nsec, slot, remain, ifname, CacheUsed);
nsec = nsec->next;
}
soa = cr->soa;
if (soa)
{
- PrintOneCacheRecord(soa, slot, remain, ifname, CacheUsed);
+ PrintOneCacheRecordToFD(fd, soa, slot, remain, ifname, CacheUsed);
}
- if (cr->resrec.AnonInfo)
- {
- ResourceRecord *nsec3 = cr->resrec.AnonInfo->nsec3RR;
- // Even though it is a resource record, we print the sameway
- // as a cache record so that it aligns properly.
- if (nsec3)
- {
- LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
- slot,
- " ",
- remain,
- ifname ? ifname : "-U-",
- (nsec3->RecordType == kDNSRecordTypePacketNegative) ? "-" :
- (nsec3->RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
- DNSTypeName(nsec3->rrtype),
- RRDisplayString(&mDNSStorage, nsec3));
- }
- }
-}
-
-mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int adstrlen)
-{
- adstr[0] = 0;
- if (ad)
- {
- int len;
- char *orig = adstr;
-
- // If the caller is lazy to compute the length, we do it for them.
- if (!adlen)
- len = strlen((const char *)ad);
- else
- len = adlen;
-
- // Print the anondata within brackets. Hence, we need space for two
- // brackets and a NULL byte.
- if (len > (adstrlen - 3))
- len = adstrlen - 3;
-
- *adstr++ = '(';
- mDNSPlatformMemCopy(adstr, ad, len);
- adstr[len] = ')';
- adstr[len+1] = 0;
- return orig;
- }
- return adstr;
}
-mDNSexport void LogMDNSStatistics(mDNS *const m)
+mDNSexport void LogMDNSStatisticsToFD(int fd, mDNS *const m)
{
- LogMsgNoIdent("--- MDNS Statistics ---");
-
- LogMsgNoIdent("Name Conflicts %u", m->mDNSStats.NameConflicts);
- LogMsgNoIdent("KnownUnique Name Conflicts %u", m->mDNSStats.KnownUniqueNameConflicts);
- LogMsgNoIdent("Duplicate Query Suppressions %u", m->mDNSStats.DupQuerySuppressions);
- LogMsgNoIdent("KA Suppressions %u", m->mDNSStats.KnownAnswerSuppressions);
- LogMsgNoIdent("KA Multiple Packets %u", m->mDNSStats.KnownAnswerMultiplePkts);
- LogMsgNoIdent("Poof Cache Deletions %u", m->mDNSStats.PoofCacheDeletions);
- LogMsgNoIdent("--------------------------------");
-
- LogMsgNoIdent("Multicast packets Sent %u", m->MulticastPacketsSent);
- LogMsgNoIdent("Multicast packets Received %u", m->MPktNum);
- LogMsgNoIdent("Remote Subnet packets %u", m->RemoteSubnet);
- LogMsgNoIdent("QU questions received %u", m->mDNSStats.UnicastBitInQueries);
- LogMsgNoIdent("Normal multicast questions %u", m->mDNSStats.NormalQueries);
- LogMsgNoIdent("Answers for questions %u", m->mDNSStats.MatchingAnswersForQueries);
- LogMsgNoIdent("Unicast responses %u", m->mDNSStats.UnicastResponses);
- LogMsgNoIdent("Multicast responses %u", m->mDNSStats.MulticastResponses);
- LogMsgNoIdent("Unicast response Demotions %u", m->mDNSStats.UnicastDemotedToMulticast);
- LogMsgNoIdent("--------------------------------");
-
- LogMsgNoIdent("Sleeps %u", m->mDNSStats.Sleeps);
- LogMsgNoIdent("Wakeups %u", m->mDNSStats.Wakes);
- LogMsgNoIdent("Interface UP events %u", m->mDNSStats.InterfaceUp);
- LogMsgNoIdent("Interface UP Flap events %u", m->mDNSStats.InterfaceUpFlap);
- LogMsgNoIdent("Interface Down events %u", m->mDNSStats.InterfaceDown);
- LogMsgNoIdent("Interface DownFlap events %u", m->mDNSStats.InterfaceDownFlap);
- LogMsgNoIdent("Cache refresh queries %u", m->mDNSStats.CacheRefreshQueries);
- LogMsgNoIdent("Cache refreshed %u", m->mDNSStats.CacheRefreshed);
- LogMsgNoIdent("Wakeup on Resolves %u", m->mDNSStats.WakeOnResolves);
+ LogToFD(fd, "--- MDNS Statistics ---");
+
+ LogToFD(fd, "Name Conflicts %u", m->mDNSStats.NameConflicts);
+ LogToFD(fd, "KnownUnique Name Conflicts %u", m->mDNSStats.KnownUniqueNameConflicts);
+ LogToFD(fd, "Duplicate Query Suppressions %u", m->mDNSStats.DupQuerySuppressions);
+ LogToFD(fd, "KA Suppressions %u", m->mDNSStats.KnownAnswerSuppressions);
+ LogToFD(fd, "KA Multiple Packets %u", m->mDNSStats.KnownAnswerMultiplePkts);
+ LogToFD(fd, "Poof Cache Deletions %u", m->mDNSStats.PoofCacheDeletions);
+ LogToFD(fd, "--------------------------------");
+
+ LogToFD(fd, "Multicast packets Sent %u", m->MulticastPacketsSent);
+ LogToFD(fd, "Multicast packets Received %u", m->MPktNum);
+ LogToFD(fd, "Remote Subnet packets %u", m->RemoteSubnet);
+ LogToFD(fd, "QU questions received %u", m->mDNSStats.UnicastBitInQueries);
+ LogToFD(fd, "Normal multicast questions %u", m->mDNSStats.NormalQueries);
+ LogToFD(fd, "Answers for questions %u", m->mDNSStats.MatchingAnswersForQueries);
+ LogToFD(fd, "Unicast responses %u", m->mDNSStats.UnicastResponses);
+ LogToFD(fd, "Multicast responses %u", m->mDNSStats.MulticastResponses);
+ LogToFD(fd, "Unicast response Demotions %u", m->mDNSStats.UnicastDemotedToMulticast);
+ LogToFD(fd, "--------------------------------");
+
+ LogToFD(fd, "Sleeps %u", m->mDNSStats.Sleeps);
+ LogToFD(fd, "Wakeups %u", m->mDNSStats.Wakes);
+ LogToFD(fd, "Interface UP events %u", m->mDNSStats.InterfaceUp);
+ LogToFD(fd, "Interface UP Flap events %u", m->mDNSStats.InterfaceUpFlap);
+ LogToFD(fd, "Interface Down events %u", m->mDNSStats.InterfaceDown);
+ LogToFD(fd, "Interface DownFlap events %u", m->mDNSStats.InterfaceDownFlap);
+ LogToFD(fd, "Cache refresh queries %u", m->mDNSStats.CacheRefreshQueries);
+ LogToFD(fd, "Cache refreshed %u", m->mDNSStats.CacheRefreshed);
+ LogToFD(fd, "Wakeup on Resolves %u", m->mDNSStats.WakeOnResolves);
}
-mDNSexport void udsserver_info()
+mDNSexport void udsserver_info_dump_to_fd(int fd)
{
mDNS *const m = &mDNSStorage;
const mDNSs32 now = mDNS_TimeNow(m);
const DNameListElem *d;
const SearchListElem *s;
- LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
-
- LogMsgNoIdent("------------ Cache -------------");
- LogMsgNoIdent("Slt Q TTL if U Type rdlen");
+ LogToFD(fd, "------------ Cache -------------");
+ LogToFD(fd, "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)
const char *ifname;
mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
mDNSu32 *const countPtr = InterfaceID ? &mcastRecordCount : &ucastRecordCount;
- if (!InterfaceID && cr->resrec.rDNSServer && (cr->resrec.rDNSServer->scopeType != kScopeNone))
+ if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scopeType)
InterfaceID = cr->resrec.rDNSServer->interface;
ifname = InterfaceNameForID(m, InterfaceID);
if (cr->CRActiveQuestion) CacheActive++;
- PrintOneCacheRecord(cr, slot, remain, ifname, countPtr);
- PrintCachedRecords(cr, slot, remain, ifname, countPtr);
+ PrintOneCacheRecordToFD(fd, cr, slot, remain, ifname, countPtr);
+ PrintCachedRecordsToFD(fd, cr, slot, remain, ifname, countPtr);
}
}
}
CacheUsed = groupCount + mcastRecordCount + ucastRecordCount;
if (m->rrcache_totalused != CacheUsed)
- LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+ LogToFD(fd, "Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
if (m->rrcache_active != CacheActive)
- LogMsgNoIdent("Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
- LogMsgNoIdent("Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
- m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
+ LogToFD(fd, "Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+ LogToFD(fd, "Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
+ m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
- LogMsgNoIdent("--------- Auth Records ---------");
- LogAuthRecords(now, m->ResourceRecords, mDNSNULL);
+ LogToFD(fd, "--------- Auth Records ---------");
+ LogAuthRecordsToFD(fd, now, m->ResourceRecords, mDNSNULL);
- LogMsgNoIdent("--------- LocalOnly, P2P Auth Records ---------");
- LogLocalOnlyAuthRecords(m);
+ LogToFD(fd, "--------- LocalOnly, P2P Auth Records ---------");
+ LogLocalOnlyAuthRecordsToFD(fd, m);
- LogMsgNoIdent("--------- /etc/hosts ---------");
- LogEtcHosts(m);
+ LogToFD(fd, "--------- /etc/hosts ---------");
+ LogEtcHostsToFD(fd, m);
- LogMsgNoIdent("------ Duplicate Records -------");
- LogAuthRecords(now, m->DuplicateRecords, mDNSNULL);
+ LogToFD(fd, "------ Duplicate Records -------");
+ LogAuthRecordsToFD(fd, now, m->DuplicateRecords, mDNSNULL);
- LogMsgNoIdent("----- Auth Records Proxied -----");
- LogAuthRecords(now, m->ResourceRecords, &ProxyA);
+ LogToFD(fd, "----- Auth Records Proxied -----");
+ LogAuthRecordsToFD(fd, now, m->ResourceRecords, &ProxyA);
- LogMsgNoIdent("-- Duplicate Records Proxied ---");
- LogAuthRecords(now, m->DuplicateRecords, &ProxyD);
+ LogToFD(fd, "-- Duplicate Records Proxied ---");
+ LogAuthRecordsToFD(fd, now, m->DuplicateRecords, &ProxyD);
- LogMsgNoIdent("---------- Questions -----------");
- if (!m->Questions) LogMsgNoIdent("<None>");
+ LogToFD(fd, "---------- Questions -----------");
+ if (!m->Questions) LogToFD(fd, "<None>");
else
{
- char anonstr[256];
CacheUsed = 0;
CacheActive = 0;
- LogMsgNoIdent(" Int Next if T NumAns VDNS Qptr DupOf SU SQ Type Name");
+ LogToFD(fd, " Int Next if T NumAns VDNS Qptr DupOf SU SQ Type Name");
for (q = m->Questions; q; q=q->next)
{
mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
char *ifname = InterfaceNameForID(m, q->InterfaceID);
CacheUsed++;
if (q->ThisQInterval) CacheActive++;
- LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s%s",
- i, n,
- ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
- mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
- PrivateQuery(q) ? "P" : q->ValidationRequired ? "V" : q->ValidatingResponse ? "R" : " ",
- q->CurrentAnswers, q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1],
- q->validDNSServers.l[0], q, q->DuplicateOf,
- q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c,
- AnonInfoToString(q->AnonInfo, anonstr, sizeof(anonstr)),
- q->DuplicateOf ? " (dup)" : "");
- }
- LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
- }
-
- LogMsgNoIdent("----- LocalOnly, P2P Questions -----");
- if (!m->LocalOnlyQuestions) LogMsgNoIdent("<None>");
+ LogToFD(fd, "%6d%6d %-7s%s%s %5d 0x%08x%08x%08x%08x 0x%p 0x%p %1d %2d %-5s%##s%s",
+ i, n,
+ ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
+ mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
+ q->ValidationRequired ? "V" : q->ValidatingResponse ? "R" : " ",
+ q->CurrentAnswers,
+ q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0],
+ q, q->DuplicateOf,
+ q->SuppressUnusable, q->Suppressed, DNSTypeName(q->qtype), q->qname.c,
+ q->DuplicateOf ? " (dup)" : "");
+ }
+ LogToFD(fd, "%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
+ }
+
+ LogToFD(fd, "----- LocalOnly, P2P Questions -----");
+ if (!m->LocalOnlyQuestions) LogToFD(fd, "<None>");
else for (q = m->LocalOnlyQuestions; q; q=q->next)
- LogMsgNoIdent(" %3s %5d %-6s%##s%s",
- q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
- q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+ LogToFD(fd, " %3s %5d %-6s%##s%s",
+ q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
+ q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
- LogMsgNoIdent("---- Active UDS Client Requests ----");
- if (!all_requests) LogMsgNoIdent("<None>");
+ LogToFD(fd, "---- Active UDS Client Requests ----");
+ if (!all_requests) LogToFD(fd, "<None>");
else
{
request_state *req, *r;
if (req->primary) // If this is a subbordinate operation, check that the parent is in the list
{
for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
- LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
+ LogToFD(fd, "%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
}
// For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
- LogClientInfo(req);
-foundparent:;
+ LogClientInfoToFD(fd, req);
+ foundparent:;
}
}
-
- LogMsgNoIdent("-------- NAT Traversals --------");
- LogMsgNoIdent("ExtAddress %.4a Retry %d Interval %d",
- &m->ExtAddress,
- m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
- m->retryIntervalGetAddr / mDNSPlatformOneSecond);
+
+ LogToFD(fd, "-------- NAT Traversals --------");
+ LogToFD(fd, "ExtAddress %.4a Retry %d Interval %d",
+ &m->ExtAddress,
+ m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
+ m->retryIntervalGetAddr / mDNSPlatformOneSecond);
if (m->NATTraversals)
{
const NATTraversalInfo *nat;
for (nat = m->NATTraversals; nat; nat=nat->next)
{
- LogMsgNoIdent("%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
- nat,
- nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
- mDNSVal16(nat->IntPort),
- (nat->lastSuccessfulProtocol == NATTProtocolNone ? "None " :
- nat->lastSuccessfulProtocol == NATTProtocolNATPMP ? "NAT-PMP " :
- nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
- nat->lastSuccessfulProtocol == NATTProtocolPCP ? "PCP " :
- /* else */ "Unknown " ),
- nat->Result,
- nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
- nat->retryInterval / mDNSPlatformOneSecond,
- nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
- &nat->NewAddress, mDNSVal16(nat->RequestedPort),
- &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
- }
- }
-
- LogMsgNoIdent("--------- AuthInfoList ---------");
- if (!m->AuthInfoList) LogMsgNoIdent("<None>");
+ LogToFD(fd, "%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
+ nat,
+ nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
+ mDNSVal16(nat->IntPort),
+ (nat->lastSuccessfulProtocol == NATTProtocolNone ? "None " :
+ nat->lastSuccessfulProtocol == NATTProtocolNATPMP ? "NAT-PMP " :
+ nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
+ nat->lastSuccessfulProtocol == NATTProtocolPCP ? "PCP " :
+ /* else */ "Unknown " ),
+ nat->Result,
+ nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
+ nat->retryInterval / mDNSPlatformOneSecond,
+ nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
+ &nat->NewAddress, mDNSVal16(nat->RequestedPort),
+ &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
+ }
+ }
+
+ LogToFD(fd, "--------- AuthInfoList ---------");
+ if (!m->AuthInfoList) LogToFD(fd, "<None>");
else
{
const DomainAuthInfo *a;
for (a = m->AuthInfoList; a; a = a->next)
{
- LogMsgNoIdent("%##s %##s %##s %d %d %.16a%s",
- a->domain.c, a->keyname.c,
- a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
- (a->deltime ? (a->deltime - now) : 0),
- &a->AutoTunnelInnerAddress, a->AutoTunnel ? " AutoTunnel" : "");
+ LogToFD(fd, "%##s %##s %##s %d %d",
+ a->domain.c, a->keyname.c,
+ a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
+ (a->deltime ? (a->deltime - now) : 0));
}
}
- #if APPLE_OSX_mDNSResponder
- LogMsgNoIdent("--------- TunnelClients --------");
- if (!m->TunnelClients) LogMsgNoIdent("<None>");
- else
- {
- const ClientTunnel *c;
- for (c = m->TunnelClients; c; c = c->next)
- LogMsgNoIdent("%##s local %.16a %.4a %.16a remote %.16a %.4a %5d %.16a interval %d",
- c->dstname.c, &c->loc_inner, &c->loc_outer, &c->loc_outer6, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), &c->rmt_outer6, c->q.ThisQInterval);
- }
- #endif // APPLE_OSX_mDNSResponder
+ LogToFD(fd, "---------- Misc State ----------");
- LogMsgNoIdent("---------- Misc State ----------");
+ LogToFD(fd, "PrimaryMAC: %.6a", &m->PrimaryMAC);
- LogMsgNoIdent("PrimaryMAC: %.6a", &m->PrimaryMAC);
+ LogToFD(fd, "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);
- 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");
+ if (!m->SPSSocket) LogToFD(fd, "Not offering Sleep Proxy Service");
#ifndef SPC_DISABLED
- else LogMsgNoIdent("Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
+ else LogToFD(fd, "Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
#endif
- 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);
+ if (m->ProxyRecords == ProxyA + ProxyD) LogToFD(fd, "ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
+ else LogToFD(fd, "ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
- LogMsgNoIdent("------ Auto Browse Domains -----");
- if (!AutoBrowseDomains) LogMsgNoIdent("<None>");
- else for (d=AutoBrowseDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+ LogToFD(fd, "------ Auto Browse Domains -----");
+ if (!AutoBrowseDomains) LogToFD(fd, "<None>");
+ else for (d=AutoBrowseDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
- LogMsgNoIdent("--- Auto Registration Domains --");
- if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
- else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+ LogToFD(fd, "--- Auto Registration Domains --");
+ if (!AutoRegistrationDomains) LogToFD(fd, "<None>");
+ else for (d=AutoRegistrationDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
- LogMsgNoIdent("--- Search Domains --");
- if (!SearchList) LogMsgNoIdent("<None>");
+ LogToFD(fd, "--- Search Domains --");
+ if (!SearchList) LogToFD(fd, "<None>");
else
{
for (s=SearchList; s; s=s->next)
{
char *ifname = InterfaceNameForID(m, s->InterfaceID);
- LogMsgNoIdent("%##s %s", s->domain.c, ifname ? ifname : "");
+ LogToFD(fd, "%##s %s", s->domain.c, ifname ? ifname : "");
}
}
- LogInfo("--- Trust Anchors ---");
+ LogToFD(fd, "--- Trust Anchors ---");
if (!m->TrustAnchors)
{
- LogInfo("<None>");
+ LogToFD(fd, "<None>");
}
else
{
{
mDNSPlatformFormatTime((unsigned long)ta->validFrom, fromTimeBuf, sizeof(fromTimeBuf));
mDNSPlatformFormatTime((unsigned long)ta->validUntil, untilTimeBuf, sizeof(untilTimeBuf));
- LogInfo("%##s %d %d %d %d %s %s", ta->zone.c, ta->rds.keyTag,
- ta->rds.alg, ta->rds.digestType, ta->digestLen, fromTimeBuf, untilTimeBuf);
+ LogToFD(fd, "%##s %d %d %d %d %s %s", ta->zone.c, ta->rds.keyTag,
+ ta->rds.alg, ta->rds.digestType, ta->digestLen, fromTimeBuf, untilTimeBuf);
}
}
- LogInfo("--- DNSSEC Statistics ---");
+ LogToFD(fd, "--- DNSSEC Statistics ---");
- LogMsgNoIdent("Unicast Cache size %u", m->rrcache_totalused_unicast);
- LogInfo("DNSSEC Cache size %u", m->DNSSECStats.TotalMemUsed);
+ LogToFD(fd, "Unicast Cache size %u", m->rrcache_totalused_unicast);
+ LogToFD(fd, "DNSSEC Cache size %u", m->DNSSECStats.TotalMemUsed);
if (m->rrcache_totalused_unicast)
- LogInfo("DNSSEC usage percentage %u", ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
- LogInfo("DNSSEC Extra Packets (0 to 2) %u", m->DNSSECStats.ExtraPackets0);
- LogInfo("DNSSEC Extra Packets (3 to 6) %u", m->DNSSECStats.ExtraPackets3);
- LogInfo("DNSSEC Extra Packets (7 to 9) %u", m->DNSSECStats.ExtraPackets7);
- LogInfo("DNSSEC Extra Packets ( >= 10) %u", m->DNSSECStats.ExtraPackets10);
-
- LogInfo("DNSSEC Latency (0 to 4ms) %u", m->DNSSECStats.Latency0);
- LogInfo("DNSSEC Latency (4 to 9ms) %u", m->DNSSECStats.Latency5);
- LogInfo("DNSSEC Latency (10 to 19ms) %u", m->DNSSECStats.Latency10);
- LogInfo("DNSSEC Latency (20 to 49ms) %u", m->DNSSECStats.Latency20);
- LogInfo("DNSSEC Latency (50 to 99ms) %u", m->DNSSECStats.Latency50);
- LogInfo("DNSSEC Latency ( >=100ms) %u", m->DNSSECStats.Latency100);
-
- LogInfo("DNSSEC Secure Status %u", m->DNSSECStats.SecureStatus);
- LogInfo("DNSSEC Insecure Status %u", m->DNSSECStats.InsecureStatus);
- LogInfo("DNSSEC Indeterminate Status %u", m->DNSSECStats.IndeterminateStatus);
- LogInfo("DNSSEC Bogus Status %u", m->DNSSECStats.BogusStatus);
- LogInfo("DNSSEC NoResponse Status %u", m->DNSSECStats.NoResponseStatus);
- LogInfo("DNSSEC Probes sent %u", m->DNSSECStats.NumProbesSent);
- LogInfo("DNSSEC Msg Size (<=1024) %u", m->DNSSECStats.MsgSize0);
- LogInfo("DNSSEC Msg Size (<=2048) %u", m->DNSSECStats.MsgSize1);
- LogInfo("DNSSEC Msg Size (> 2048) %u", m->DNSSECStats.MsgSize2);
-
- LogMDNSStatistics(m);
-
- LogMsgNoIdent("---- Task Scheduling Timers ----");
-
-#if BONJOUR_ON_DEMAND
- LogMsgNoIdent("BonjourEnabled %d", m->BonjourEnabled);
-#endif // BONJOUR_ON_DEMAND
+ LogToFD(fd, "DNSSEC usage percentage %u", ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
+ LogToFD(fd, "DNSSEC Extra Packets (0 to 2) %u", m->DNSSECStats.ExtraPackets0);
+ LogToFD(fd, "DNSSEC Extra Packets (3 to 6) %u", m->DNSSECStats.ExtraPackets3);
+ LogToFD(fd, "DNSSEC Extra Packets (7 to 9) %u", m->DNSSECStats.ExtraPackets7);
+ LogToFD(fd, "DNSSEC Extra Packets ( >= 10) %u", m->DNSSECStats.ExtraPackets10);
+
+ LogToFD(fd, "DNSSEC Latency (0 to 4ms) %u", m->DNSSECStats.Latency0);
+ LogToFD(fd, "DNSSEC Latency (4 to 9ms) %u", m->DNSSECStats.Latency5);
+ LogToFD(fd, "DNSSEC Latency (10 to 19ms) %u", m->DNSSECStats.Latency10);
+ LogToFD(fd, "DNSSEC Latency (20 to 49ms) %u", m->DNSSECStats.Latency20);
+ LogToFD(fd, "DNSSEC Latency (50 to 99ms) %u", m->DNSSECStats.Latency50);
+ LogToFD(fd, "DNSSEC Latency ( >=100ms) %u", m->DNSSECStats.Latency100);
+
+ LogToFD(fd, "DNSSEC Secure Status %u", m->DNSSECStats.SecureStatus);
+ LogToFD(fd, "DNSSEC Insecure Status %u", m->DNSSECStats.InsecureStatus);
+ LogToFD(fd, "DNSSEC Indeterminate Status %u", m->DNSSECStats.IndeterminateStatus);
+ LogToFD(fd, "DNSSEC Bogus Status %u", m->DNSSECStats.BogusStatus);
+ LogToFD(fd, "DNSSEC NoResponse Status %u", m->DNSSECStats.NoResponseStatus);
+ LogToFD(fd, "DNSSEC Probes sent %u", m->DNSSECStats.NumProbesSent);
+ LogToFD(fd, "DNSSEC Msg Size (<=1024) %u", m->DNSSECStats.MsgSize0);
+ LogToFD(fd, "DNSSEC Msg Size (<=2048) %u", m->DNSSECStats.MsgSize1);
+ LogToFD(fd, "DNSSEC Msg Size (> 2048) %u", m->DNSSECStats.MsgSize2);
+
+ LogMDNSStatisticsToFD(fd, m);
+
+ LogToFD(fd, "---- Task Scheduling Timers ----");
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ LogToFD(fd, "BonjourEnabled %d", m->BonjourEnabled);
+#endif
#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
- LogMsgNoIdent("EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
- LogMsgNoIdent("DefaultToBLETriggered %d", DefaultToBLETriggered);
+ LogToFD(fd, "EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
+ LogToFD(fd, "DefaultToBLETriggered %d", DefaultToBLETriggered);
#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
if (!m->NewQuestions)
- LogMsgNoIdent("NewQuestion <NONE>");
+ LogToFD(fd, "NewQuestion <NONE>");
else
- LogMsgNoIdent("NewQuestion DelayAnswering %d %d %##s (%s)",
- m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
- m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+ LogToFD(fd, "NewQuestion DelayAnswering %d %d %##s (%s)",
+ m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
+ m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
if (!m->NewLocalOnlyQuestions)
- LogMsgNoIdent("NewLocalOnlyQuestions <NONE>");
+ LogToFD(fd, "NewLocalOnlyQuestions <NONE>");
else
- LogMsgNoIdent("NewLocalOnlyQuestions %##s (%s)",
- m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+ LogToFD(fd, "NewLocalOnlyQuestions %##s (%s)",
+ m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
if (!m->NewLocalRecords)
- LogMsgNoIdent("NewLocalRecords <NONE>");
+ LogToFD(fd, "NewLocalRecords <NONE>");
else
- LogMsgNoIdent("NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
-
- LogMsgNoIdent("SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
- LogMsgNoIdent("LocalRemoveEvents%s", m->LocalRemoveEvents ? "" : " <NONE>");
- LogMsgNoIdent("m->AutoTunnelRelayAddr %.16a", &m->AutoTunnelRelayAddr);
- LogMsgNoIdent("m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
- LogMsgNoIdent("m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
- LogMsgNoIdent("m->WABRegQueriesCount %d", m->WABRegQueriesCount);
- LogMsgNoIdent("m->AutoTargetServices %d", m->AutoTargetServices);
+ LogToFD(fd, "NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
+
+ LogToFD(fd, "SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
+ LogToFD(fd, "LocalRemoveEvents%s", m->LocalRemoveEvents ? "" : " <NONE>");
+ LogToFD(fd, "m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
+ LogToFD(fd, "m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
+ LogToFD(fd, "m->WABRegQueriesCount %d", m->WABRegQueriesCount);
+ LogToFD(fd, "m->AutoTargetServices %u", m->AutoTargetServices);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+ LogToFD(fd, "m->AutoTargetAWDLIncludedCount %u", m->AutoTargetAWDLIncludedCount);
+ LogToFD(fd, "m->AutoTargetAWDLOnlyCount %u", m->AutoTargetAWDLOnlyCount);
+#endif
- LogMsgNoIdent(" ABS (hex) ABS (dec) REL (hex) REL (dec)");
- LogMsgNoIdent("m->timenow %08X %11d", now, now);
- LogMsgNoIdent("m->timenow_adjust %08X %11d", m->timenow_adjust, m->timenow_adjust);
- LogTimer("m->NextScheduledEvent ", m->NextScheduledEvent);
+ LogToFD(fd, " ABS (hex) ABS (dec) REL (hex) REL (dec)");
+ LogToFD(fd, "m->timenow %08X %11d", now, now);
+ LogToFD(fd, "m->timenow_adjust %08X %11d", m->timenow_adjust, m->timenow_adjust);
+ LogTimerToFD(fd, "m->NextScheduledEvent ", m->NextScheduledEvent);
#ifndef UNICAST_DISABLED
- LogTimer("m->NextuDNSEvent ", m->NextuDNSEvent);
- LogTimer("m->NextSRVUpdate ", m->NextSRVUpdate);
- LogTimer("m->NextScheduledNATOp ", m->NextScheduledNATOp);
- LogTimer("m->retryGetAddr ", m->retryGetAddr);
+ LogTimerToFD(fd, "m->NextuDNSEvent ", m->NextuDNSEvent);
+ LogTimerToFD(fd, "m->NextSRVUpdate ", m->NextSRVUpdate);
+ LogTimerToFD(fd, "m->NextScheduledNATOp ", m->NextScheduledNATOp);
+ LogTimerToFD(fd, "m->retryGetAddr ", m->retryGetAddr);
#endif
- LogTimer("m->NextCacheCheck ", m->NextCacheCheck);
- LogTimer("m->NextScheduledSPS ", m->NextScheduledSPS);
- LogTimer("m->NextScheduledKA ", m->NextScheduledKA);
+ LogTimerToFD(fd, "m->NextCacheCheck ", m->NextCacheCheck);
+ LogTimerToFD(fd, "m->NextScheduledSPS ", m->NextScheduledSPS);
+ LogTimerToFD(fd, "m->NextScheduledKA ", m->NextScheduledKA);
-#if BONJOUR_ON_DEMAND
- LogTimer("m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
-#endif // BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+ LogTimerToFD(fd, "m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
+#endif
- LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
- LogTimer("m->DelaySleep ", m->DelaySleep);
+ LogTimerToFD(fd, "m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
+ LogTimerToFD(fd, "m->DelaySleep ", m->DelaySleep);
- LogTimer("m->NextScheduledQuery ", m->NextScheduledQuery);
- LogTimer("m->NextScheduledProbe ", m->NextScheduledProbe);
- LogTimer("m->NextScheduledResponse", m->NextScheduledResponse);
+ LogTimerToFD(fd, "m->NextScheduledQuery ", m->NextScheduledQuery);
+ LogTimerToFD(fd, "m->NextScheduledProbe ", m->NextScheduledProbe);
+ LogTimerToFD(fd, "m->NextScheduledResponse", m->NextScheduledResponse);
- LogTimer("m->SuppressSending ", m->SuppressSending);
- LogTimer("m->SuppressProbes ", m->SuppressProbes);
- LogTimer("m->ProbeFailTime ", m->ProbeFailTime);
- LogTimer("m->DelaySleep ", m->DelaySleep);
- LogTimer("m->SleepLimit ", m->SleepLimit);
- LogTimer("m->NextScheduledStopTime ", m->NextScheduledStopTime);
+ LogTimerToFD(fd, "m->SuppressSending ", m->SuppressSending);
+ LogTimerToFD(fd, "m->SuppressProbes ", m->SuppressProbes);
+ LogTimerToFD(fd, "m->ProbeFailTime ", m->ProbeFailTime);
+ LogTimerToFD(fd, "m->DelaySleep ", m->DelaySleep);
+ LogTimerToFD(fd, "m->SleepLimit ", m->SleepLimit);
+ LogTimerToFD(fd, "m->NextScheduledStopTime ", m->NextScheduledStopTime);
}
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-mDNSexport void uds_validatelists(void)
+#if MDNS_MALLOC_DEBUGGING
+mDNSlocal void udsserver_validatelists(void *context)
{
const request_state *req, *p;
+ (void)context; // unused
for (req = all_requests; req; req=req->next)
{
if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
}
-#endif // APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+#endif // MDNS_MALLOC_DEBUGGING
mDNSlocal int send_msg(request_state *const req)
{
if (nextevent - now > mDNSPlatformOneSecond)
nextevent = now + mDNSPlatformOneSecond;
+ LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+ "[R%u] Could not send all replies. Will try again in %d ticks.", r->request_id, nextevent - now);
if (mDNSStorage.SleepState != SleepState_Awake)
r->time_blocked = 0;
else if (!r->time_blocked)
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2018 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.
#include "mDNSEmbeddedAPI.h"
#include "dnssd_ipc.h"
+#include "ClientRequests.h"
/* Client request: */
mDNSBool validUUID;
dnssd_sock_t errsd;
mDNSu32 uid;
+ mDNSu32 request_id;
void * platform_data;
// Note: On a shared connection these fields in the primary structure, including hdr, are re-used
mDNSBool ForceMCast;
domainname regtype;
browser_t *browsers;
- const mDNSu8 *AnonData;
} browser;
struct
{
mDNSBool autorename; // Set if this client wants us to automatically rename on conflict
mDNSBool allowremotequery; // Respond to unicast queries from outside the local link?
int num_subtypes;
- mDNSBool AnonData;
service_instance *instances;
} servicereg;
struct
- {
- mDNSInterfaceID interface_id;
- mDNSu32 flags;
- mDNSu32 protocol;
- DNSQuestion q4;
- DNSQuestion *q42;
- DNSQuestion q6;
- DNSQuestion *q62;
- mDNSu8 v4ans;
- mDNSu8 v6ans;
- } addrinfo;
- struct
{
mDNSIPPort ReqExt; // External port we originally requested, for logging purposes
NATTraversalInfo NATinfo;
DNSQuestion q_autoall;
} enumeration;
struct
- {
- DNSQuestion q;
- DNSQuestion *q2;
- mDNSu8 ans;
- } queryrecord;
- struct
{
DNSQuestion qtxt;
DNSQuestion qsrv;
mDNSs32 ReportTime;
mDNSBool external_advertise;
} resolve;
+ GetAddrInfoClientRequest addrinfo;
+ QueryRecordClientRequest queryrecord;
} u;
};
#define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
-#define LogTimer(MSG,T) LogMsgNoIdent( MSG " %08X %11d %08X %11d", (T), (T), (T)-now, (T)-now)
+#define LogTimerToFD(FILE_DESCRIPTOR, MSG, T) LogToFD((FILE_DESCRIPTOR), MSG " %08X %11d %08X %11d", (T), (T), (T)-now, (T)-now)
extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count);
extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
-extern void udsserver_info(void); // print out info about current state
+extern void udsserver_info_dump_to_fd(int fd);
extern void udsserver_handle_configchange(mDNS *const m);
extern int udsserver_exit(void); // should be called prior to app exit
extern void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog);
/* Routines that uds_daemon expects to link against: */
-typedef void (*udsEventCallback)(int fd, short filter, void *context);
+typedef void (*udsEventCallback)(int fd, void *context);
extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context, void **platform_data);
extern int udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data);
extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well
extern DNameListElem *AutoRegistrationDomains;
extern DNameListElem *AutoBrowseDomains;
-extern mDNSs32 ChopSubTypes(char *regtype, char **AnonData);
-extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData);
extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
-extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags);
extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
extern int CountPeerRegistrations(ServiceRecordSet *const srs);
-#if APPLE_OSX_mDNSResponder
-
-// D2D interface support
-extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
-extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
-extern void external_connection_release(const domainname *instance);
-
-#else // APPLE_OSX_mDNSResponder
-
-#define external_start_browsing_for_service(A,B,C,D) (void)(A)
-#define external_stop_browsing_for_service(A,B,C,D) (void)(A)
-#define external_start_advertising_service(A,B) (void)(A)
-#define external_stop_advertising_service(A,B) do { (void)(A); (void)(B); } while (0)
-#define external_start_resolving_service(A,B,C) (void)(A)
-#define external_stop_resolving_service(A,B,C) (void)(A)
-#define external_connection_release(A) (void)(A)
-
-#endif // APPLE_OSX_mDNSResponder
-
extern const char mDNSResponderVersionString_SCCS[];
#define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5)
+++ /dev/null
-These are the platform support files for running mDNSCore on VxWorks.
-
-Please note, most of the developers working on the mDNSResponder code do
-not have access to a VxWorks development environment, so they are not able
-to personally verify that the VxWorks compiles and runs successfully after
-every single change to the mDNSCore code. We do try to take care not to
-make careless changes that would break the VxWorks build, but if you do
-find that something is broken, let us know and we'll fix it.
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2005 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.
- */
-
-#if 0
-#pragma mark == Configuration ==
-#endif
-
-//===========================================================================================================================
-// Configuration
-//===========================================================================================================================
-
-#define DEBUG_NAME "[mDNS] "
-#define MDNS_AAAA_OVER_IPV4 1 // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
-#define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 1 // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
-#define MDNS_ENABLE_PPP 0 // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
-#define MDNS_DEBUG_PACKETS 1 // 1=Enable debug output for packet send/recv if debug level high enough.
-#define MDNS_DEBUG_SHOW 1 // 1=Enable console show routines.
-#define DEBUG_USE_DEFAULT_CATEGORY 1 // Set up to use the default category (see DebugServices.h for details).
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include "vxWorks.h"
-#include "config.h"
-
-#include <sys/types.h>
-
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/ifaddrs.h>
-#include <netinet6/in6_var.h>
-#include <netinet/if_ether.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include "ifLib.h"
-#include "inetLib.h"
-#include "pipeDrv.h"
-#include "selectLib.h"
-#include "semLib.h"
-#include "sockLib.h"
-#include "sysLib.h"
-#include "taskLib.h"
-#include "tickLib.h"
-
-#include "CommonServices.h"
-#include "DebugServices.h"
-#include "DNSCommon.h"
-#include "mDNSEmbeddedAPI.h"
-
-#include "mDNSVxWorks.h"
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-typedef uint8_t MDNSPipeCommandCode;
-
-#define kMDNSPipeCommandCodeInvalid 0
-#define kMDNSPipeCommandCodeReschedule 1
-#define kMDNSPipeCommandCodeReconfigure 2
-#define kMDNSPipeCommandCodeQuit 3
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-#if ( DEBUG )
-mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... );
-
- #define dmsg( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
-#else
- #define dmsg( LEVEL, ARGS... )
-#endif
-
-#if ( DEBUG && MDNS_DEBUG_PACKETS )
- #define dpkt( LEVEL, ARGS... ) DebugMsg( LEVEL, ## ARGS )
-#else
- #define dpkt( LEVEL, ARGS... )
-#endif
-
-#define ForgetSem( X ) do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
-#define ForgetSocket( X ) do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
-
-// Interfaces
-
-mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC );
-mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC );
-mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC );
-mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC );
-mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing );
-mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID );
-mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex );
-mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS );
-mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP );
-
-// Commands
-
-mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
-mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS );
-
-// Threads
-
-mDNSlocal void Task( mDNS *inMDNS );
-mDNSlocal mStatus TaskInit( mDNS *inMDNS );
-mDNSlocal void TaskTerm( mDNS *inMDNS );
-mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout );
-mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock );
-mDNSlocal ssize_t
-mDNSRecvMsg(
- SocketRef inSock,
- void * inBuffer,
- size_t inBufferSize,
- void * outFrom,
- size_t inFromSize,
- size_t * outFromSize,
- mDNSAddr * outDstAddr,
- uint32_t * outIndex );
-
-// DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
-struct mDNSPlatformInterfaceInfo
-{
- const char * name;
- mDNSAddr ip;
-};
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
-
-#ifdef __cplusplus
-}
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-debug_log_new_default_category( mdns );
-
-mDNSexport mDNSs32 mDNSPlatformOneSecond;
-mDNSlocal mDNSs32 gMDNSTicksToMicro = 0;
-mDNSlocal mDNS * gMDNSPtr = NULL;
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSlocal mDNSBool gMDNSDeferIPv4 = mDNSfalse;
-#if ( DEBUG )
-DebugLevel gMDNSDebugOverrideLevel = kDebugLevelMax;
-#endif
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// mDNSReconfigure
-//===========================================================================================================================
-
-void mDNSReconfigure( void )
-{
- if( gMDNSPtr ) SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure );
-}
-
-//===========================================================================================================================
-// mDNSDeferIPv4
-//===========================================================================================================================
-
-void mDNSDeferIPv4( mDNSBool inDefer )
-{
- gMDNSDeferIPv4 = inDefer;
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// mDNSPlatformInit
-//===========================================================================================================================
-
-mStatus mDNSPlatformInit( mDNS * const inMDNS )
-{
- mStatus err;
- int id;
-
- mDNSPlatformOneSecond = sysClkRateGet();
- gMDNSTicksToMicro = ( 1000000L / mDNSPlatformOneSecond );
-
- // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
-
- mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
- if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
- inMDNS->p->unicastSS.info = NULL;
- inMDNS->p->unicastSS.sockV4 = kInvalidSocketRef;
- inMDNS->p->unicastSS.sockV6 = kInvalidSocketRef;
- inMDNS->p->initErr = mStatus_NotInitializedErr;
- inMDNS->p->commandPipe = ERROR;
- inMDNS->p->taskID = ERROR;
-
- inMDNS->p->lock = semMCreate( SEM_Q_FIFO );
- require_action( inMDNS->p->lock, exit, err = mStatus_NoMemoryErr );
-
- inMDNS->p->initEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
- require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr );
-
- inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
- require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
-
- // Start the task and wait for it to initialize. The task does the full initialization from its own context
- // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers).
- // We wait here until the init is complete because it needs to be ready to use as soon as this function returns.
-
- id = taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR) Task, (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
- err = translate_errno( id != ERROR, errno_compat(), mStatus_NoMemoryErr );
- require_noerr( err, exit );
-
- err = semTake( inMDNS->p->initEvent, WAIT_FOREVER );
- if( err == OK ) err = inMDNS->p->initErr;
- require_noerr( err, exit );
-
- gMDNSPtr = inMDNS;
- mDNSCoreInitComplete( inMDNS, err );
-
-exit:
- if( err ) mDNSPlatformClose( inMDNS );
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformClose
-//===========================================================================================================================
-
-void mDNSPlatformClose( mDNS * const inMDNS )
-{
- mStatus err;
-
- check( inMDNS );
-
- gMDNSPtr = NULL;
-
- // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread.
-
- if( inMDNS->p->taskID != ERROR )
- {
- SendCommand( inMDNS, kMDNSPipeCommandCodeQuit );
- if( inMDNS->p->quitEvent )
- {
- err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 );
- check_noerr( err );
- }
- inMDNS->p->taskID = ERROR;
- }
-
- // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
-
- ForgetSem( &inMDNS->p->quitEvent );
- ForgetSem( &inMDNS->p->initEvent );
- ForgetSem( &inMDNS->p->lock );
-
- dmsg( kDebugLevelNotice, DEBUG_NAME "CLOSED\n" );
-}
-
-//===========================================================================================================================
-// mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformSendUDP(
- const mDNS * const inMDNS,
- const void * const inMsg,
- const mDNSu8 * const inEnd,
- mDNSInterfaceID inInterfaceID,
- const mDNSAddr * inDstIP,
- mDNSIPPort inDstPort )
-{
- mStatus err;
- NetworkInterfaceInfoVxWorks * info;
- SocketRef sock;
- struct sockaddr_storage to;
- int n;
-
- // Set up the sockaddr to sent to and the socket to send on.
-
- info = (NetworkInterfaceInfoVxWorks *) inInterfaceID;
- if( inDstIP->type == mDNSAddrType_IPv4 )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) &to;
- sa4->sin_len = sizeof( *sa4 );
- sa4->sin_family = AF_INET;
- sa4->sin_port = inDstPort.NotAnInteger;
- sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
- sock = info ? info->ss.sockV4 : inMDNS->p->unicastSS.sockV4;
- }
- else if( inDstIP->type == mDNSAddrType_IPv6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) &to;
- sa6->sin6_len = sizeof( *sa6 );
- 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 = info ? info->scopeID : 0;
- sock = info ? info->ss.sockV6 : inMDNS->p->unicastSS.sockV6;
- }
- else
- {
- dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__ );
- err = mStatus_BadParamErr;
- goto exit;
- }
-
- // Send the packet if we've got a valid socket of this type. Note: mDNSCore may ask us to send an IPv4 packet and then
- // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error.
-
- n = (int)( (mDNSu8 *) inEnd - (mDNSu8 *) inMsg );
- if( !IsValidSocket( sock ) )
- {
- dpkt( kDebugLevelChatty - 1,
- DEBUG_NAME "DROP: %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
- n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info );
- err = mStatus_Invalid;
- goto exit;
- }
-
- dpkt( kDebugLevelChatty,
- DEBUG_NAME "SEND %4d bytes, DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
- n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info );
-
- n = sendto( sock, (mDNSu8 *) inMsg, n, 0, (struct sockaddr *) &to, to.ss_len );
- if( n < 0 )
- {
- // Don't warn about ARP failures or no route to host for unicast destinations.
-
- err = errno_compat();
- if( ( ( err == EHOSTDOWN ) || ( err == ENETDOWN ) || ( err == EHOSTUNREACH ) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP ) )
- {
- goto exit;
- }
-
- dmsg( kDebugLevelError, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
- __ROUTINE__, info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, inDstIP, mDNSVal16( inDstPort ),
- sock, err, (unsigned int) inMDNS->timenow );
- if( err == 0 ) err = mStatus_UnknownErr;
- goto exit;
- }
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// Connection-oriented (TCP) functions
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context, int *descriptor)
-{
- (void)dst; // Unused
- (void)dstport; // Unused
- (void)InterfaceID; // Unused
- (void)callback; // Unused
- (void)context; // Unused
- (void)descriptor; // Unused
- return(mStatus_UnsupportedErr);
-}
-
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
-{
- (void)sd; // Unused
-}
-
-mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
-{
- (void)sd; // Unused
- (void)buf; // Unused
- (void)buflen; // Unused
- return(0);
-}
-
-mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
-{
- (void)sd; // Unused
- (void)msg; // Unused
- (void)len; // Unused
- return(0);
-}
-
-//===========================================================================================================================
-// mDNSPlatformLock
-//===========================================================================================================================
-
-void mDNSPlatformLock( const mDNS * const inMDNS )
-{
- check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
-
-#if ( DEBUG )
- if( semTake( inMDNS->p->lock, 60 * sysClkRateGet() ) != OK )
- {
- dmsg( kDebugLevelTragic, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS->p->lock, taskIdSelf() );
- debug_stack_trace(); // 1) Print Stack Trace.
- semShow( inMDNS->p->lock, 1 ); // 2) Print semaphore info, including which tasks are pending on it.
- taskSuspend( 0 ); // 3) Suspend task. Can be resumed from the console for debugging.
- }
-#else
- semTake( inMDNS->p->lock, WAIT_FOREVER );
-#endif
-}
-
-//===========================================================================================================================
-// mDNSPlatformUnlock
-//===========================================================================================================================
-
-void mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
- check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
-
- // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time.
- // We only need to wake up if we're not already inside the task. This avoids filling up the command queue.
-
- if( taskIdSelf() != inMDNS->p->taskID )
- {
- SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule );
- }
- semGive( inMDNS->p->lock );
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSu32 mDNSPlatformStrLen( const void *inSrc )
-{
- check( inSrc );
-
- return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrCopy
-//===========================================================================================================================
-
-void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
- check( inSrc );
- check( inDst );
-
- strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemCopy
-//===========================================================================================================================
-
-void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- return( memcmp( inSrc, inDst, inSize ) == 0 );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemZero
-//===========================================================================================================================
-
-void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
- check( inDst );
-
- memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
- void * mem;
-
- check( inSize > 0 );
-
- mem = malloc( inSize );
- check( mem );
-
- return( mem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemFree( void *inMem )
-{
- check( inMem );
- if( inMem ) free( inMem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRandomSeed
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformRandomSeed( void )
-{
- return( tickGet() );
-}
-
-//===========================================================================================================================
-// mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTimeInit( void )
-{
- // No special setup is required on VxWorks -- we just use tickGet().
-
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSs32 mDNSPlatformRawTime( void )
-{
- return( (mDNSs32) tickGet() );
-}
-
-//===========================================================================================================================
-// mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32 mDNSPlatformUTC( void )
-{
- return( (mDNSs32) time( NULL ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDfromInterfaceIndex
-//===========================================================================================================================
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex )
-{
- NetworkInterfaceInfoVxWorks * i;
-
- if( inIndex == (mDNSu32) -1 ) return( mDNSInterface_LocalOnly );
- if( inIndex != 0 )
- {
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- // Don't get tricked by inactive interfaces with no InterfaceID set.
-
- if( i->ifinfo.InterfaceID && ( i->scopeID == inIndex ) ) return( i->ifinfo.InterfaceID );
- }
- }
- return( NULL );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIndexfromInterfaceID
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID )
-{
- NetworkInterfaceInfoVxWorks * i;
-
- if( inID == mDNSInterface_LocalOnly ) return( (mDNSu32) -1 );
- if( inID )
- {
- // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
-
- for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
- if( i ) return( i->scopeID );
- }
- return( 0 );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
- NetworkInterfaceInfoVxWorks * i;
-
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- // Don't get tricked by inactive interfaces with no InterfaceID set.
-
- if( i->ifinfo.InterfaceID && ( strcmp( i->ifinfo.ifname, inName ) == 0 ) )
- {
- *outID = (mDNSInterfaceID) i;
- return( mStatus_NoError );
- }
- }
- return( mStatus_NoSuchNameErr );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
- NetworkInterfaceInfoVxWorks * i;
-
- // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
-
- for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
- if( !i ) return( mStatus_NoSuchNameErr );
-
- outInfo->name = i->ifinfo.ifname;
- outInfo->ip = i->ifinfo.ip;
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// debugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS > 0 )
-mDNSexport void debugf_( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
-
- va_start( args, inFormat );
- mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-// verbosedebugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS > 1 )
-mDNSexport void verbosedebugf_( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
-
- va_start( args, inFormat );
- mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-// LogMsg
-//===========================================================================================================================
-
-mDNSexport void LogMsg( const char *inFormat, ... )
-{
-#if ( DEBUG )
- char buffer[ 512 ];
- va_list args;
-
- va_start( args, inFormat );
- mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelWarning, "%s\n", buffer );
-#else
- DEBUG_UNUSED( inFormat );
-#endif
-}
-
-#if ( DEBUG )
-//===========================================================================================================================
-// DebugMsg
-//===========================================================================================================================
-
-mDNSlocal void DebugMsg( DebugLevel inLevel, const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
-
- va_start( args, inFormat );
- mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- if( inLevel >= gMDNSDebugOverrideLevel ) inLevel = kDebugLevelMax;
- dlog( inLevel, "%s", buffer );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Interfaces ==
-#endif
-
-//===========================================================================================================================
-// UpdateInterfaceList
-//===========================================================================================================================
-
-#if ( MDNS_ENABLE_PPP )
-
-// Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
-
- #define IsCompatibleInterface( IFA ) \
- ( ( ( IFA )->ifa_flags & IFF_UP ) && \
- ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
- ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) && \
- ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
-#else
- #define IsCompatibleInterface( IFA ) \
- ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) ) && \
- ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) ) && \
- ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) )
-#endif
-
-#define IsLinkLocalSockAddr( SA ) \
- ( ( ( (const struct sockaddr *)( SA ) )->sa_family == AF_INET ) \
- ? ( ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 0 ] == 169 ) && \
- ( ( (uint8_t *)( &( (const struct sockaddr_in *)( SA ) )->sin_addr ) )[ 1 ] == 254 ) ) \
- : IN6_IS_ADDR_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
-
-#define FamilyToString( X ) \
- ( ( ( X ) == AF_INET ) ? "AF_INET" : \
- ( ( ( X ) == AF_INET6 ) ? "AF_INET6" : \
- ( ( ( X ) == AF_LINK ) ? "AF_LINK" : \
- "UNKNOWN" ) ) )
-
-mDNSlocal mStatus UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC )
-{
- mStatus err;
- struct ifaddrs * ifaList;
- struct ifaddrs * ifa;
- int family;
- mDNSBool foundV4;
- mDNSBool foundV6;
- struct ifaddrs * loopbackV4;
- struct ifaddrs * loopbackV6;
- mDNSEthAddr primaryMAC;
- SocketRef infoSock;
- char defaultName[ 64 ];
- NetworkInterfaceInfoVxWorks * i;
- domainlabel nicelabel;
- domainlabel hostlabel;
- domainlabel tmp;
-
- ifaList = NULL;
- foundV4 = mDNSfalse;
- foundV6 = mDNSfalse;
- loopbackV4 = NULL;
- loopbackV6 = NULL;
- primaryMAC = zeroEthAddr;
-
- // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
-
- infoSock = socket( AF_INET6, SOCK_DGRAM, 0 );
- check_translated_errno( IsValidSocket( infoSock ), errno_compat(), kUnknownErr );
-
- // Run through the entire list of interfaces.
-
- err = getifaddrs( &ifaList );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
- for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
- {
- int flags;
-
- family = ifa->ifa_addr->sa_family;
- dmsg( kDebugLevelVerbose, DEBUG_NAME "%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__,
- ifa->ifa_name, if_nametoindex( ifa->ifa_name ), ifa->ifa_flags, FamilyToString( family ), family );
-
- // Save off the MAC address of the first Ethernet-ish interface.
-
- if( family == AF_LINK )
- {
- struct sockaddr_dl * sdl;
-
- sdl = (struct sockaddr_dl *) ifa->ifa_addr;
- if( ( sdl->sdl_type == IFT_ETHER ) && ( sdl->sdl_alen == sizeof( primaryMAC ) &&
- mDNSSameEthAddress( &primaryMAC, &zeroEthAddr ) ) )
- {
- memcpy( primaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6 );
- }
- }
-
- if( !IsCompatibleInterface( ifa ) ) continue;
-
- // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
-
- if( IsLinkLocalSockAddr( ifa->ifa_addr ) )
- {
- struct ifaddrs * ifaLL;
-
- for( ifaLL = ifaList; ifaLL; ifaLL = ifaLL->ifa_next )
- {
- if( ifaLL->ifa_addr->sa_family != family ) continue;
- if( !IsCompatibleInterface( ifaLL ) ) continue;
- if( strcmp( ifaLL->ifa_name, ifa->ifa_name ) != 0 ) continue;
- if( !IsLinkLocalSockAddr( ifaLL->ifa_addr ) ) break;
- }
- if( ifaLL )
- {
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %8s(%d) skipping link-local alias\n", __ROUTINE__,
- ifa->ifa_name, if_nametoindex( ifa->ifa_name ) );
- continue;
- }
- }
-
- // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use.
- // If this is a loopback interface, save it off since we may add it later if there are no other interfaces.
- // Otherwise, add the interface to the list.
-
- flags = 0;
- if( ( family == AF_INET6 ) && IsValidSocket( infoSock ) )
- {
- struct sockaddr_in6 * sa6;
- struct in6_ifreq ifr6;
-
- sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
- mDNSPlatformMemZero( &ifr6, sizeof( ifr6 ) );
- strcpy( ifr6.ifr_name, ifa->ifa_name );
- ifr6.ifr_addr = *sa6;
- if( ioctl( infoSock, SIOCGIFAFLAG_IN6, (int) &ifr6 ) != -1 )
- {
- flags = ifr6.ifr_ifru.ifru_flags6;
- }
- }
-
- // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is
- // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an
- // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround,
- // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks.
-
- if( flags & ( IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY ) )
- {
- dmsg( kDebugLevelNotice, DEBUG_NAME "%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__,
- ifa->ifa_name, if_nametoindex( ifa->ifa_name ), flags );
- continue;
- }
- if( ifa->ifa_flags & IFF_LOOPBACK )
- {
- if( family == AF_INET ) loopbackV4 = ifa;
- else loopbackV6 = ifa;
- }
- else
- {
- if( ( family == AF_INET ) && gMDNSDeferIPv4 && IsLinkLocalSockAddr( ifa->ifa_addr ) ) continue;
- i = AddInterfaceToList( inMDNS, ifa, inUTC );
- if( i && i->multicast )
- {
- if( family == AF_INET ) foundV4 = mDNStrue;
- else foundV6 = mDNStrue;
- }
- }
- }
-
- // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
-
- if( !foundV4 && loopbackV4 ) AddInterfaceToList( inMDNS, loopbackV4, inUTC );
- if( !foundV6 && loopbackV6 ) AddInterfaceToList( inMDNS, loopbackV6, inUTC );
- freeifaddrs( ifaList );
- if( IsValidSocket( infoSock ) ) close_compat( infoSock );
-
- // The list is complete. Set the McastTxRx setting for each interface. We always send and receive using IPv4.
- // To reduce traffic, we send and receive using IPv6 only on interfaces that have no routable IPv4 address.
- // Having a routable IPv4 address assigned is a reasonable indicator of being on a large, configured network,
- // which means there's a good chance that most or all the other devices on that network should also have v4.
- // By doing this we lose the ability to talk to true v6-only devices on that link, but we cut the packet rate in half.
- // At this time, reducing the packet rate is more important than v6-only devices on a large configured network,
- // so we are willing to make that sacrifice.
-
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- if( i->exists )
- {
- mDNSBool txrx;
-
- txrx = i->multicast && ( ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) || !FindRoutableIPv4( inMDNS, i->scopeID ) );
- if( i->ifinfo.McastTxRx != txrx )
- {
- i->ifinfo.McastTxRx = txrx;
- i->exists = 2; // 2=state change; need to de-register and re-register this interface.
- }
- }
- }
-
- // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
-
- mDNS_snprintf( defaultName, sizeof( defaultName ), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
- primaryMAC.b[ 0 ], primaryMAC.b[ 1 ], primaryMAC.b[ 2 ], primaryMAC.b[ 3 ], primaryMAC.b[ 4 ], primaryMAC.b[ 5 ] );
-
- MakeDomainLabelFromLiteralString( &nicelabel, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
- if( nicelabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel, defaultName );
-
- // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
-
- MakeDomainLabelFromLiteralString( &tmp, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device.
- ConvertUTF8PstringToRFC1034HostLabel( tmp.c, &hostlabel );
- if( hostlabel.c[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel.c, &hostlabel );
- if( hostlabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel, defaultName );
-
- // Update our globals and mDNS with the new labels.
-
- if( !SameDomainLabelCS( inMDNS->p->userNiceLabel.c, nicelabel.c ) )
- {
- dmsg( kDebugLevelInfo, DEBUG_NAME "Updating nicelabel to \"%#s\"\n", nicelabel.c );
- inMDNS->p->userNiceLabel = nicelabel;
- inMDNS->nicelabel = nicelabel;
- }
- if( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) )
- {
- dmsg( kDebugLevelInfo, DEBUG_NAME "Updating hostlabel to \"%#s\"\n", hostlabel.c );
- inMDNS->p->userHostLabel = hostlabel;
- inMDNS->hostlabel = hostlabel;
- mDNS_SetFQDN( inMDNS );
- }
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// AddInterfaceToList
-//===========================================================================================================================
-
-mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC )
-{
- mStatus err;
- mDNSAddr ip;
- mDNSAddr mask;
- mDNSu32 scopeID;
- NetworkInterfaceInfoVxWorks ** p;
- NetworkInterfaceInfoVxWorks * i;
-
- i = NULL;
-
- err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ip );
- require_noerr( err, exit );
-
- err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &mask );
- require_noerr( err, exit );
-
- // Search for an existing interface with the same info. If found, just return that one.
-
- scopeID = if_nametoindex( inIFA->ifa_name );
- check( scopeID );
- for( p = &inMDNS->p->interfaceList; *p; p = &( *p )->next )
- {
- if( ( scopeID == ( *p )->scopeID ) && mDNSSameAddress( &ip, &( *p )->ifinfo.ip ) )
- {
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__,
- scopeID, &ip, *p );
- ( *p )->exists = mDNStrue;
- i = *p;
- goto exit;
- }
- }
-
- // Allocate the new interface info and fill it out.
-
- i = (NetworkInterfaceInfoVxWorks *) calloc( 1, sizeof( *i ) );
- require( i, exit );
-
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Making new interface %u with address %#a at %#p\n", __ROUTINE__, scopeID, &ip, i );
- strncpy( i->ifinfo.ifname, inIFA->ifa_name, sizeof( i->ifinfo.ifname ) );
- i->ifinfo.ifname[ sizeof( i->ifinfo.ifname ) - 1 ] = '\0';
- i->ifinfo.InterfaceID = NULL;
- i->ifinfo.ip = ip;
- i->ifinfo.mask = mask;
- i->ifinfo.Advertise = inMDNS->AdvertiseLocalAddresses;
- i->ifinfo.McastTxRx = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList.
-
- i->next = NULL;
- i->exists = mDNStrue;
- i->lastSeen = inUTC;
- i->scopeID = scopeID;
- i->family = inIFA->ifa_addr->sa_family;
- i->multicast = ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTOPOINT );
-
- i->ss.info = i;
- i->ss.sockV4 = kInvalidSocketRef;
- i->ss.sockV6 = kInvalidSocketRef;
- *p = i;
-
-exit:
- return( i );
-}
-
-//===========================================================================================================================
-// SetupActiveInterfaces
-//
-// Returns a count of non-link local IPv4 addresses registered.
-//===========================================================================================================================
-
-#define mDNSAddressIsNonLinkLocalIPv4( X ) \
- ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
-
-mDNSlocal int SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC )
-{
- int count;
- NetworkInterfaceInfoVxWorks * i;
-
- count = 0;
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- NetworkInterfaceInfo * n;
- NetworkInterfaceInfoVxWorks * primary;
-
- if( !i->exists ) continue;
-
- // Search for the primary interface and sanity check it.
-
- n = &i->ifinfo;
- primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
- if( !primary )
- {
- dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! didn't find %s(%u)\n", __ROUTINE__, i->ifinfo.ifname, i->scopeID );
- continue;
- }
- if( n->InterfaceID && ( n->InterfaceID != (mDNSInterfaceID) primary ) )
- {
- dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__,
- n->InterfaceID, primary );
- n->InterfaceID = NULL;
- }
-
- // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface.
- // so we don't need to call it again. Otherwise, register the interface with mDNS.
-
- if( !n->InterfaceID )
- {
- mDNSBool flapping;
-
- n->InterfaceID = (mDNSInterfaceID) primary;
-
- // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away.
- // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds.
- // If it's is an old one that went away and came back in less than a minute, we're in a flapping scenario.
-
- flapping = ( ( inUTC - i->lastSeen ) > 0 ) && ( ( inUTC - i->lastSeen ) < 60 );
- mDNS_RegisterInterface( inMDNS, n, (flapping ? SlowActivation : NormalActivation));
- if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
-
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Registered %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__,
- i->ifinfo.ifname, i->scopeID, primary, &n->ip,
- flapping ? " (Flapping)" : "",
- n->InterfaceActive ? " (Primary)" : "" );
- }
-
- // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we
- // don't need a socket since unicast traffic will be handled on the unicast socket.
-
- if( n->McastTxRx )
- {
- mStatus err;
-
- if( ( ( i->family == AF_INET ) && !IsValidSocket( primary->ss.sockV4 ) ) ||
- ( ( i->family == AF_INET6 ) && !IsValidSocket( primary->ss.sockV6 ) ) )
- {
- err = SetupSocket( inMDNS, &i->ifinfo.ip, mDNStrue, i->family, &primary->ss );
- check_noerr( err );
- }
- }
- else
- {
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: No Tx/Rx on %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__,
- i->ifinfo.ifname, i->scopeID, primary, &n->ip );
- }
- }
- return( count );
-}
-
-//===========================================================================================================================
-// MarkAllInterfacesInactive
-//===========================================================================================================================
-
-mDNSlocal void MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC )
-{
- NetworkInterfaceInfoVxWorks * i;
-
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- if( !i->exists ) continue;
- i->lastSeen = inUTC;
- i->exists = mDNSfalse;
- }
-}
-
-//===========================================================================================================================
-// ClearInactiveInterfaces
-//
-// Returns count of non-link local IPv4 addresses de-registered.
-//===========================================================================================================================
-
-mDNSlocal int ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing )
-{
- int count;
- NetworkInterfaceInfoVxWorks * i;
- NetworkInterfaceInfoVxWorks ** p;
-
- // First pass:
- // If an interface is going away, then de-register it from mDNSCore.
- // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away.
- // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
- // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though:
- // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that
- // interface. (Not yet implemented, but a good idea anyway.).
-
- count = 0;
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- NetworkInterfaceInfoVxWorks * primary;
-
- // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
-
- if( !i->ifinfo.InterfaceID ) continue;
- primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
- if( ( i->exists == 0 ) || ( i->exists == 2 ) || ( i->ifinfo.InterfaceID != (mDNSInterfaceID) primary ) )
- {
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__,
- i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
- i->ifinfo.InterfaceActive ? " (Primary)" : "" );
-
- mDNS_DeregisterInterface( inMDNS, &i->ifinfo, NormalActivation );
- i->ifinfo.InterfaceID = NULL;
- if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
- }
- }
-
- // Second pass:
- // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
-
- p = &inMDNS->p->interfaceList;
- while( *p )
- {
- i = *p;
-
- // 2. Close all our sockets. We'll recreate them later as needed.
- // (We may have previously had both v4 and v6, and we may not need both any more.).
-
- ForgetSocket( &i->ss.sockV4 );
- ForgetSocket( &i->ss.sockV6 );
-
- // 3. If no longer active, remove the interface from the list and free its memory.
-
- if( !i->exists )
- {
- mDNSBool deleteIt;
-
- if( inClosing )
- {
- check_string( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0, "closing with in-use records!" );
- deleteIt = mDNStrue;
- }
- else
- {
- if( i->lastSeen == inUTC ) i->lastSeen = inUTC - 1;
- deleteIt = ( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0 ) && ( ( inUTC - i->lastSeen ) >= 60 );
- }
- dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__,
- deleteIt ? "Deleting" : "Holding", i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
- inUTC - i->lastSeen, i->ifinfo.InterfaceActive ? " (Primary)" : "" );
- if( deleteIt )
- {
- *p = i->next;
- free( i );
- continue;
- }
- }
- p = &i->next;
- }
- return( count );
-}
-
-//===========================================================================================================================
-// FindRoutableIPv4
-//===========================================================================================================================
-
-mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID )
-{
-#if ( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
- NetworkInterfaceInfoVxWorks * i;
-
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- if( i->exists && ( i->scopeID == inScopeID ) && mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) )
- {
- break;
- }
- }
- return( i );
-#else
- DEBUG_UNUSED( inMDNS );
- DEBUG_UNUSED( inScopeID );
-
- return( NULL );
-#endif
-}
-
-//===========================================================================================================================
-// FindInterfaceByIndex
-//===========================================================================================================================
-
-mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex )
-{
- NetworkInterfaceInfoVxWorks * i;
-
- check( inIndex != 0 );
-
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- if( i->exists && ( i->scopeID == inIndex ) &&
- ( MDNS_AAAA_OVER_IPV4 ||
- ( ( inFamily == AF_INET ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) ) ||
- ( ( inFamily == AF_INET6 ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv6 ) ) ) )
- {
- return( i );
- }
- }
- return( NULL );
-}
-
-//===========================================================================================================================
-// SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS )
-{
- mStatus err;
- SocketRef * sockPtr;
- mDNSIPPort port;
- SocketRef sock;
- const int on = 1;
-
- check( inAddr );
- check( inSS );
-
- sockPtr = ( inFamily == AF_INET ) ? &inSS->sockV4 : &inSS->sockV6;
- port = ( inMcast || inMDNS->CanReceiveUnicastOn5353 ) ? MulticastDNSPort : zeroIPPort;
-
- sock = socket( inFamily, SOCK_DGRAM, IPPROTO_UDP );
- err = translate_errno( IsValidSocket( sock ), errno_compat(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // Allow multiple listeners if this is a multicast port.
-
- if( port.NotAnInteger )
- {
- err = setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof( on ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Set up the socket based on the family (IPv4 or IPv6).
-
- if( inFamily == AF_INET )
- {
- const int ttlV4 = 255;
- const u_char ttlV4Mcast = 255;
- struct sockaddr_in sa4;
-
- // Receive destination addresses so we know which address the packet was sent to.
-
- err = setsockopt( sock, IPPROTO_IP, IP_RECVDSTADDR, (char *) &on, sizeof( on ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Receive interface indexes so we know which interface received the packet.
-
- err = setsockopt( sock, IPPROTO_IP, IP_RECVIF, (char *) &on, sizeof( on ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
-
- if( inMcast )
- {
- struct in_addr addrV4;
- struct ip_mreq mreqV4;
-
- addrV4.s_addr = inAddr->ip.v4.NotAnInteger;
- mreqV4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- mreqV4.imr_interface = addrV4;
- err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqV4, sizeof( mreqV4 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addrV4, sizeof( addrV4 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Send unicast packets with TTL 255 (helps against spoofing).
-
- err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &ttlV4, sizeof( ttlV4 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Send multicast packets with TTL 255 (helps against spoofing).
-
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttlV4Mcast, sizeof( ttlV4Mcast ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Start listening for packets.
-
- mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
- sa4.sin_len = sizeof( sa4 );
- sa4.sin_family = AF_INET;
- sa4.sin_port = port.NotAnInteger;
- sa4.sin_addr.s_addr = htonl( INADDR_ANY ); // We want to receive multicasts AND unicasts on this socket.
- err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
- else if( inFamily == AF_INET6 )
- {
- struct sockaddr_in6 sa6;
- const int ttlV6 = 255;
-
- // Receive destination addresses and interface index so we know where the packet was received and intended.
-
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &on, sizeof( on ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
-
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof( on ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
-
- if( inMcast )
- {
- u_int ifindex;
- struct ipv6_mreq mreqV6;
-
- ifindex = inSS->info->scopeID;
- mreqV6.ipv6mr_interface = ifindex;
- mreqV6.ipv6mr_multiaddr = *( (struct in6_addr * ) &AllDNSLinkGroup_v6.ip.v6 );
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqV6, sizeof( mreqV6 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &ifindex, sizeof( ifindex ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Send unicast packets with TTL 255 (helps against spoofing).
-
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Send multicast packets with TTL 255 (helps against spoofing).
-
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Receive our own packets for same-machine operation.
-
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &on, sizeof( on ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Start listening for packets.
-
- mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
- sa6.sin6_len = sizeof( sa6 );
- sa6.sin6_family = AF_INET6;
- sa6.sin6_port = port.NotAnInteger;
- sa6.sin6_flowinfo = 0;
- sa6.sin6_addr = in6addr_any; // We want to receive multicasts AND unicasts on this socket.
- sa6.sin6_scope_id = 0;
- err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
- else
- {
- dmsg( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inFamily );
- err = kUnsupportedErr;
- goto exit;
- }
-
- // Make the socket non-blocking so we can potentially get multiple packets per select call.
-
- err = ioctl( sock, FIONBIO, (int) &on );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- *sockPtr = sock;
- sock = kInvalidSocketRef;
- err = mStatus_NoError;
-
-exit:
- if( IsValidSocket( sock ) ) close_compat( sock );
- return( err );
-}
-
-//===========================================================================================================================
-// SockAddrToMDNSAddr
-//===========================================================================================================================
-
-mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP )
-{
- mStatus err;
-
- check( inSA );
- check( outIP );
-
- if( inSA->sa_family == AF_INET )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) inSA;
- outIP->type = mDNSAddrType_IPv4;
- outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
- err = mStatus_NoError;
- }
- else if( inSA->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) inSA;
- outIP->type = mDNSAddrType_IPv6;
- outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
- if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) ) outIP->ip.v6.w[ 1 ] = 0;
- err = mStatus_NoError;
- }
- else
- {
- dmsg( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family (%d)\n", __ROUTINE__, inSA->sa_family );
- err = mStatus_BadParamErr;
- }
- return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Commands ==
-#endif
-
-//===========================================================================================================================
-// SetupCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS )
-{
- mStatus err;
-
- err = pipeDevCreate( "/pipe/mDNS", 32, 1 );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
- inMDNS->p->commandPipe = open( "/pipe/mDNS", O_RDWR, 0 );
- err = translate_errno( inMDNS->p->commandPipe != ERROR, errno_compat(), mStatus_UnsupportedErr );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS )
-{
- mStatus err;
-
- if( inMDNS->p->commandPipe != ERROR )
- {
- err = close( inMDNS->p->commandPipe );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
- inMDNS->p->commandPipe = ERROR;
-
- err = pipeDevDelete( "/pipe/mDNS", FALSE );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
- }
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// SendCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode )
-{
- mStatus err;
-
- require_action_quiet( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
-
- err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) );
- err = translate_errno( err >= 0, errno_compat(), kWriteErr );
- require_noerr( err, exit );
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ProcessCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS )
-{
- mStatus err;
- MDNSPipeCommandCode cmd;
- mDNSs32 utc;
-
- err = read( inMDNS->p->commandPipe, &cmd, sizeof( cmd ) );
- err = translate_errno( err >= 0, errno_compat(), kReadErr );
- require_noerr( err, exit );
-
- switch( cmd )
- {
- case kMDNSPipeCommandCodeReschedule: // Reschedule: just break out to re-run mDNS_Execute.
- break;
-
- case kMDNSPipeCommandCodeReconfigure: // Reconfigure: rebuild the interface list after a config change.
- dmsg( kDebugLevelInfo, DEBUG_NAME "*** NETWORK CONFIGURATION CHANGE ***\n" );
- mDNSPlatformLock( inMDNS );
-
- utc = mDNSPlatformUTC();
- MarkAllInterfacesInactive( inMDNS, utc );
- UpdateInterfaceList( inMDNS, utc );
- ClearInactiveInterfaces( inMDNS, utc, mDNSfalse );
- SetupActiveInterfaces( inMDNS, utc );
-
- mDNSPlatformUnlock( inMDNS );
- mDNS_ConfigChanged(inMDNS);
- break;
-
- case kMDNSPipeCommandCodeQuit: // Quit: just set a flag so the task exits cleanly.
- inMDNS->p->quit = mDNStrue;
- break;
-
- default:
- dmsg( kDebugLevelError, DEBUG_NAME "unknown pipe command (%d)\n", cmd );
- err = mStatus_BadParamErr;
- goto exit;
- }
-
-exit:
- return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Threads ==
-#endif
-
-//===========================================================================================================================
-// Task
-//===========================================================================================================================
-
-mDNSlocal void Task( mDNS *inMDNS )
-{
- mStatus err;
- mDNSs32 nextEvent;
- fd_set readSet;
- int maxFd;
- struct timeval timeout;
- NetworkInterfaceInfoVxWorks * i;
- int fd;
- int n;
-
- check( inMDNS );
-
- err = TaskInit( inMDNS );
- require_noerr( err, exit );
-
- while( !inMDNS->p->quit )
- {
- // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
-
- nextEvent = mDNS_Execute( inMDNS );
- TaskSetupSelect( inMDNS, &readSet, &maxFd, nextEvent, &timeout );
- n = select( maxFd + 1, &readSet, NULL, NULL, &timeout );
- check_translated_errno( n >= 0, errno_compat(), kUnknownErr );
- if( n == 0 ) continue;
-
- // Process interface-specific sockets with pending data.
-
- n = 0;
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- fd = i->ss.sockV4;
- if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
- {
- TaskProcessPackets( inMDNS, &i->ss, fd );
- ++n;
- }
- fd = i->ss.sockV6;
- if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
- {
- TaskProcessPackets( inMDNS, &i->ss, fd );
- ++n;
- }
- }
-
- // Process unicast sockets with pending data.
-
- fd = inMDNS->p->unicastSS.sockV4;
- if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
- {
- TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
- ++n;
- }
- fd = inMDNS->p->unicastSS.sockV6;
- if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
- {
- TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
- ++n;
- }
-
- // Processing pending commands.
-
- fd = inMDNS->p->commandPipe;
- check( fd >= 0 );
- if( FD_ISSET( fd, &readSet ) )
- {
- ProcessCommand( inMDNS );
- ++n;
- }
- check_string( n > 0, "select said something was readable, but nothing was" );
- }
-
-exit:
- TaskTerm( inMDNS );
-}
-
-//===========================================================================================================================
-// TaskInit
-//===========================================================================================================================
-
-mDNSlocal mStatus TaskInit( mDNS *inMDNS )
-{
- mStatus err;
- mDNSs32 utc;
- socklen_t len;
-
- inMDNS->p->taskID = taskIdSelf();
-
- err = SetupCommandPipe( inMDNS );
- require_noerr( err, exit );
-
- inMDNS->CanReceiveUnicastOn5353 = mDNStrue;
-
- // Set up the HINFO string using the description property (e.g. "Device V1.0").
-
- inMDNS->HIHardware.c[ 0 ] = 11;
- memcpy( &inMDNS->HIHardware.c[ 1 ], "Device V1.0", inMDNS->HIHardware.c[ 0 ] ); // $$$ Implementers: Fill in real info.
-
- // Set up the unicast sockets.
-
- err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET, &inMDNS->p->unicastSS );
- check_noerr( err );
- if( err == mStatus_NoError )
- {
- struct sockaddr_in sa4;
-
- len = sizeof( sa4 );
- err = getsockname( inMDNS->p->unicastSS.sockV4, (struct sockaddr *) &sa4, &len );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
- if( err == 0 ) inMDNS->UnicastPort4.NotAnInteger = sa4.sin_port;
- }
-
- err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET6, &inMDNS->p->unicastSS );
- check_noerr( err );
- if( err == mStatus_NoError )
- {
- struct sockaddr_in6 sa6;
-
- len = sizeof( sa6 );
- err = getsockname( inMDNS->p->unicastSS.sockV6, (struct sockaddr *) &sa6, &len );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
- if( err == 0 ) inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port;
- }
-
- // Set up the interfaces.
-
- utc = mDNSPlatformUTC();
- UpdateInterfaceList( inMDNS, utc );
- SetupActiveInterfaces( inMDNS, utc );
- err = mStatus_NoError;
-
-exit:
- // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
-
- inMDNS->p->initErr = err;
- semGive( inMDNS->p->initEvent );
- return( err );
-}
-
-//===========================================================================================================================
-// TaskTerm
-//===========================================================================================================================
-
-mDNSlocal void TaskTerm( mDNS *inMDNS )
-{
- mStatus err;
- mDNSs32 utc;
-
- // Tear down all interfaces.
-
- utc = mDNSPlatformUTC();
- MarkAllInterfacesInactive( inMDNS, utc );
- ClearInactiveInterfaces( inMDNS, utc, mDNStrue );
- check_string( !inMDNS->p->interfaceList, "LEAK: closing without deleting all interfaces" );
-
- // Close unicast sockets.
-
- ForgetSocket( &inMDNS->p->unicastSS.sockV4);
- ForgetSocket( &inMDNS->p->unicastSS.sockV6 );
-
- // Tear down everything else that was set up in TaskInit then signal back that we're done.
-
- err = TearDownCommandPipe( inMDNS );
- check_noerr( err );
-
- err = semGive( inMDNS->p->quitEvent );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-}
-
-//===========================================================================================================================
-// TaskSetupSelect
-//===========================================================================================================================
-
-mDNSlocal void TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout )
-{
- NetworkInterfaceInfoVxWorks * i;
- int maxFd;
- int fd;
- mDNSs32 delta;
-
- FD_ZERO( outSet );
- maxFd = -1;
-
- // Add the interface-specific sockets.
-
- for( i = inMDNS->p->interfaceList; i; i = i->next )
- {
- fd = i->ss.sockV4;
- if( IsValidSocket( fd ) )
- {
- FD_SET( fd, outSet );
- if( fd > maxFd ) maxFd = fd;
- }
-
- fd = i->ss.sockV6;
- if( IsValidSocket( fd ) )
- {
- FD_SET( fd, outSet );
- if( fd > maxFd ) maxFd = fd;
- }
- }
-
- // Add the unicast sockets.
-
- fd = inMDNS->p->unicastSS.sockV4;
- if( IsValidSocket( fd ) )
- {
- FD_SET( fd, outSet );
- if( fd > maxFd ) maxFd = fd;
- }
-
- fd = inMDNS->p->unicastSS.sockV6;
- if( IsValidSocket( fd ) )
- {
- FD_SET( fd, outSet );
- if( fd > maxFd ) maxFd = fd;
- }
-
- // Add the command pipe.
-
- fd = inMDNS->p->commandPipe;
- check( fd >= 0 );
- FD_SET( fd, outSet );
- if( fd > maxFd ) maxFd = fd;
-
- check( maxFd > 0 );
- *outMaxFd = maxFd;
-
- // Calculate how long to wait before performing idle processing.
-
- delta = inNextEvent - mDNS_TimeNow( inMDNS );
- if( delta <= 0 )
- {
- // The next task time is now or in the past. Set the timeout to fire immediately.
-
- outTimeout->tv_sec = 0;
- outTimeout->tv_usec = 0;
- }
- else
- {
- // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
- // before multiplying to account for integer rounding error and avoid firing the timeout too early.
-
- outTimeout->tv_sec = delta / mDNSPlatformOneSecond;
- outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicro;
- if( outTimeout->tv_usec >= 1000000L )
- {
- outTimeout->tv_sec += 1;
- outTimeout->tv_usec = 0;
- }
- }
-}
-
-//===========================================================================================================================
-// TaskProcessPackets
-//===========================================================================================================================
-
-mDNSlocal void TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock )
-{
- mDNSu32 ifindex;
- ssize_t n;
- mDNSu8 * buf;
- size_t size;
- struct sockaddr_storage from;
- size_t fromSize;
- mDNSAddr destAddr;
- mDNSAddr senderAddr;
- mDNSIPPort senderPort;
- mDNSInterfaceID id;
-
- buf = (mDNSu8 *) &inMDNS->imsg;
- size = sizeof( inMDNS->imsg );
- for( ;; )
- {
- ifindex = 0;
- n = mDNSRecvMsg( inSock, buf, size, &from, sizeof( from ), &fromSize, &destAddr, &ifindex );
- if( n < 0 ) break;
- if( from.ss_family == AF_INET )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) &from;
- senderAddr.type = mDNSAddrType_IPv4;
- senderAddr.ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
- senderPort.NotAnInteger = sa4->sin_port;
- }
- else if( from.ss_family == AF_INET6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) &from;
- senderAddr.type = mDNSAddrType_IPv6;
- senderAddr.ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
- senderPort.NotAnInteger = sa6->sin6_port;
- }
- else
- {
- dmsg( kDebugLevelWarning, DEBUG_NAME "%s: WARNING! from addr unknown family %d\n", __ROUTINE__, from.ss_family );
- continue;
- }
-
- // Even though we indicated a specific interface when joining the multicast group, a weirdness of the
- // sockets API means that even though this socket has only officially joined the multicast group
- // on one specific interface, the kernel will still deliver multicast packets to it no matter which
- // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
- // To work around this weirdness, we use the IP_RECVIF/IPV6_PKTINFO options to find the interface
- // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
-
- if( mDNSAddrIsDNSMulticast( &destAddr ) )
- {
- if( !inSS->info || !inSS->info->exists )
- {
- dpkt( kDebugLevelChatty - 3, DEBUG_NAME " ignored mcast, src=[%#39a], dst=[%#39a], if= unicast socket %d\n",
- &senderAddr, &destAddr, inSock );
- continue;
- }
- if( ifindex != inSS->info->scopeID )
- {
- #if ( DEBUG && MDNS_DEBUG_PACKETS )
- char ifname[ IF_NAMESIZE ];
- #endif
-
- dpkt( kDebugLevelChatty - 3,
- DEBUG_NAME " ignored mcast, src=[%#39a] dst=[%#39a], if=%8s(%u) -- really for %8s(%u)\n",
- &senderAddr, &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID,
- if_indextoname( ifindex, ifname ), ifindex );
- continue;
- }
-
- id = inSS->info->ifinfo.InterfaceID;
- dpkt( kDebugLevelChatty - 2, DEBUG_NAME "recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a], if=%8s(%u) %#p\n",
- n, &senderAddr, mDNSVal16( senderPort ), &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID, id );
- }
- else
- {
- NetworkInterfaceInfoVxWorks * i;
-
- // For unicast packets, try to find the matching interface.
-
- for( i = inMDNS->p->interfaceList; i && ( i->scopeID != ifindex ); i = i->next ) {}
- if( i ) id = i->ifinfo.InterfaceID;
- else id = NULL;
- }
- mDNSCoreReceive( inMDNS, buf, buf + n, &senderAddr, senderPort, &destAddr, MulticastDNSPort, id );
- }
-}
-
-//===========================================================================================================================
-// mDNSRecvMsg
-//===========================================================================================================================
-
-mDNSlocal ssize_t
-mDNSRecvMsg(
- SocketRef inSock,
- void * inBuffer,
- size_t inBufferSize,
- void * outFrom,
- size_t inFromSize,
- size_t * outFromSize,
- mDNSAddr * outDstAddr,
- uint32_t * outIndex )
-{
- struct msghdr msg;
- struct iovec iov;
- ssize_t n;
- char ancillary[ 1024 ];
- struct cmsghdr * cmPtr;
- int err;
-
- // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
-
- iov.iov_base = (char *) inBuffer;
- iov.iov_len = inBufferSize;
- msg.msg_name = (caddr_t) outFrom;
- msg.msg_namelen = inFromSize;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = (caddr_t) &ancillary;
- msg.msg_controllen = sizeof( ancillary );
- msg.msg_flags = 0;
- n = recvmsg( inSock, &msg, 0 );
- if( n < 0 )
- {
- err = errno_compat();
- if( err != EWOULDBLOCK ) dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) returned %d, errno %d\n",
- __ROUTINE__, inSock, n, err );
- goto exit;
- }
- if( msg.msg_controllen < sizeof( struct cmsghdr ) )
- {
- dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
- __ROUTINE__, inSock, msg.msg_controllen, sizeof( struct cmsghdr ) );
- n = mStatus_UnknownErr;
- goto exit;
- }
- if( msg.msg_flags & MSG_CTRUNC )
- {
- dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__, inSock, n );
- n = mStatus_BadFlagsErr;
- goto exit;
- }
- *outFromSize = msg.msg_namelen;
-
- // Parse each option out of the ancillary data.
-
- for( cmPtr = CMSG_FIRSTHDR( &msg ); cmPtr; cmPtr = CMSG_NXTHDR( &msg, cmPtr ) )
- {
- if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVDSTADDR ) )
- {
- outDstAddr->type = mDNSAddrType_IPv4;
- outDstAddr->ip.v4.NotAnInteger = *( (mDNSu32 *) CMSG_DATA( cmPtr ) );
- }
- else if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVIF ) )
- {
- struct sockaddr_dl * sdl;
-
- sdl = (struct sockaddr_dl *) CMSG_DATA( cmPtr );
- *outIndex = sdl->sdl_index;
- }
- else if( ( cmPtr->cmsg_level == IPPROTO_IPV6 ) && ( cmPtr->cmsg_type == IPV6_PKTINFO ) )
- {
- struct in6_pktinfo * pi6;
-
- pi6 = (struct in6_pktinfo *) CMSG_DATA( cmPtr );
- outDstAddr->type = mDNSAddrType_IPv6;
- outDstAddr->ip.v6 = *( (mDNSv6Addr *) &pi6->ipi6_addr );
- *outIndex = pi6->ipi6_ifindex;
- }
- }
-
-exit:
- return( n );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Debugging ==
-#endif
-
-#if ( DEBUG && MDNS_DEBUG_SHOW )
-//===========================================================================================================================
-// mDNSShow
-//===========================================================================================================================
-
-void mDNSShow( void );
-
-void mDNSShow( void )
-{
- NetworkInterfaceInfoVxWorks * i;
- int num;
- AuthRecord * r;
- mDNSs32 utc;
-
- // Globals
-
- dmsg( kDebugLevelMax, "\n-- mDNS globals --\n" );
- dmsg( kDebugLevelMax, " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS ) );
- dmsg( kDebugLevelMax, " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord ) );
- dmsg( kDebugLevelMax, " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord ) );
- dmsg( kDebugLevelMax, " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord ) );
- dmsg( kDebugLevelMax, " mDNSPlatformOneSecond = %ld\n", mDNSPlatformOneSecond );
- dmsg( kDebugLevelMax, " gMDNSTicksToMicro = %ld\n", gMDNSTicksToMicro );
- dmsg( kDebugLevelMax, " gMDNSPtr = %#p\n", gMDNSPtr );
- if( !gMDNSPtr )
- {
- dmsg( kDebugLevelMax, "### mDNS not initialized\n" );
- return;
- }
- dmsg( kDebugLevelMax, " nicelabel = \"%#s\"\n", gMDNSPtr->nicelabel.c );
- dmsg( kDebugLevelMax, " hostLabel = \"%#s\"\n", gMDNSPtr->hostlabel.c );
- dmsg( kDebugLevelMax, " MulticastHostname = \"%##s\"\n", gMDNSPtr->MulticastHostname.c );
- dmsg( kDebugLevelMax, " HIHardware = \"%#s\"\n", gMDNSPtr->HIHardware.c );
- dmsg( kDebugLevelMax, " HISoftware = \"%#s\"\n", gMDNSPtr->HISoftware.c );
- dmsg( kDebugLevelMax, " UnicastPort4/6 = %d/%d\n",
- mDNSVal16( gMDNSPtr->UnicastPort4 ), mDNSVal16( gMDNSPtr->UnicastPort6 ) );
- dmsg( kDebugLevelMax, " unicastSS.sockV4/V6 = %d/%d\n",
- gMDNSPtr->p->unicastSS.sockV4, gMDNSPtr->p->unicastSS.sockV6 );
- dmsg( kDebugLevelMax, " lock = %#p\n", gMDNSPtr->p->lock );
- dmsg( kDebugLevelMax, " initEvent = %#p\n", gMDNSPtr->p->initEvent );
- dmsg( kDebugLevelMax, " initErr = %ld\n", gMDNSPtr->p->initErr );
- dmsg( kDebugLevelMax, " quitEvent = %#p\n", gMDNSPtr->p->quitEvent );
- dmsg( kDebugLevelMax, " commandPipe = %d\n", gMDNSPtr->p->commandPipe );
- dmsg( kDebugLevelMax, " taskID = %#p\n", gMDNSPtr->p->taskID );
- dmsg( kDebugLevelMax, "\n" );
-
- // Interfaces
-
- utc = mDNSPlatformUTC();
- dmsg( kDebugLevelMax, "-- mDNS interfaces --\n" );
- num = 0;
- for( i = gMDNSPtr->p->interfaceList; i; i = i->next )
- {
- dmsg( kDebugLevelMax, " interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
- num, i->ifinfo.ifname, i->scopeID, &i->ifinfo.ip,
- i->ifinfo.InterfaceID ? " REGISTERED" : "*NOT* registered",
- i->ss.sockV4, i->ss.sockV6, utc - i->lastSeen );
- ++num;
- }
- dmsg( kDebugLevelMax, "\n" );
-
- // Resource Records
-
- dmsg( kDebugLevelMax, "-- mDNS resource records --\n" );
- num = 0;
- for( r = gMDNSPtr->ResourceRecords; r; r = r->next )
- {
- i = (NetworkInterfaceInfoVxWorks *) r->resrec.InterfaceID;
- if( r->resrec.rrtype == kDNSType_TXT )
- {
- RDataBody * rd;
- const mDNSu8 * txt;
- const mDNSu8 * end;
- mDNSu8 size;
- int nEntries;
-
- rd = &r->resrec.rdata->u;
- dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %4d %##s %s:\n", num, i,
- i ? i->ifinfo.ifname : "<any>",
- i ? i->scopeID : 0,
- r->resrec.rdlength, r->resrec.name->c, DNSTypeName( r->resrec.rrtype ) );
-
- nEntries = 0;
- txt = rd->txt.c;
- end = txt + r->resrec.rdlength;
- while( txt < end )
- {
- size = *txt++;
- if( ( txt + size ) > end )
- {
- dmsg( kDebugLevelMax, " ### ERROR! txt length byte too big (%u, %u max)\n", size, end - txt );
- break;
- }
- dmsg( kDebugLevelMax, " string %2d (%3d bytes): \"%.*s\"\n", nEntries, size, size, txt );
- txt += size;
- ++nEntries;
- }
- }
- else
- {
- dmsg( kDebugLevelMax, " record %2d: %#p %8s(%u): %s\n", num, i,
- i ? i->ifinfo.ifname : "<any>",
- i ? i->scopeID : 0,
- ARDisplayString( gMDNSPtr, r ) );
- }
- ++num;
- }
- dmsg( kDebugLevelMax, "\n");
-}
-#endif // DEBUG && MDNS_DEBUG_SHOW
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __MDNS_VXWORKS_H__
-#define __MDNS_VXWORKS_H__
-
-#include "vxWorks.h"
-#include "config.h"
-
-#include "semLib.h"
-
-#include "CommonServices.h"
-#include "DebugServices.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Forward Declarations
-
-typedef struct NetworkInterfaceInfoVxWorks NetworkInterfaceInfoVxWorks;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct SocketSet
-
- @abstract Data for IPv4 and IPv6 sockets.
- */
-
-typedef struct SocketSet SocketSet;
-struct SocketSet
-{
- NetworkInterfaceInfoVxWorks * info;
- SocketRef sockV4;
- SocketRef sockV6;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct NetworkInterfaceInfoVxWorks
-
- @abstract Interface info for VxWorks.
- */
-
-struct NetworkInterfaceInfoVxWorks
-{
- NetworkInterfaceInfo ifinfo; // MUST be the first element in this structure.
- NetworkInterfaceInfoVxWorks * next;
- mDNSu32 exists; // 1 = currently exists in getifaddrs list; 0 = doesn't.
- // 2 = exists, but McastTxRx state changed.
- mDNSs32 lastSeen; // If exists == 0, last time this interface appeared in getifaddrs list.
- mDNSu32 scopeID; // Interface index / IPv6 scope ID.
- int family; // Socket address family of the primary socket.
- mDNSBool multicast;
- SocketSet ss;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct mDNS_PlatformSupport_struct
-
- @abstract Data for mDNS platform plugin.
- */
-
-struct mDNS_PlatformSupport_struct
-{
- NetworkInterfaceInfoVxWorks * interfaceList;
- SocketSet unicastSS;
- domainlabel userNiceLabel;
- domainlabel userHostLabel;
-
- SEM_ID lock;
- SEM_ID initEvent;
- mStatus initErr;
- SEM_ID quitEvent;
- int commandPipe;
- int taskID;
- mDNSBool quit;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function mDNSReconfigure
-
- @abstract Tell mDNS that the configuration has changed. Call when IP address changes, link goes up after being down, etc.
-
- @discussion
-
- VxWorks does not provide a generic mechanism for getting notified when network interfaces change so this routines
- provides a way for BSP-specific code to signal mDNS that something has changed and it should re-build its interfaces.
- */
-
-void mDNSReconfigure( void );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function mDNSDeferIPv4
-
- @abstract Tells mDNS whether to defer advertising of IPv4 interfaces.
-
- @discussion
-
- To workaround problems with clients getting a link-local IPv4 address before a DHCP address is acquired, this allows
- external code to defer advertising of IPv4 addresses until a DHCP lease has been acquired (or it times out).
- */
-
-void mDNSDeferIPv4( mDNSBool inDefer );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __MDNS_VXWORKS_H__
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
- Contains: mDNS platform plugin for VxWorks.
-
- Copyright: Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
-
- Notes for non-Apple platforms:
-
- TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
-
- To Do:
-
- - Add support for IPv6 (needs VxWorks IPv6 support).
- */
-
-// Set up the debug library to use the default category (see DebugServicesLite.h for details).
-
-#if ( !TARGET_NON_APPLE )
- #define DEBUG_USE_DEFAULT_CATEGORY 1
-#endif
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netinet/if_ether.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include "vxWorks.h"
-#include "ifLib.h"
-#include "inetLib.h"
-#include "pipeDrv.h"
-#include "selectLib.h"
-#include "semLib.h"
-#include "sockLib.h"
-#include "sysLib.h"
-#include "taskLib.h"
-#include "tickLib.h"
-
-#include "config.h"
-
-#if ( !TARGET_NON_APPLE )
- #include "ACP/ACPUtilities.h"
- #include "Support/DebugServicesLite.h"
- #include "Support/MiscUtilities.h"
-#endif
-
-#include "mDNSEmbeddedAPI.h"
-
-#include "mDNSVxWorks.h"
-
-#if 0
-#pragma mark == Preprocessor ==
-#endif
-
-//===========================================================================================================================
-// Preprocessor
-//===========================================================================================================================
-
-#if ( !TARGET_NON_APPLE )
-debug_log_new_default_category( mdns );
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME "[mDNS] "
-
-#define kMDNSDefaultName "My-Device"
-
-#define kMDNSTaskName "tMDNS"
-#define kMDNSTaskPriority 102
-#define kMDNSTaskStackSize 49152
-
-#define kMDNSPipeName "/pipe/mDNS"
-#define kMDNSPipeMessageQueueSize 32
-#define kMDNSPipeMessageSize 1
-
-#define kInvalidSocketRef -1
-
-typedef uint8_t MDNSPipeCommandCode;
-enum
-{
- kMDNSPipeCommandCodeInvalid = 0,
- kMDNSPipeCommandCodeReschedule = 1,
- kMDNSPipeCommandCodeReconfigure = 2,
- kMDNSPipeCommandCodeQuit = 3
-};
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-// Structures
-//===========================================================================================================================
-
-typedef int MDNSSocketRef;
-
-struct MDNSInterfaceItem
-{
- MDNSInterfaceItem * next;
- char name[ 32 ];
- MDNSSocketRef multicastSocketRef;
- MDNSSocketRef sendingSocketRef;
- NetworkInterfaceInfo hostSet;
- mDNSBool hostRegistered;
-
- int sendMulticastCounter;
- int sendUnicastCounter;
- int sendErrorCounter;
-
- int recvCounter;
- int recvErrorCounter;
- int recvLoopCounter;
-};
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-// Macros
-//===========================================================================================================================
-
-#if ( TARGET_NON_APPLE )
-
-// Do-nothing versions of the debugging macros for non-Apple platforms.
-
- #define check(assertion)
- #define check_string( assertion, cstring )
- #define check_noerr(err)
- #define check_noerr_string( error, cstring )
- #define check_errno( assertion, errno_value )
- #define debug_string( cstring )
- #define require( assertion, label ) do { if( !(assertion) ) goto label;} while(0)
- #define require_string( assertion, label, string ) require(assertion, label)
- #define require_quiet( assertion, label ) require( assertion, label )
- #define require_noerr( error, label ) do { if( (error) != 0 ) goto label;} while(0)
- #define require_noerr_quiet( assertion, label ) require_noerr( assertion, label )
- #define require_noerr_action( error, label, action ) do { if( (error) != 0 ) { {action;}; goto label; } } while(0)
- #define require_noerr_action_quiet( assertion, label, action ) require_noerr_action( assertion, label, action )
- #define require_action( assertion, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
- #define require_action_quiet( assertion, label, action ) require_action( assertion, label, action )
- #define require_action_string( assertion, label, action, cstring ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
- #define require_errno( assertion, errno_value, label ) do { if( !(assertion) ) goto label;} while(0)
- #define require_errno_action( assertion, errno_value, label, action ) do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-
- #define dlog( ARGS... )
-
- #define DEBUG_UNUSED( X ) (void)( X )
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-// ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
-
-extern struct ifnet * ifIndexToIfp(int ifIndex);
-
-// Platform Internals
-
-mDNSlocal void SetupNames( mDNS * const inMDNS );
-mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS );
-mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS );
-mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem );
-mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem );
-mDNSlocal mStatus
-SetupSocket(
- mDNS * const inMDNS,
- const struct ifaddrs * inAddr,
- mDNSIPPort inPort,
- MDNSSocketRef * outSocketRef );
-
-// Commands
-
-mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
-mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS );
-mDNSlocal void ProcessCommandReconfigure( mDNS *inMDNS );
-
-// Threads
-
-mDNSlocal mStatus SetupTask( mDNS * const inMDNS );
-mDNSlocal mStatus TearDownTask( mDNS * const inMDNS );
-mDNSlocal void Task( mDNS *inMDNS );
-mDNSlocal mStatus TaskInit( mDNS *inMDNS );
-mDNSlocal void TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket );
-mDNSlocal void TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout );
-mDNSlocal void TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef );
-
-// Utilities
-
-#if ( TARGET_NON_APPLE )
-mDNSlocal void GenerateUniqueHostName( char *outName, long *ioSeed );
-mDNSlocal void GenerateUniqueDNSName( char *outName, long *ioSeed );
-#endif
-
-// Platform Accessors
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
-struct mDNSPlatformInterfaceInfo
-{
- const char * name;
- mDNSAddr ip;
-};
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
-
-#ifdef __cplusplus
-}
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-mDNSlocal mDNS * gMDNSPtr = NULL;
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier = 0;
-
-// Platform support
-
-mDNSs32 mDNSPlatformOneSecond;
-
-#if 0
-#pragma mark -
-#pragma mark == Public APIs ==
-#endif
-
-//===========================================================================================================================
-// mDNSReconfigure
-//===========================================================================================================================
-
-void mDNSReconfigure( void )
-{
- // Send a "reconfigure" command to the MDNS task.
-
- if( gMDNSPtr )
- {
- SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure );
- }
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Support ==
-#endif
-
-//===========================================================================================================================
-// mDNSPlatformInit
-//===========================================================================================================================
-
-mStatus mDNSPlatformInit( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "platform init\n" );
-
- // Initialize variables.
-
- mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
- inMDNS->p = &gMDNSPlatformSupport;
- inMDNS->p->commandPipe = ERROR;
- inMDNS->p->task = ERROR;
- inMDNS->p->rescheduled = 1; // Default to rescheduled until fully initialized.
- mDNSPlatformOneSecond = sysClkRateGet();
- gMDNSTicksToMicrosecondsMultiplier = ( 1000000L / mDNSPlatformOneSecond );
-
- // Allocate semaphores.
-
- inMDNS->p->lockID = semMCreate( SEM_Q_FIFO );
- require_action( inMDNS->p->lockID, exit, err = mStatus_NoMemoryErr );
-
- inMDNS->p->readyEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
- require_action( inMDNS->p->readyEvent, exit, err = mStatus_NoMemoryErr );
-
- inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
- require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
-
- gMDNSPtr = inMDNS;
-
- // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
- // stack space issues. Some of the initialization may require a larger stack than the current task supports.
-
- err = SetupTask( inMDNS );
- require_noerr( err, exit );
-
- err = semTake( inMDNS->p->readyEvent, WAIT_FOREVER );
- require_noerr( err, exit );
- err = inMDNS->p->taskInitErr;
- require_noerr( err, exit );
-
- mDNSCoreInitComplete( inMDNS, err );
-
-exit:
- if( err )
- {
- mDNSPlatformClose( inMDNS );
- }
- dlog( kDebugLevelInfo, DEBUG_NAME "platform init done (err=%ld)\n", err );
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformClose
-//===========================================================================================================================
-
-void mDNSPlatformClose( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "platform close\n" );
- check( inMDNS );
-
- // Tear everything down.
-
- err = TearDownTask( inMDNS );
- check_noerr( err );
-
- err = TearDownInterfaceList( inMDNS );
- check_noerr( err );
-
- err = TearDownCommandPipe( inMDNS );
- check_noerr( err );
-
- gMDNSPtr = NULL;
-
- // Release semaphores.
-
- if( inMDNS->p->quitEvent )
- {
- semDelete( inMDNS->p->quitEvent );
- inMDNS->p->quitEvent = 0;
- }
- if( inMDNS->p->readyEvent )
- {
- semDelete( inMDNS->p->readyEvent );
- inMDNS->p->readyEvent = 0;
- }
- if( inMDNS->p->lockID )
- {
- semDelete( inMDNS->p->lockID );
- inMDNS->p->lockID = 0;
- }
-
- dlog( kDebugLevelInfo, DEBUG_NAME "platform close done\n" );
-}
-
-//===========================================================================================================================
-// mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformSendUDP(
- const mDNS * const inMDNS,
- const void * const inMsg,
- const mDNSu8 * const inMsgEnd,
- mDNSInterfaceID inInterfaceID,
- const mDNSAddr * inDstIP,
- mDNSIPPort inDstPort )
-{
- mStatus err;
- MDNSInterfaceItem * item;
- struct sockaddr_in addr;
- int n;
-
- dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP\n" );
-
- // Check parameters.
-
- check( inMDNS );
- check( inMsg );
- check( inMsgEnd );
- check( inInterfaceID );
- check( inDstIP );
- if( inDstIP->type != mDNSAddrType_IPv4 )
- {
- err = mStatus_BadParamErr;
- goto exit;
- }
-
-#if ( DEBUG )
- // Make sure the InterfaceID is valid.
-
- for( item = inMDNS->p->interfaceList; item; item = item->next )
- {
- if( item == (MDNSInterfaceItem *) inInterfaceID )
- {
- break;
- }
- }
- require_action( item, exit, err = mStatus_NoSuchNameErr );
-#endif
-
- // Send the packet.
-
- item = (MDNSInterfaceItem *) inInterfaceID;
- check( item->sendingSocketRef != kInvalidSocketRef );
-
- mDNSPlatformMemZero( &addr, sizeof( addr ) );
- addr.sin_family = AF_INET;
- addr.sin_port = inDstPort.NotAnInteger;
- addr.sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
-
- n = inMsgEnd - ( (const mDNSu8 * const) inMsg );
- n = sendto( item->sendingSocketRef, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
- check_errno( n, errno );
-
- item->sendErrorCounter += ( n < 0 );
- item->sendMulticastCounter += ( inDstPort.NotAnInteger == MulticastDNSPort.NotAnInteger );
- item->sendUnicastCounter += ( inDstPort.NotAnInteger != MulticastDNSPort.NotAnInteger );
-
- dlog( kDebugLevelChatty, DEBUG_NAME "sent (to=%u.%u.%u.%u:%hu)\n",
- inDstIP->ip.v4.b[ 0 ], inDstIP->ip.v4.b[ 1 ], inDstIP->ip.v4.b[ 2 ], inDstIP->ip.v4.b[ 3 ],
- htons( inDstPort.NotAnInteger ) );
- err = mStatus_NoError;
-
-exit:
- dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP done\n" );
- return( err );
-}
-
-//===========================================================================================================================
-// Connection-oriented (TCP) functions
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
- TCPConnectionCallback callback, void *context, int *descriptor)
-{
- (void)dst; // Unused
- (void)dstport; // Unused
- (void)InterfaceID; // Unused
- (void)callback; // Unused
- (void)context; // Unused
- (void)descriptor; // Unused
- return(mStatus_UnsupportedErr);
-}
-
-mDNSexport void mDNSPlatformTCPCloseConnection(int sd)
-{
- (void)sd; // Unused
-}
-
-mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
-{
- (void)sd; // Unused
- (void)buf; // Unused
- (void)buflen; // Unused
- return(0);
-}
-
-mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
-{
- (void)sd; // Unused
- (void)msg; // Unused
- (void)len; // Unused
- return(0);
-}
-
-//===========================================================================================================================
-// mDNSPlatformLock
-//===========================================================================================================================
-
-void mDNSPlatformLock( const mDNS * const inMDNS )
-{
- check( inMDNS->p->lockID );
-
- if( inMDNS->p->lockID )
- {
- #if ( TARGET_NON_APPLE )
- semTake( inMDNS->p->lockID, WAIT_FOREVER );
- #else
- semTakeDeadlockDetect( inMDNS->p->lockID, WAIT_FOREVER );
- #endif
- }
-}
-
-//===========================================================================================================================
-// mDNSPlatformUnlock
-//===========================================================================================================================
-
-void mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
- check( inMDNS );
- check( inMDNS->p );
- check( inMDNS->p->lockID );
- check_string( inMDNS->p->task != ERROR, "mDNS task not started" );
-
- // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
- // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
- // (a) handle immediate work (if any) resulting from this API call
- // (b) calculate the next sleep time between now and the next interesting event
-
- if( ( mDNS_TimeNow(inMDNS) - inMDNS->NextScheduledEvent ) >= 0 )
- {
- // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
- // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
-
- if( ( inMDNS->p->rescheduled++ == 0 ) && ( taskIdSelf() != inMDNS->p->task ) )
- {
- SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule );
- }
- }
-
- if( inMDNS->p->lockID )
- {
- semGive( inMDNS->p->lockID );
- }
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSu32 mDNSPlatformStrLen( const void *inSrc )
-{
- check( inSrc );
-
- return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrCopy
-//===========================================================================================================================
-
-void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
- check( inSrc );
- check( inDst );
-
- strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemCopy
-//===========================================================================================================================
-
-void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- return( memcmp( inSrc, inDst, inSize ) == 0 );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemZero
-//===========================================================================================================================
-
-void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
- check( inDst );
-
- memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
- void * mem;
-
- check( inSize > 0 );
-
- mem = malloc( inSize );
- check( mem );
-
- return( mem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemFree( void *inMem )
-{
- check( inMem );
-
- free( inMem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRandomSeed
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
-{
- return( tickGet() );
-}
-
-//===========================================================================================================================
-// mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTimeInit( void )
-{
- // No special setup is required on VxWorks -- we just use tickGet().
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSs32 mDNSPlatformRawTime( void )
-{
- return( (mDNSs32) tickGet() );
-}
-
-//===========================================================================================================================
-// mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32 mDNSPlatformUTC( void )
-{
- return( -1 );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
- mStatus err;
- MDNSInterfaceItem * ifd;
-
- check( inMDNS );
- check( inMDNS->p );
- check( inName );
-
- // Search for an interface with the specified name,
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( strcmp( ifd->name, inName ) == 0 )
- {
- break;
- }
- }
- if( !ifd )
- {
- err = mStatus_NoSuchNameErr;
- goto exit;
- }
-
- // Success!
-
- if( outID )
- {
- *outID = (mDNSInterfaceID) ifd;
- }
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
- mStatus err;
- MDNSInterfaceItem * ifd;
-
- check( inMDNS );
- check( inID );
- check( outInfo );
-
- // Search for an interface with the specified ID,
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( ifd == (MDNSInterfaceItem *) inID )
- {
- break;
- }
- }
- if( !ifd )
- {
- err = mStatus_NoSuchNameErr;
- goto exit;
- }
-
- // Success!
-
- outInfo->name = ifd->name;
- outInfo->ip = ifd->hostSet.ip;
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// debugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS )
-mDNSexport void debugf_( const char *format, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, format );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), format, args );
- va_end( args );
-
- dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-// verbosedebugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS > 1 )
-mDNSexport void verbosedebugf_( const char *format, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, format );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), format, args );
- va_end( args );
-
- dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-// LogMsg
-//===========================================================================================================================
-
-void LogMsg( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, inFormat );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelWarning, "%s\n", buffer );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Internals ==
-#endif
-
-//===========================================================================================================================
-// SetupNames
-//===========================================================================================================================
-
-mDNSlocal void SetupNames( mDNS * const inMDNS )
-{
- char tempCString[ 128 ];
- mDNSu8 tempPString[ 128 ];
- mDNSu8 * namePtr;
-
- // Set up the host name.
-
- tempCString[ 0 ] = '\0';
- GenerateUniqueHostName( tempCString, NULL );
- check( tempCString[ 0 ] != '\0' );
- if( tempCString[ 0 ] == '\0' )
- {
- // No name so use the default.
-
- strcpy( tempCString, kMDNSDefaultName );
- }
- inMDNS->nicelabel.c[ 0 ] = strlen( tempCString );
- memcpy( &inMDNS->nicelabel.c[ 1 ], tempCString, inMDNS->nicelabel.c[ 0 ] );
- check( inMDNS->nicelabel.c[ 0 ] > 0 );
-
- // Set up the DNS name.
-
- tempCString[ 0 ] = '\0';
- GenerateUniqueDNSName( tempCString, NULL );
- if( tempCString[ 0 ] != '\0' )
- {
- tempPString[ 0 ] = strlen( tempCString );
- memcpy( &tempPString[ 1 ], tempCString, tempPString[ 0 ] );
- namePtr = tempPString;
- }
- else
- {
- // No DNS name so use the host name.
-
- namePtr = inMDNS->nicelabel.c;
- }
- ConvertUTF8PstringToRFC1034HostLabel( namePtr, &inMDNS->hostlabel );
- if( inMDNS->hostlabel.c[ 0 ] == 0 )
- {
- // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
-
- MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
- }
- check( inMDNS->hostlabel.c[ 0 ] > 0 );
-
- mDNS_SetFQDN( inMDNS );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
- dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
-}
-
-//===========================================================================================================================
-// SetupInterfaceList
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
-{
- mStatus err;
- struct ifaddrs * addrs;
- struct ifaddrs * p;
- uint32_t flagMask;
- uint32_t flagTest;
- MDNSInterfaceItem ** next;
- MDNSInterfaceItem * item;
-
- addrs = NULL;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list\n" );
- check( inMDNS );
-
- // Tear down any existing interfaces that may be set up.
-
- TearDownInterfaceList( inMDNS );
- inMDNS->p->interfaceList = NULL;
- next = &inMDNS->p->interfaceList;
-
- // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
-
- flagMask = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTOPOINT;
- flagTest = IFF_UP | IFF_MULTICAST;
-
- err = getifaddrs( &addrs );
- require_noerr( err, exit );
-
- for( p = addrs; p; p = p->ifa_next )
- {
- if( ( p->ifa_flags & flagMask ) == flagTest )
- {
- err = SetupInterface( inMDNS, p, &item );
- require_noerr( err, exit );
-
- *next = item;
- next = &item->next;
- }
- }
- err = mStatus_NoError;
-
-exit:
- if( addrs )
- {
- freeifaddrs( addrs );
- }
- if( err )
- {
- TearDownInterfaceList( inMDNS );
- }
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list done (err=%ld)\n", err );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownInterfaceList
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownInterfaceList( mDNS * const inMDNS )
-{
- dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list\n" );
- check( inMDNS );
-
- // Tear down all the interfaces.
-
- while( inMDNS->p->interfaceList )
- {
- MDNSInterfaceItem * item;
-
- item = inMDNS->p->interfaceList;
- inMDNS->p->interfaceList = item->next;
-
- TearDownInterface( inMDNS, item );
- }
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list done\n" );
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// SetupInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem )
-{
- mStatus err;
- MDNSInterfaceItem * item;
- MDNSSocketRef socketRef;
- const struct sockaddr_in * ipv4, *mask;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface (name=%s)\n", inAddr->ifa_name );
- check( inMDNS );
- check( inAddr );
- check( inAddr->ifa_addr );
- ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr;
- mask = (const struct sockaddr_in *) inAddr->ifa_netmask;
- check( outItem );
-
- // Allocate memory for the info item.
-
- item = (MDNSInterfaceItem *) calloc( 1, sizeof( *item ) );
- require_action( item, exit, err = mStatus_NoMemoryErr );
- strcpy( item->name, inAddr->ifa_name );
- item->multicastSocketRef = kInvalidSocketRef;
- item->sendingSocketRef = kInvalidSocketRef;
-
- // Set up the multicast DNS (port 5353) socket for this interface.
-
- err = SetupSocket( inMDNS, inAddr, MulticastDNSPort, &socketRef );
- require_noerr( err, exit );
- item->multicastSocketRef = socketRef;
-
- // Set up the sending socket for this interface.
-
- err = SetupSocket( inMDNS, inAddr, zeroIPPort, &socketRef );
- require_noerr( err, exit );
- item->sendingSocketRef = socketRef;
-
- // Register this interface with mDNS.
-
- item->hostSet.InterfaceID = (mDNSInterfaceID) item;
- item->hostSet.ip.type = mDNSAddrType_IPv4;
- item->hostSet.ip.ip.v4.NotAnInteger = ipv4->sin_addr.s_addr;
- item->hostSet.mask.type = mDNSAddrType_IPv4;
- item->hostSet.mask.ip.v4.NotAnInteger = mask->sin_addr.s_addr;
- item->hostSet.ifname[0] = 0;
- item->hostSet.Advertise = inMDNS->AdvertiseLocalAddresses;
- item->hostSet.McastTxRx = mDNStrue;
-
- err = mDNS_RegisterInterface( inMDNS, &item->hostSet, NormalActivation );
- require_noerr( err, exit );
- item->hostRegistered = mDNStrue;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Registered IP address: %u.%u.%u.%u\n",
- item->hostSet.ip.ip.v4.b[ 0 ], item->hostSet.ip.ip.v4.b[ 1 ],
- item->hostSet.ip.ip.v4.b[ 2 ], item->hostSet.ip.ip.v4.b[ 3 ] );
-
- // Success!
-
- *outItem = item;
- item = NULL;
-
-exit:
- if( item )
- {
- TearDownInterface( inMDNS, item );
- }
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface done (name=%s, err=%ld)\n", inAddr->ifa_name, err );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem )
-{
- MDNSSocketRef socketRef;
-
- check( inMDNS );
- check( inItem );
-
- // Deregister this interface with mDNS.
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering IP address: %u.%u.%u.%u\n",
- inItem->hostSet.ip.ip.v4.b[ 0 ], inItem->hostSet.ip.ip.v4.b[ 1 ],
- inItem->hostSet.ip.ip.v4.b[ 2 ], inItem->hostSet.ip.ip.v4.b[ 3 ] );
-
- if( inItem->hostRegistered )
- {
- inItem->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, NormalActivation );
- }
-
- // Close the multicast socket.
-
- socketRef = inItem->multicastSocketRef;
- inItem->multicastSocketRef = kInvalidSocketRef;
- if( socketRef != kInvalidSocketRef )
- {
- dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down multicast socket %d\n", socketRef );
- close( socketRef );
- }
-
- // Close the sending socket.
-
- socketRef = inItem->sendingSocketRef;
- inItem->sendingSocketRef = kInvalidSocketRef;
- if( socketRef != kInvalidSocketRef )
- {
- dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down sending socket %d\n", socketRef );
- close( socketRef );
- }
-
- // Free the memory used by the interface info.
-
- free( inItem );
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus
-SetupSocket(
- mDNS * const inMDNS,
- const struct ifaddrs * inAddr,
- mDNSIPPort inPort,
- MDNSSocketRef * outSocketRef )
-{
- mStatus err;
- MDNSSocketRef socketRef;
- int option;
- unsigned char optionByte;
- struct ip_mreq mreq;
- const struct sockaddr_in * ipv4;
- struct sockaddr_in addr;
- mDNSv4Addr ip;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done\n" );
- check( inMDNS );
- check( inAddr );
- check( inAddr->ifa_addr );
- ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr;
- check( outSocketRef );
-
- // Set up a UDP socket for multicast DNS.
-
- socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
- require_errno_action( socketRef, errno, exit, err = mStatus_UnknownErr );
-
- // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
- // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
- // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
- // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
- // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
-
- if( inPort.NotAnInteger != zeroIPPort.NotAnInteger )
- {
- // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
-
- option = 1;
- err = setsockopt( socketRef, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
- check_errno( err, errno );
-
- // Join the all-DNS multicast group so we receive Multicast DNS packets.
-
- ip.NotAnInteger = ipv4->sin_addr.s_addr;
- mreq.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- mreq.imr_interface.s_addr = ip.NotAnInteger;
- err = setsockopt( socketRef, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof( mreq ) );
- check_errno( err, errno );
-
- // Bind to the multicast DNS address and port 5353.
-
- mDNSPlatformMemZero( &addr, sizeof( addr ) );
- addr.sin_family = AF_INET;
- addr.sin_port = inPort.NotAnInteger;
- addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
- check_errno( err, errno );
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
- inAddr->ifa_name, ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], ntohs( inPort.NotAnInteger ), socketRef );
- }
- else
- {
- // Bind to the interface address and multicast DNS port.
-
- ip.NotAnInteger = ipv4->sin_addr.s_addr;
- mDNSPlatformMemZero( &addr, sizeof( addr ) );
- addr.sin_family = AF_INET;
- addr.sin_port = MulticastDNSPort.NotAnInteger;
- addr.sin_addr.s_addr = ip.NotAnInteger;
- err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
- check_errno( err, errno );
-
- // Direct multicast packets to the specified interface.
-
- addr.sin_addr.s_addr = ip.NotAnInteger;
- err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addr.sin_addr, sizeof( addr.sin_addr ) );
- check_errno( err, errno );
-
- // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( socketRef, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
- check_errno( err, errno );
-
- // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
-
- optionByte = 255;
- err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &optionByte, sizeof( optionByte ) );
- check_errno( err, errno );
-
- // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
- // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
-
-#if 0
- // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
-
- option = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
- err = setsockopt( socketRef, IPPROTO_IP, IP_TOS, (char *) &option, sizeof( option ) );
- check_errno( err, errno );
-#endif
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
- inAddr->ifa_name, ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], socketRef );
- }
-
- // Success!
-
- *outSocketRef = socketRef;
- socketRef = kInvalidSocketRef;
- err = mStatus_NoError;
-
-exit:
- if( socketRef != kInvalidSocketRef )
- {
- close( socketRef );
- }
- return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Commands ==
-#endif
-
-//===========================================================================================================================
-// SetupCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupCommandPipe( mDNS * const inMDNS )
-{
- mStatus err;
-
- // Clean up any leftover command pipe.
-
- TearDownCommandPipe( inMDNS );
-
- // Create the pipe device and open it.
-
- pipeDevCreate( kMDNSPipeName, kMDNSPipeMessageQueueSize, kMDNSPipeMessageSize );
-
- inMDNS->p->commandPipe = open( kMDNSPipeName, O_RDWR, 0 );
- require_errno_action( inMDNS->p->commandPipe, errno, exit, err = mStatus_UnsupportedErr );
-
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownCommandPipe( mDNS * const inMDNS )
-{
- if( inMDNS->p->commandPipe != ERROR )
- {
- close( inMDNS->p->commandPipe );
-#ifdef _WRS_VXWORKS_5_X
- // pipeDevDelete is not defined in older versions of VxWorks
- pipeDevDelete( kMDNSPipeName, FALSE );
-#endif
- inMDNS->p->commandPipe = ERROR;
- }
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// SendCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode )
-{
- mStatus err;
-
- require_action( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
-
- err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) );
- require_errno( err, errno, exit );
-
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ProcessCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus ProcessCommand( mDNS * const inMDNS )
-{
- mStatus err;
- MDNSPipeCommandCode commandCode;
-
- require_action( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
-
- // Read the command code from the pipe and dispatch it.
-
- err = read( inMDNS->p->commandPipe, &commandCode, sizeof( commandCode ) );
- require_errno( err, errno, exit );
-
- switch( commandCode )
- {
- case kMDNSPipeCommandCodeReschedule:
-
- // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
-
- dlog( kDebugLevelChatty, DEBUG_NAME "reschedule\n" );
- break;
-
- case kMDNSPipeCommandCodeReconfigure:
- ProcessCommandReconfigure( inMDNS );
- break;
-
- case kMDNSPipeCommandCodeQuit:
-
- // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "processing pipe quit command\n" );
- inMDNS->p->quit = mDNStrue;
- ++inMDNS->p->configID;
- break;
-
- default:
- dlog( kDebugLevelError, DEBUG_NAME "unknown pipe command code (code=0x%08X)\n", commandCode );
- err = mStatus_BadParamErr;
- goto exit;
- break;
- }
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// ProcessCommandReconfigure
-//===========================================================================================================================
-
-mDNSlocal void ProcessCommandReconfigure( mDNS *inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "processing pipe reconfigure command\n" );
-
- // Tear down the existing interfaces and set up new ones using the new IP info.
-
- mDNSPlatformLock( inMDNS );
-
- err = TearDownInterfaceList( inMDNS );
- check_noerr( err );
-
- err = SetupInterfaceList( inMDNS );
- check_noerr( err );
-
- mDNSPlatformUnlock( inMDNS );
-
- // Inform clients of the change.
-
- mDNS_ConfigChanged(m);
-
- // Force mDNS to update.
-
- 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.
-
- ++inMDNS->p->configID;
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Threads ==
-#endif
-
-//===========================================================================================================================
-// SetupTask
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupTask( mDNS * const inMDNS )
-{
- mStatus err;
- int task;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread\n" );
- check( inMDNS );
-
- // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
- // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
- // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
-
- task = taskSpawn( kMDNSTaskName, kMDNSTaskPriority, 0, kMDNSTaskStackSize, (FUNCPTR) Task,
- (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
- require_action( task != ERROR, exit, err = mStatus_NoMemoryErr );
-
- err = mStatus_NoError;
-
-exit:
- dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread done (err=%ld, id=%d)\n", err, task );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownTask
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownTask( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down thread\n" );
- check( inMDNS );
-
- // Send a quit command to cause the thread to exit.
-
- SendCommand( inMDNS, kMDNSPipeCommandCodeQuit );
-
- // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
-
- if( inMDNS->p->quitEvent )
- {
- err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 );
- check_noerr( err );
- }
- err = mStatus_NoError;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down thread done (err=%ld)\n", err );
- return( err );
-}
-
-//===========================================================================================================================
-// Task
-//===========================================================================================================================
-
-mDNSlocal void Task( mDNS *inMDNS )
-{
- mStatus err;
- fd_set allReadSet;
- MDNSInterfaceItem * item;
- int maxSocket;
- long configID;
- struct timeval timeout;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "task starting\n" );
- check( inMDNS );
-
- // Set up everything up.
-
- err = TaskInit( inMDNS );
- require_noerr( err, exit );
-
- // Main Processing Loop.
-
- while( !inMDNS->p->quit )
- {
- // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
- // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
-
- TaskSetupReadSet( inMDNS, &allReadSet, &maxSocket );
- configID = inMDNS->p->configID;
- dlog( kDebugLevelVerbose, DEBUG_NAME "task starting processing loop (configID=%ld)\n", configID );
-
- while( configID == inMDNS->p->configID )
- {
- mDNSs32 nextTaskTime;
- fd_set readSet;
- int n;
-
- // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
- // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
- // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
- // processing packets. This introduces a window for a race condition because the thread wake-up and
- // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
- // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
-
- inMDNS->p->rescheduled = 0;
- nextTaskTime = mDNS_Execute( inMDNS );
- TaskSetupTimeout( inMDNS, nextTaskTime, &timeout );
-
- // Wait until something occurs (e.g. command, incoming packet, or timeout).
-
- readSet = allReadSet;
- n = select( maxSocket + 1, &readSet, NULL, NULL, &timeout );
- inMDNS->p->rescheduled = 1;
- check_errno( n, errno );
- dlog( kDebugLevelChatty - 1, DEBUG_NAME "task select result = %d\n", n );
- if( n == 0 )
- {
- // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
-
- dlog( kDebugLevelChatty, DEBUG_NAME "next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS) );
- continue;
- }
-
- // Scan the read set to determine if any sockets have something pending and process them.
-
- n = 0;
- for( item = inMDNS->p->interfaceList; item; item = item->next )
- {
- if( FD_ISSET( item->multicastSocketRef, &readSet ) )
- {
- TaskProcessPacket( inMDNS, item, item->multicastSocketRef );
- ++n;
- }
- }
-
- // Check for a pending command and process it.
-
- if( FD_ISSET( inMDNS->p->commandPipe, &readSet ) )
- {
- ProcessCommand( inMDNS );
- ++n;
- }
- check( n > 0 );
- }
- }
-
-exit:
- // Signal we've quit.
-
- check( inMDNS->p->quitEvent );
- semGive( inMDNS->p->quitEvent );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "task ended\n" );
-}
-
-//===========================================================================================================================
-// TaskInit
-//===========================================================================================================================
-
-mDNSlocal mStatus TaskInit( mDNS *inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "task init\n" );
- check( inMDNS->p->readyEvent );
-
- inMDNS->p->task = taskIdSelf();
-
- err = SetupCommandPipe( inMDNS );
- require_noerr( err, exit );
-
- SetupNames( inMDNS );
-
- err = SetupInterfaceList( inMDNS );
- require_noerr( err, exit );
-
-exit:
- // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
-
- inMDNS->p->taskInitErr = err;
- semGive( inMDNS->p->readyEvent );
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "task init done (err=%ld)\n", err );
- return( err );
-}
-
-//===========================================================================================================================
-// TaskSetupReadSet
-//===========================================================================================================================
-
-mDNSlocal void TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket )
-{
- MDNSInterfaceItem * item;
- int maxSocket;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "task setting up read set\n" );
- check( inMDNS );
- check( outReadSet );
- check( outMaxSocket );
-
- // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
- // should never happen since we should always have at least one interface, but it's just to be safe.
-
- FD_ZERO( outReadSet );
- maxSocket = -1;
-
- // Add all the receiving sockets to the read set.
-
- for( item = inMDNS->p->interfaceList; item; item = item->next )
- {
- FD_SET( item->multicastSocketRef, outReadSet );
- if( item->multicastSocketRef > maxSocket )
- {
- maxSocket = item->multicastSocketRef;
- }
- }
-
- // Add the command pipe to the read set.
-
- FD_SET( inMDNS->p->commandPipe, outReadSet );
- if( inMDNS->p->commandPipe > maxSocket )
- {
- maxSocket = inMDNS->p->commandPipe;
- }
- check( maxSocket > 0 );
- *outMaxSocket = maxSocket;
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "task setting up read set done (maxSocket=%d)\n", maxSocket );
-}
-
-//===========================================================================================================================
-// TaskSetupTimeout
-//===========================================================================================================================
-
-mDNSlocal void TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout )
-{
- mDNSs32 delta;
-
- // Calculate how long to wait before performing idle processing.
-
- delta = inNextTaskTime - mDNS_TimeNow(inMDNS);
- if( delta <= 0 )
- {
- // The next task time is now or in the past. Set the timeout to fire immediately.
-
- outTimeout->tv_sec = 0;
- outTimeout->tv_usec = 0;
- }
- else
- {
- // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
- // before multiplying to account for integer rounding error and avoid firing the timeout too early.
-
- outTimeout->tv_sec = delta / mDNSPlatformOneSecond;
- outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicrosecondsMultiplier;
-
- // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
-
- if( outTimeout->tv_usec >= 1000000L )
- {
- outTimeout->tv_sec += 1;
- outTimeout->tv_usec = 0;
- }
- }
-
- dlog( kDebugLevelChatty, DEBUG_NAME "next task in %ld:%ld seconds (%ld)\n",
- outTimeout->tv_sec, outTimeout->tv_usec, inNextTaskTime );
-}
-//===========================================================================================================================
-// TaskProcessPacket
-//===========================================================================================================================
-
-mDNSlocal void TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef )
-{
- int n;
- DNSMessage packet;
- struct sockaddr_in addr;
- int addrSize;
- mDNSu8 * packetEndPtr;
- mDNSAddr srcAddr;
- mDNSIPPort srcPort;
- mDNSAddr dstAddr;
- mDNSIPPort dstPort;
-
- // Receive the packet.
-
- addrSize = sizeof( addr );
- n = recvfrom( inSocketRef, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
- check( n >= 0 );
- if( n >= 0 )
- {
- // Set up the src/dst/interface info.
-
- srcAddr.type = mDNSAddrType_IPv4;
- srcAddr.ip.v4.NotAnInteger = addr.sin_addr.s_addr;
- srcPort.NotAnInteger = addr.sin_port;
- dstAddr.type = mDNSAddrType_IPv4;
- dstAddr.ip.v4 = AllDNSLinkGroup_v4.ip.v4;
- dstPort = MulticastDNSPort;
-
- dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
- dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", n );
- dlog( kDebugLevelChatty, DEBUG_NAME " src = %u.%u.%u.%u:%hu\n",
- srcAddr.ip.v4.b[ 0 ], srcAddr.ip.v4.b[ 1 ], srcAddr.ip.v4.b[ 2 ], srcAddr.ip.v4.b[ 3 ],
- ntohs( srcPort.NotAnInteger ) );
- dlog( kDebugLevelChatty, DEBUG_NAME " dst = %u.%u.%u.%u:%hu\n",
- dstAddr.ip.v4.b[ 0 ], dstAddr.ip.v4.b[ 1 ], dstAddr.ip.v4.b[ 2 ], dstAddr.ip.v4.b[ 3 ],
- ntohs( dstPort.NotAnInteger ) );
- dlog( kDebugLevelChatty, DEBUG_NAME " interface = 0x%08X\n", (int) inItem->hostSet.InterfaceID );
- dlog( kDebugLevelChatty, DEBUG_NAME "--\n" );
-
- // Dispatch the packet to mDNS.
-
- packetEndPtr = ( (mDNSu8 *) &packet ) + n;
- mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inItem->hostSet.InterfaceID );
- }
-
- // Update counters.
-
- inItem->recvCounter += 1;
- inItem->recvErrorCounter += ( n < 0 );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-#if ( TARGET_NON_APPLE )
-//===========================================================================================================================
-// GenerateUniqueHostName
-//
-// Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
-//===========================================================================================================================
-
-mDNSlocal void GenerateUniqueHostName( char *outName, long *ioSeed )
-{
- DEBUG_UNUSED( ioSeed );
-
- // $$$ Non-Apple Platforms: Fill in appropriate name for device.
-
- mDNSPlatformStrCopy( outName, kMDNSDefaultName );
-}
-
-//===========================================================================================================================
-// GenerateUniqueDNSName
-//
-// Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
-// implemented to return a unique name.
-//===========================================================================================================================
-
-mDNSlocal void GenerateUniqueDNSName( char *outName, long *ioSeed )
-{
- DEBUG_UNUSED( ioSeed );
-
- // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
-
- mDNSPlatformStrCopy( outName, kMDNSDefaultName );
-}
-#endif
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// getifaddrs
-//===========================================================================================================================
-
-int getifaddrs( struct ifaddrs **outAddrs )
-{
- int err;
- struct ifaddrs * head;
- struct ifaddrs ** next;
- struct ifaddrs * ifa;
- int i;
- struct ifnet * ifp;
- char ipString[ INET_ADDR_LEN ];
- int n;
-
- head = NULL;
- next = &head;
-
- i = 1;
- for( ;; )
- {
- ifp = ifIndexToIfp( i );
- if( !ifp )
- {
- break;
- }
- ++i;
-
- // Allocate and initialize the ifaddrs structure and attach it to the linked list.
-
- ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
- require_action( ifa, exit, err = ENOMEM );
-
- *next = ifa;
- next = &ifa->ifa_next;
-
- // Fetch the name.
-
- ifa->ifa_name = (char *) malloc( 16 );
- require_action( ifa->ifa_name, exit, err = ENOMEM );
-
- n = sprintf( ifa->ifa_name, "%s%d", ifp->if_name, ifp->if_unit );
- require_action( n < 16, exit, err = ENOBUFS );
-
- // Fetch the address.
-
- ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( struct sockaddr_in ) );
- require_action( ifa->ifa_addr, exit, err = ENOMEM );
-
- ipString[ 0 ] = '\0';
- #if ( TARGET_NON_APPLE )
- err = ifAddrGet( ifa->ifa_name, ipString );
- require_noerr( err, exit );
- #else
- err = ifAddrGetNonAlias( ifa->ifa_name, ipString );
- require_noerr( err, exit );
- #endif
-
- err = sock_pton( ipString, AF_INET, ifa->ifa_addr, 0, NULL );
- require_noerr( err, exit );
-
- // Fetch flags.
-
- ifa->ifa_flags = ifp->if_flags;
- }
-
- // Success!
-
- if( outAddrs )
- {
- *outAddrs = head;
- head = NULL;
- }
- err = 0;
-
-exit:
- if( head )
- {
- freeifaddrs( head );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// freeifaddrs
-//===========================================================================================================================
-
-void freeifaddrs( struct ifaddrs *inAddrs )
-{
- struct ifaddrs * p;
- struct ifaddrs * q;
-
- // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
-
- for( p = inAddrs; p; p = q )
- {
- q = p->ifa_next;
-
- if( p->ifa_name )
- {
- free( p->ifa_name );
- p->ifa_name = NULL;
- }
- if( p->ifa_addr )
- {
- free( p->ifa_addr );
- p->ifa_addr = NULL;
- }
- if( p->ifa_netmask )
- {
- free( p->ifa_netmask );
- p->ifa_netmask = NULL;
- }
- if( p->ifa_dstaddr )
- {
- free( p->ifa_dstaddr );
- p->ifa_dstaddr = NULL;
- }
- if( p->ifa_data )
- {
- free( p->ifa_data );
- p->ifa_data = NULL;
- }
- free( p );
- }
-}
-
-//===========================================================================================================================
-// sock_pton
-//===========================================================================================================================
-
-int sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize )
-{
- int err;
-
- if( inFamily == AF_INET )
- {
- struct sockaddr_in * ipv4;
-
- if( inAddrSize == 0 )
- {
- inAddrSize = sizeof( struct sockaddr_in );
- }
- if( inAddrSize < sizeof( struct sockaddr_in ) )
- {
- err = EINVAL;
- goto exit;
- }
-
- ipv4 = (struct sockaddr_in *) outAddr;
- err = inet_aton( (char *) inString, &ipv4->sin_addr );
- if( err == 0 )
- {
- ipv4->sin_family = AF_INET;
- if( outAddrSize )
- {
- *outAddrSize = sizeof( struct sockaddr_in );
- }
- }
- }
-#if ( defined( AF_INET6 ) )
- else if( inFamily == AF_INET6 ) // $$$ TO DO: Add IPv6 support.
- {
- err = EAFNOSUPPORT;
- goto exit;
- }
-#endif
- else
- {
- err = EAFNOSUPPORT;
- goto exit;
- }
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// sock_ntop
-//===========================================================================================================================
-
-char * sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize )
-{
- const struct sockaddr * addr;
-
- addr = (const struct sockaddr *) inAddr;
- if( addr->sa_family == AF_INET )
- {
- struct sockaddr_in * ipv4;
-
- if( inAddrSize == 0 )
- {
- inAddrSize = sizeof( struct sockaddr_in );
- }
- if( inAddrSize < sizeof( struct sockaddr_in ) )
- {
- errno = EINVAL;
- inBuffer = NULL;
- goto exit;
- }
- if( inBufferSize < 16 )
- {
- errno = ENOBUFS;
- inBuffer = NULL;
- goto exit;
- }
-
- ipv4 = (struct sockaddr_in *) addr;
- inet_ntoa_b( ipv4->sin_addr, inBuffer );
- }
-#if ( defined( AF_INET6 ) )
- else if( addr->sa_family == AF_INET6 ) // $$$ TO DO: Add IPv6 support.
- {
- errno = EAFNOSUPPORT;
- inBuffer = NULL;
- goto exit;
- }
-#endif
- else
- {
- errno = EAFNOSUPPORT;
- inBuffer = NULL;
- goto exit;
- }
-
-exit:
- return( inBuffer );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Debugging ==
-#endif
-
-#if ( DEBUG )
-
-void mDNSShow( BOOL inShowRecords );
-void mDNSShowRecords( void );
-void mDNSShowTXT( const void *inTXT, size_t inTXTSize );
-
-//===========================================================================================================================
-// mDNSShow
-//===========================================================================================================================
-
-void mDNSShow( BOOL inShowRecords )
-{
- MDNSInterfaceItem * item;
- mDNSAddr ip;
- int n;
-
- if( !gMDNSPtr )
- {
- printf( "### mDNS not initialized\n" );
- return;
- }
-
- // Globals
-
- printf( "\n-- mDNS globals --\n" );
- printf( " sizeof( mDNS ) = %d\n", (int) sizeof( mDNS ) );
- printf( " sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord ) );
- printf( " sizeof( AuthRecord ) = %d\n", (int) sizeof( AuthRecord ) );
- printf( " sizeof( CacheRecord ) = %d\n", (int) sizeof( CacheRecord ) );
- printf( " gMDNSPtr = 0x%08lX\n", (unsigned long) gMDNSPtr );
- printf( " gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier );
- printf( " lockID = 0x%08lX\n", (unsigned long) gMDNSPtr->p->lockID );
- printf( " readyEvent = 0x%08lX\n", (unsigned long) gMDNSPtr->p->readyEvent );
- printf( " taskInitErr = %ld\n", gMDNSPtr->p->taskInitErr );
- printf( " quitEvent = 0x%08lX\n", (unsigned long) gMDNSPtr->p->quitEvent );
- printf( " commandPipe = %d\n", gMDNSPtr->p->commandPipe );
- printf( " task = 0x%08lX\n", (unsigned long) gMDNSPtr->p->task );
- printf( " quit = %d\n", gMDNSPtr->p->quit );
- printf( " configID = %ld\n", gMDNSPtr->p->configID );
- printf( " rescheduled = %d\n", gMDNSPtr->p->rescheduled );
- printf( " nicelabel = \"%.*s\"\n", gMDNSPtr->nicelabel.c[ 0 ], (char *) &gMDNSPtr->nicelabel.c[ 1 ] );
- printf( " hostLabel = \"%.*s\"\n", gMDNSPtr->hostlabel.c[ 0 ], (char *) &gMDNSPtr->hostlabel.c[ 1 ] );
- printf( "\n");
-
- // Interfaces
-
- printf( "\n-- mDNS interfaces --\n" );
- n = 1;
- for( item = gMDNSPtr->p->interfaceList; item; item = item->next )
- {
- printf( " -- interface %u --\n", n );
- printf( " name = \"%s\"\n", item->name );
- printf( " multicastSocketRef = %d\n", item->multicastSocketRef );
- printf( " sendingSocketRef = %d\n", item->sendingSocketRef );
- ip = item->hostSet.ip;
- printf( " hostSet.ip = %u.%u.%u.%u\n", ip.ip.v4.b[ 0 ], ip.ip.v4.b[ 1 ],
- ip.ip.v4.b[ 2 ], ip.ip.v4.b[ 3 ] );
- printf( " hostSet.advertise = %s\n", item->hostSet.Advertise ? "YES" : "NO" );
- printf( " hostRegistered = %s\n", item->hostRegistered ? "YES" : "NO" );
- printf( " --\n" );
- printf( " sendMulticastCounter = %d\n", item->sendMulticastCounter );
- printf( " sendUnicastCounter = %d\n", item->sendUnicastCounter );
- printf( " sendErrorCounter = %d\n", item->sendErrorCounter );
- printf( " recvCounter = %d\n", item->recvCounter );
- printf( " recvErrorCounter = %d\n", item->recvErrorCounter );
- printf( " recvLoopCounter = %d\n", item->recvLoopCounter );
- printf( "\n" );
- ++n;
- }
-
- // Resource Records
-
- if( inShowRecords )
- {
- mDNSShowRecords();
- }
-}
-
-//===========================================================================================================================
-// mDNSShowRecords
-//===========================================================================================================================
-
-void mDNSShowRecords( void )
-{
- MDNSInterfaceItem * item;
- int n;
- AuthRecord * record;
- char name[ MAX_ESCAPED_DOMAIN_NAME ];
-
- printf( "\n-- mDNS resource records --\n" );
- n = 1;
- for( record = gMDNSPtr->ResourceRecords; record; record = record->next )
- {
- item = (MDNSInterfaceItem *) record->resrec.InterfaceID;
- ConvertDomainNameToCString( &record->resrec.name, name );
- printf( " -- record %d --\n", n );
- printf( " interface = 0x%08X (%s)\n", (int) item, item ? item->name : "<any>" );
- printf( " name = \"%s\"\n", name );
- printf( "\n" );
- ++n;
- }
- printf( "\n");
-}
-
-//===========================================================================================================================
-// mDNSShowTXT
-//===========================================================================================================================
-
-void mDNSShowTXT( const void *inTXT, size_t inTXTSize )
-{
- const mDNSu8 * p;
- const mDNSu8 * end;
- int i;
- mDNSu8 size;
-
- printf( "\nTXT record (%u bytes):\n\n", inTXTSize );
-
- p = (const mDNSu8 *) inTXT;
- end = p + inTXTSize;
- i = 0;
-
- while( p < end )
- {
- size = *p++;
- if( ( p + size ) > end )
- {
- printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
- break;
- }
- printf( "%2d (%3d bytes): \"%.*s\"\n", i, size, size, p );
- p += size;
- ++i;
- }
- printf( "\n" );
-}
-#endif // DEBUG
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
- Contains: mDNS platform plugin for VxWorks.
-
- Copyright: Copyright (C) 2002-2003 Apple Computer, Inc., All Rights Reserved.
-
- */
-
-#ifndef __MDNS_VXWORKS__
-#define __MDNS_VXWORKS__
-
-#include "vxWorks.h"
-#include "semLib.h"
-
-#include "mDNSEmbeddedAPI.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Forward Declarations
-
-typedef struct MDNSInterfaceItem MDNSInterfaceItem;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct mDNS_PlatformSupport_struct
-
- @abstract Structure containing platform-specific data.
- */
-
-struct mDNS_PlatformSupport_struct
-{
- SEM_ID lockID;
- SEM_ID readyEvent;
- mStatus taskInitErr;
- SEM_ID quitEvent;
- MDNSInterfaceItem * interfaceList;
- int commandPipe;
- int task;
- mDNSBool quit;
- long configID;
- int rescheduled;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function mDNSReconfigure
-
- @abstract Tell mDNS that the configuration has changed. Call when IP address changes, link goes up after being down, etc.
-
- @discussion
-
- VxWorks does not provide a generic mechanism for getting notified when network interfaces change so this routines
- provides a way for BSP-specific code to signal mDNS that something has changed and it should re-build its interfaces.
- */
-
-void mDNSReconfigure( void );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct ifaddrs
-
- @abstract Interface information
- */
-
-struct ifaddrs
-{
- struct ifaddrs * ifa_next;
- char * ifa_name;
- u_int ifa_flags;
- struct sockaddr * ifa_addr;
- struct sockaddr * ifa_netmask;
- struct sockaddr * ifa_dstaddr;
- void * ifa_data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @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 );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function sock_pton
-
- @abstract Converts a 'p'resentation address string into a 'n'umeric sockaddr structure.
-
- @result 0 if successful or an error code on failure.
- */
-
-int sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @function sock_ntop
-
- @abstract Converts a 'n'umeric sockaddr structure into a 'p'resentation address string.
-
- @result Ptr to 'p'resentation address string buffer if successful or NULL on failure.
- */
-
-char * sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __MDNS_VXWORKS__
+++ /dev/null
-\r
-Microsoft Visual Studio Solution File, Format Version 11.00\r
-# Visual Studio 2010\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL", "DLL\dnssd.vcxproj", "{AB581101-18F0-46F6-B56A-83A6B1EA657E}"\r
-EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSResponder", "SystemService\Service.vcxproj", "{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"\r
-EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdnsNSP", "mdnsNSP\mdnsNSP.vcxproj", "{F4F15529-F0EB-402F-8662-73C5797EE557}"\r
-EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns-sd", "..\Clients\DNS-SD.VisualStudio\dns-sd.vcxproj", "{AA230639-E115-4A44-AA5A-44A61235BA50}"\r
- ProjectSection(ProjectDependencies) = postProject\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}\r
- EndProjectSection\r
-EndProject\r
-Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "BonjourQuickLooksInstaller", "BonjourQuickLooksInstaller\BonjourQuickLooksInstaller.wixproj", "{E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}"\r
-EndProject\r
-Global\r
- GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
- Debug|Win32 = Debug|Win32\r
- Debug|x64 = Debug|x64\r
- Debug|x86 = Debug|x86\r
- Release|Win32 = Release|Win32\r
- Release|x64 = Release|x64\r
- Release|x86 = Release|x86\r
- EndGlobalSection\r
- GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.ActiveCfg = Debug|Win32\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.Build.0 = Debug|Win32\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.ActiveCfg = Debug|x64\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.Build.0 = Debug|x64\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x86.ActiveCfg = Debug|Win32\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.ActiveCfg = Release|Win32\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.Build.0 = Release|Win32\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.ActiveCfg = Release|x64\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.Build.0 = Release|x64\r
- {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x86.ActiveCfg = Release|Win32\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.ActiveCfg = Debug|Win32\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.Build.0 = Debug|Win32\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.ActiveCfg = Debug|x64\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.Build.0 = Debug|x64\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x86.ActiveCfg = Debug|Win32\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.ActiveCfg = Release|Win32\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.Build.0 = Release|Win32\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.ActiveCfg = Release|x64\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.Build.0 = Release|x64\r
- {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x86.ActiveCfg = Release|Win32\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.ActiveCfg = Debug|Win32\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.Build.0 = Debug|Win32\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.ActiveCfg = Debug|x64\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.Build.0 = Debug|x64\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x86.ActiveCfg = Debug|Win32\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.ActiveCfg = Release|Win32\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.Build.0 = Release|Win32\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.ActiveCfg = Release|x64\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.Build.0 = Release|x64\r
- {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x86.ActiveCfg = Release|Win32\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.ActiveCfg = Debug|Win32\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.Build.0 = Debug|Win32\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.ActiveCfg = Debug|x64\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.Build.0 = Debug|x64\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x86.ActiveCfg = Debug|Win32\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.ActiveCfg = Release|Win32\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.Build.0 = Release|Win32\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.ActiveCfg = Release|x64\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.Build.0 = Release|x64\r
- {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x86.ActiveCfg = Release|Win32\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|Win32.ActiveCfg = Debug|x86\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x64.ActiveCfg = Debug|x64\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x64.Build.0 = Debug|x64\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x86.ActiveCfg = Debug|x86\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x86.Build.0 = Debug|x86\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|Win32.ActiveCfg = Release|x86\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x64.ActiveCfg = Release|x64\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x64.Build.0 = Release|x64\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x86.ActiveCfg = Release|x86\r
- {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x86.Build.0 = Release|x86\r
- EndGlobalSection\r
- GlobalSection(SolutionProperties) = preSolution\r
- HideSolutionNode = FALSE\r
- EndGlobalSection\r
-EndGlobal\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <PropertyGroup>\r
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
- <Platform Condition=" '$(Platform)' == '' ">x86</Platform>\r
- <ProductVersion>3.10</ProductVersion>\r
- <ProjectGuid>e24a4dc1-9b6f-4da4-bd76-7d5fe73732bf</ProjectGuid>\r
- <SchemaVersion>2.0</SchemaVersion>\r
- <OutputName>BonjourQuickLooks</OutputName>\r
- <OutputType>Package</OutputType>\r
- <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>\r
- <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>\r
- <Name>BonjourQuickLooksInstaller</Name>\r
- </PropertyGroup>\r
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">\r
- <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
- <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
- <DefineConstants>Debug</DefineConstants>\r
- </PropertyGroup>\r
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">\r
- <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
- <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
- </PropertyGroup>\r
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">\r
- <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
- <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
- <DefineConstants>Debug</DefineConstants>\r
- </PropertyGroup>\r
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">\r
- <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
- <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
- </PropertyGroup>\r
- <ItemGroup>\r
- <Compile Include="Product.wxs" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ProjectReference Include="..\..\Clients\DNS-SD.VisualStudio\dns-sd.vcxproj">\r
- <Name>dns-sd</Name>\r
- <Project>{aa230639-e115-4a44-aa5a-44a61235ba50}</Project>\r
- <Private>True</Private>\r
- <DoNotHarvest>True</DoNotHarvest>\r
- <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
- <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
- </ProjectReference>\r
- <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
- <Name>DLL</Name>\r
- <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
- <Private>True</Private>\r
- <DoNotHarvest>True</DoNotHarvest>\r
- <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
- <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
- </ProjectReference>\r
- <ProjectReference Include="..\mdnsNSP\mdnsNSP.vcxproj">\r
- <Name>mdnsNSP</Name>\r
- <Project>{f4f15529-f0eb-402f-8662-73c5797ee557}</Project>\r
- <Private>True</Private>\r
- <DoNotHarvest>True</DoNotHarvest>\r
- <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
- <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
- </ProjectReference>\r
- <ProjectReference Include="..\SystemService\Service.vcxproj">\r
- <Name>mDNSResponder</Name>\r
- <Project>{c1d98254-ba27-4427-a3be-a68ca2cc5f69}</Project>\r
- <Private>True</Private>\r
- <DoNotHarvest>True</DoNotHarvest>\r
- <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
- <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
- </ProjectReference>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <WixExtension Include="WixFirewallExtension">\r
- <HintPath>$(WixExtDir)\WixFirewallExtension.dll</HintPath>\r
- <Name>WixFirewallExtension</Name>\r
- </WixExtension>\r
- </ItemGroup>\r
- <Import Project="$(WixTargetsPath)" />\r
- <!--\r
- To modify your build process, add your task inside one of the targets below and uncomment it.\r
- Other similar extension points exist, see Wix.targets.\r
- <Target Name="BeforeBuild">\r
- </Target>\r
- <Target Name="AfterBuild">\r
- </Target>\r
- -->\r
-</Project>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- Copyright (c) 2016 Apple Inc. All rights reserved. -->
-
-<Wix xmlns = "http://schemas.microsoft.com/wix/2006/wi"
- xmlns:fire = "http://schemas.microsoft.com/wix/FirewallExtension" >
-
- <?define ProductManufacturer = "Apple Inc."?>
- <?define ProductName = "Bonjour (QuickLooks Testing)"?>
- <?define UpgradeCode = "46AE3251-43D6-41CF-8CDF-E902C38516D1"?>
- <?define ProductVersion = "1.0.0"?>
- <?define ProductVersionMarketing = "1.0.0"?>
- <?if $(var.Platform) = x64?>
- <?define Win64 = "yes" ?>
- <?define PlatformSystemFolder = "System64Folder"?>
- <?define PlatformProgramFilesFolder = "ProgramFiles64Folder"?>
- <?define PlatformInstallDir = "INSTALLDIR64"?>
- <?define GUID_DNSSDExe = "528ACC12-D4A8-11DE-927F-58D855D89593"?>
- <?define GUID_DNSSDDLL = "20F30EC6-1F92-11DC-8314-0800200C9A66"?>
- <?define GUID_MDNSNSPDLL = "255EBC6C-1F92-11DC-8314-0800200C9A66"?>
- <?define GUID_MDNSResponderExe = "BB3076CA-D4DF-11E0-8AC8-AA0E4824019B"?>
- <?else?>
- <?define Win64 = "no" ?>
- <?define PlatformSystemFolder = "SystemFolder"?>
- <?define PlatformProgramFilesFolder = "ProgramFilesFolder"?>
- <?define PlatformInstallDir = "INSTALLDIR"?>
- <?define GUID_DNSSDExe = "DCA08E52-8D4E-43AF-A0F7-9B809FCCFEBF"?>
- <?define GUID_DNSSDDLL = "E6B826D2-6338-4822-8DEA-EC03C2CA41A7"?>
- <?define GUID_MDNSNSPDLL = "0E416468-0A21-4778-BE61-64AAA5BE1039"?>
- <?define GUID_MDNSResponderExe = "836FE314-37A7-4905-90F0-AFE25F315CA3"?>
- <?endif?>
- <?define GUID_InstallerCache = "EDD5CC92-97D7-4364-9CA6-F7001C75A90E"?>
-
- <Product
- Id = "*"
- Language = "1033"
- Manufacturer = "$(var.ProductManufacturer)"
- Name = "$(var.ProductName)"
- UpgradeCode = "$(var.UpgradeCode)"
- Version = "$(var.ProductVersion)" >
-
- <Package
- Keywords = "Installer,MSI"
- Comments = "$(var.ProductName) $(var.ProductVersion)"
- Compressed = "yes"
- Description = "[ProductName] Installer"
- InstallerVersion = "300"
- Languages = "1033"
- Manufacturer = "$(var.ProductManufacturer)"
- SummaryCodepage = "1252" />
-
- <!-- Launch Conditions -->
- <Condition
- Message = "You do not have sufficient privileges to complete this installation for all users of the machine. Log on as an administrator and then retry this installation." >
- <![CDATA[Privileged]]>
- </Condition>
- <Condition
- Message = "[ProductName] requires that your computer is running Windows XP SP2 or newer.">
- <![CDATA[((VersionNT=501 AND ServicePackLevel>=2) OR VersionNT>501)]]>
- </Condition>
- <?if $(var.Win64) = "no"?>
- <Condition
- Message = "This installer is intended for 32-bit versions of Windows" >
- <![CDATA[NOT VersionNT64]]>
- </Condition>
- <?endif?>
-
- <!-- Directory Table -->
- <Directory Id="TARGETDIR" Name="SourceDir">
- <Directory Id="$(var.PlatformSystemFolder)" />
- <Directory Id="$(var.PlatformProgramFilesFolder)">
- <Directory Id="Bonjour64InstallFolder" Name="Bonjour">
- <Directory Id="$(var.PlatformInstallDir)" />
- </Directory>
- </Directory>
- <Directory Id="DesktopFolder" />
- <Directory Id="CommonAppDataFolder" Name="Application Data">
- <Directory Id="AppleCommonAppDataFolder" Name="Apple">
- <Directory Id="CachedInstallationsFolder" Name="Installer Cache">
- <Directory Id="INSTALLERCACHE" Name="$(var.ProductName) $(var.ProductVersion)" />
- </Directory>
- </Directory>
- </Directory>
- </Directory>
-
- <!-- Features -->
- <Feature Id="Bonjour" Title="Bonjour" Level="1" AllowAdvertise="no" Display="expand">
- <ComponentRef Id="InstallerCache" />
- <Feature Id="mDNSResponder" Title="mDNSResponder" Level="1" AllowAdvertise="no" Absent="disallow">
- <ComponentRef Id="dns_sd.exe" />
- <ComponentRef Id="dnssd.dll" />
- <ComponentRef Id="mdnsNSP.dll" />
- <ComponentRef Id="mDNSResponder.exe" />
- </Feature>
- </Feature>
-
- <!-- InstallerCache -->
- <DirectoryRef Id="INSTALLERCACHE">
- <Component Id="InstallerCache" Guid="$(var.GUID_InstallerCache)" KeyPath="yes">
- <Condition><![CDATA[NOT DONTCACHEMSI]]></Condition>
- <CreateFolder />
- <CopyFile Id="BonjourQuickLooks.msi" SourceProperty="SourceDir" SourceName="BonjourQuickLooks.msi" DestinationDirectory="INSTALLERCACHE" />
- <RemoveFile Id="BonjourQuickLooks.msi" Directory="INSTALLERCACHE" Name="BonjourQuickLooks.msi" On="uninstall" />
- <RemoveFolder Id="INSTALLERCACHE" Directory="INSTALLERCACHE" On="uninstall" />
- </Component>
- </DirectoryRef>
-
- <!-- Bonjour -->
- <DirectoryRef Id="$(var.PlatformSystemFolder)">
- <Component Id="dns_sd.exe" Guid="$(var.GUID_DNSSDExe)" Win64="$(var.Win64)">
- <File Id="dns_sd.exe" Name="dns-sd.exe" KeyPath="yes" Source="$(var.dns-sd.TargetPath)" />
- </Component>
- <Component Id="dnssd.dll" Guid="$(var.GUID_DNSSDDLL)" Win64="$(var.Win64)">
- <File Id="dnssd.dll" Name="dnssd.dll" KeyPath="yes" Source="$(var.DLL.TargetPath)" />
- </Component>
- </DirectoryRef>
-
- <DirectoryRef Id="$(var.PlatformInstallDir)">
- <Component Id="mdnsNSP.dll" Guid="$(var.GUID_MDNSNSPDLL)" Win64="$(var.Win64)">
- <File Id="mdnsNSP.dll" Name="mdnsNSP.dll" Source="$(var.mdnsNSP.TargetPath)" KeyPath="yes" SelfRegCost="1024" />
- </Component>
- <Component Id="mDNSResponder.exe" Guid="$(var.GUID_MDNSResponderExe)" Win64="$(var.Win64)">
- <File Id="mDNSResponder.exe" Name="mDNSResponder.exe" Source="$(var.mDNSResponder.TargetPath)" KeyPath="yes">
- <fire:FirewallException Id="mDNSException1" Name="Bonjour Service" IgnoreFailure="yes" Scope="any" />
- </File>
- <ServiceInstall
- Id = "BonjourService"
- Name = "Bonjour Service"
- DisplayName = "Bonjour Service"
- Description = "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence."
- Start = "auto"
- Type = "ownProcess"
- ErrorControl = "normal"
- Vital = "yes" >
- <ServiceDependency Id="Tcpip" Group="no" />
- </ServiceInstall>
- <ServiceControl
- Id = "BonjourService"
- Name = "Bonjour Service"
- Start = "install"
- Stop = "both"
- Remove = "uninstall"
- Wait = "yes" />
- <RegistryValue
- Name = "ManageLLRouting"
- Root = "HKLM"
- Key = "SYSTEM\CurrentControlSet\Services\Bonjour Service\Parameters"
- Type = "integer"
- Value = "1" />
- <RegistryKey
- Root = "HKLM"
- Key = "SOFTWARE\Apple Inc.\Bonjour"
- Action = "createAndRemoveOnUninstall" >
- <RegistryValue
- Name = "InstallDir"
- Type = "string"
- Value = "[$(var.PlatformInstallDir)]" />
- <RegistryValue
- Name = "Version"
- Type = "string"
- Value = "$(var.ProductVersion)" />
- </RegistryKey>
- </Component>
- </DirectoryRef>
-
- <!-- Media -->
- <Media Id="1" EmbedCab="yes" Cabinet="BonjourQuickLooks.cab" CompressionLevel="high" />
-
- <!-- Properties -->
- <Property Id="ALLUSERS" Value="1" />
- <Property Id="ARPNOMODIFY" Value="1" />
- <Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
-
- <MajorUpgrade AllowDowngrades="yes" Schedule="afterInstallValidate" />
- </Product>
-</Wix>
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BrowsingPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-
-#include <WinServices.h>
-
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CBrowsingPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::CBrowsingPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CBrowsingPage::CBrowsingPage()
-:
- CPropertyPage(CBrowsingPage::IDD)
-{
- //{{AFX_DATA_INIT(CBrowsingPage)
- //}}AFX_DATA_INIT
-
- m_firstTime = true;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::~CBrowsingPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CBrowsingPage::~CBrowsingPage()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CBrowsingPage::DoDataExchange(CDataExchange* pDX)
-{
- CPropertyPage::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CBrowsingPage)
- //}}AFX_DATA_MAP
- DDX_Control(pDX, IDC_BROWSE_LIST, m_browseListCtrl);
- DDX_Control(pDX, IDC_REMOVE_BROWSE_DOMAIN, m_removeButton);
-}
-
-BEGIN_MESSAGE_MAP(CBrowsingPage, CPropertyPage)
- //{{AFX_MSG_MAP(CBrowsingPage)
- //}}AFX_MSG_MAP
- ON_BN_CLICKED(IDC_ADD_BROWSE_DOMAIN, OnBnClickedAddBrowseDomain)
- ON_BN_CLICKED(IDC_REMOVE_BROWSE_DOMAIN, OnBnClickedRemoveBrowseDomain)
- ON_NOTIFY(LVN_ITEMCHANGED, IDC_BROWSE_LIST, OnLvnItemchangedBrowseList)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CBrowsingPage::SetModified( BOOL bChanged )
-{
- m_modified = bChanged;
-
- CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CBrowsingPage::OnSetActive()
-{
- CConfigPropertySheet * psheet;
- HKEY key = NULL;
- HKEY subKey = NULL;
- DWORD dwSize;
- DWORD enabled;
- DWORD err;
- TCHAR subKeyName[MAX_KEY_LENGTH];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- int nIndex;
- DWORD i;
- BOOL b = CPropertyPage::OnSetActive();
-
- psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
- require_quiet( psheet, exit );
-
- m_modified = FALSE;
-
- if ( m_firstTime )
- {
- m_browseListCtrl.SetExtendedStyle((m_browseListCtrl.GetStyle() & (~LVS_EX_GRIDLINES))|LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
-
- m_browseListCtrl.InsertColumn(0, L"", LVCFMT_LEFT, 20 );
- m_browseListCtrl.InsertColumn(1, L"", LVCFMT_LEFT, 345);
-
- m_firstTime = false;
- }
-
- m_initialized = false;
-
- // Clear out what's there
-
- m_browseListCtrl.DeleteAllItems();
-
- // Now populate the browse domain box
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- // Get information about this node
-
- err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- for ( i = 0; i < cSubKeys; i++)
- {
- dwSize = MAX_KEY_LENGTH;
-
- err = RegEnumKeyEx( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- err = RegOpenKey( key, subKeyName, &subKey );
- require_noerr( err, exit );
-
- dwSize = sizeof( DWORD );
- err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
- require_noerr( err, exit );
-
- nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
- m_browseListCtrl.SetItemText( nIndex, 1, subKeyName );
- m_browseListCtrl.SetCheck( nIndex, enabled );
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
-
- m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
-
- m_removeButton.EnableWindow( FALSE );
-
-exit:
-
- if ( subKey )
- {
- RegCloseKey( subKey );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- m_initialized = true;
-
- return b;
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::OnOK()
-{
- if ( m_modified )
- {
- Commit();
- }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::Commit()
-{
- HKEY key = NULL;
- HKEY subKey = NULL;
- TCHAR subKeyName[MAX_KEY_LENGTH];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- DWORD dwSize;
- int i;
- DWORD err;
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- // First, remove all the entries that are there
-
- err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- for ( i = 0; i < (int) cSubKeys; i++ )
- {
- dwSize = MAX_KEY_LENGTH;
-
- err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- err = RegDeleteKey( key, subKeyName );
- require_noerr( err, exit );
- }
-
- // Now re-populate
-
- for ( i = 0; i < m_browseListCtrl.GetItemCount(); i++ )
- {
- DWORD enabled = (DWORD) m_browseListCtrl.GetCheck( i );
-
- err = RegCreateKeyEx( key, m_browseListCtrl.GetItemText( i, 1 ), 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &subKey, NULL );
- require_noerr( err, exit );
-
- err = RegSetValueEx( subKey, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
- require_noerr( err, exit );
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
-
-exit:
-
- if ( subKey )
- {
- RegCloseKey( subKey );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::OnBnClickedAddBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::OnBnClickedAddBrowseDomain()
-{
- CAddBrowseDomain dlg( GetParent() );
-
- if ( ( dlg.DoModal() == IDOK ) && ( dlg.m_text.GetLength() > 0 ) )
- {
- int nIndex;
-
- nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
- m_browseListCtrl.SetItemText( nIndex, 1, dlg.m_text );
- m_browseListCtrl.SetCheck( nIndex, 1 );
-
- m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
-
- m_browseListCtrl.Invalidate();
-
- SetModified( TRUE );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage::OnBnClickedRemoveBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::OnBnClickedRemoveBrowseDomain()
-{
- UINT selectedCount = m_browseListCtrl.GetSelectedCount();
- int nItem = -1;
- UINT i;
-
- // Update all of the selected items.
-
- for ( i = 0; i < selectedCount; i++ )
- {
- nItem = m_browseListCtrl.GetNextItem( -1, LVNI_SELECTED );
- check( nItem != -1 );
-
- m_browseListCtrl.DeleteItem( nItem );
-
- SetModified( TRUE );
- }
-
- m_removeButton.EnableWindow( FALSE );
-}
-
-
-void
-CBrowsingPage::OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
-{
- if ( m_browseListCtrl.GetSelectedCount() )
- {
- m_removeButton.EnableWindow( TRUE );
- }
-
- if ( m_initialized )
- {
- NM_LISTVIEW * pNMListView = (NM_LISTVIEW*)pNMHDR;
-
- BOOL bPrevState = (BOOL) ( ( ( pNMListView->uOldState & LVIS_STATEIMAGEMASK ) >> 12 ) - 1 );
-
- if ( bPrevState < 0 )
- {
- bPrevState = 0;
- }
-
-
- BOOL bChecked = ( BOOL ) ( ( ( pNMListView->uNewState & LVIS_STATEIMAGEMASK ) >> 12) - 1 );
-
- if ( bChecked < 0 )
- {
- bChecked = 0;
- }
-
- if ( bPrevState != bChecked )
- {
- SetModified( TRUE );
- }
- }
-
- *pResult = 0;
-}
-
-
-
-int CALLBACK
-CBrowsingPage::SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
-{
- CString str1;
- CString str2;
- int ret = 0;
-
- CBrowsingPage * self = reinterpret_cast<CBrowsingPage*>( lParamSort );
- require_quiet( self, exit );
-
- str1 = self->m_browseListCtrl.GetItemText( (int) lParam1, 1 );
- str2 = self->m_browseListCtrl.GetItemText( (int) lParam2, 1 );
-
- ret = str1.Compare( str2 );
-
-exit:
-
- return ret;
-}
-
-
-// CAddBrowseDomain dialog
-
-IMPLEMENT_DYNAMIC(CAddBrowseDomain, CDialog)
-CAddBrowseDomain::CAddBrowseDomain(CWnd* pParent /*=NULL*/)
- : CDialog(CAddBrowseDomain::IDD, pParent)
-{
-}
-
-CAddBrowseDomain::~CAddBrowseDomain()
-{
-}
-
-void CAddBrowseDomain::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- DDX_Control(pDX, IDC_COMBO1, m_comboBox);
-}
-
-
-BOOL
-CAddBrowseDomain::OnInitDialog()
-{
- CConfigPropertySheet * psheet;
- CConfigPropertySheet::StringList::iterator it;
-
- BOOL b = CDialog::OnInitDialog();
-
- psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
- require_quiet( psheet, exit );
-
- for ( it = psheet->m_browseDomains.begin(); it != psheet->m_browseDomains.end(); it++ )
- {
- CString text = *it;
-
- if ( m_comboBox.FindStringExact( -1, *it ) == CB_ERR )
- {
- m_comboBox.AddString( *it );
- }
- }
-
-exit:
-
- return b;
-}
-
-
-void
-CAddBrowseDomain::OnOK()
-{
- m_comboBox.GetWindowText( m_text );
-
- CDialog::OnOK();
-}
-
-
-
-BEGIN_MESSAGE_MAP(CAddBrowseDomain, CDialog)
-END_MESSAGE_MAP()
-
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#include "afxcmn.h"
-
-#include "afxwin.h"
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CBrowsingPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CBrowsingPage : public CPropertyPage
-{
-public:
- CBrowsingPage();
- ~CBrowsingPage();
-
-protected:
-
- //{{AFX_DATA(CBrowsingPage)
- enum { IDD = IDR_APPLET_PAGE3 };
- //}}AFX_DATA
-
- //{{AFX_VIRTUAL(CBrowsingPage)
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- DECLARE_DYNCREATE(CBrowsingPage)
-
- //{{AFX_MSG(CBrowsingPage)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
-private:
-
- typedef std::list<CString> StringList;
-
- afx_msg BOOL
- OnSetActive();
-
- afx_msg void
- OnOK();
-
- void
- SetModified( BOOL bChanged = TRUE );
-
- void
- Commit();
-
- BOOL m_modified;
-
-public:
-private:
-
- static int CALLBACK
-
- SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
-
-
-
- CListCtrl m_browseListCtrl;
-
- bool m_initialized;
-
- bool m_firstTime;
-
-
-
-public:
-
-
-
- afx_msg void OnBnClickedAddBrowseDomain();
-
- afx_msg void OnBnClickedRemoveBrowseDomain();
-
- afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
-
- CButton m_removeButton;
-
-};
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CAddBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-
-class CAddBrowseDomain : public CDialog
-
-{
-
- DECLARE_DYNAMIC(CAddBrowseDomain)
-
-
-
-public:
-
- CAddBrowseDomain(CWnd* pParent = NULL); // standard constructor
-
- virtual ~CAddBrowseDomain();
-
-
-
-// Dialog Data
-
- enum { IDD = IDR_ADD_BROWSE_DOMAIN };
-
-
-
-protected:
-
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
-
- virtual BOOL OnInitDialog();
-
- virtual void OnOK();
-
- DECLARE_MESSAGE_MAP()
-
-public:
-
- CComboBox m_comboBox;
-
- CString m_text;
-
-};
-
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "ConfigDialog.h"
-#include "ControlPanel.h"
-
-
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-IMPLEMENT_DYNCREATE(CConfigDialog, CDialog)
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigDialog::CConfigDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-CConfigDialog::CConfigDialog()
- : CDialog(CConfigDialog::IDD, NULL)
-{
- //{{AFX_DATA_INIT(CConfigDialog)
- //}}AFX_DATA_INIT
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigDialog::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CConfigDialog::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CConfigDialog)
- //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CConfigDialog, CDialog)
- //{{AFX_MSG_MAP(CConfigDialog)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CConfigDialog : public CDialog
-{
-public:
-
- CConfigDialog();
-
-protected:
-
- //{{AFX_DATA(CConfigDialog)
- enum { IDD = IDR_APPLET };
- //}}AFX_DATA
-
- //{{AFX_VIRTUAL(CConfigDialog)
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- //{{AFX_MSG(CConfigDialog)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
- DECLARE_DYNCREATE(CConfigDialog)
-};
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ConfigPropertySheet.h"
-#include <WinServices.h>
-extern "C"
-{
-#include <ClientCommon.h>
-}
-#include <process.h>
-
-// Custom events
-
-#define WM_DATAREADY ( WM_USER + 0x100 )
-
-
-IMPLEMENT_DYNCREATE(CConfigPropertySheet, CPropertySheet)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::CConfigPropertySheet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CConfigPropertySheet::CConfigPropertySheet()
-:
- CPropertySheet(),
- m_browseDomainsRef( NULL ),
- m_thread( NULL ),
- m_threadExited( NULL )
-{
- AddPage(&m_firstPage );
- AddPage(&m_secondPage);
- AddPage(&m_thirdPage);
-
- InitializeCriticalSection( &m_lock );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::~CConfigPropertySheet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CConfigPropertySheet::~CConfigPropertySheet()
-{
- DeleteCriticalSection( &m_lock );
-}
-
-
-BEGIN_MESSAGE_MAP(CConfigPropertySheet, CPropertySheet)
- //{{AFX_MSG_MAP(CConfigPropertySheet)
- //}}AFX_MSG_MAP
- ON_MESSAGE( WM_DATAREADY, OnDataReady )
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::OnInitDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CConfigPropertySheet::OnInitDialog()
-{
- OSStatus err;
-
- BOOL b = CPropertySheet::OnInitDialog();
-
- err = SetupBrowsing();
- require_noerr( err, exit );
-
-exit:
-
- return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::OnCommand
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CConfigPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
-{
- // Check if OK or Cancel was hit
-
- if ( ( wParam == ID_WIZFINISH ) || ( wParam == IDOK ) || ( wParam == IDCANCEL ) )
- {
- OnEndDialog();
- }
-
- return CPropertySheet::OnCommand(wParam, lParam);
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::OnDataReady
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam)
-{
- if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
- {
- dlog( kDebugLevelError, "OnSocket: window error\n" );
- }
- else
- {
- SOCKET sock = (SOCKET) inWParam;
-
- if ( m_browseDomainsRef && DNSServiceRefSockFD( m_browseDomainsRef ) == (int) sock )
- {
- DNSServiceProcessResult( m_browseDomainsRef );
- }
- }
-
- return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::OnEndDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CConfigPropertySheet::OnEndDialog()
-{
- OSStatus err;
-
- err = TearDownBrowsing();
- check_noerr( err );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::SetupBrowsing
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::SetupBrowsing()
-{
- OSStatus err;
-
- // Start browsing for browse domains
-
- err = DNSServiceEnumerateDomains( &m_browseDomainsRef, kDNSServiceFlagsBrowseDomains, 0, BrowseDomainsReply, this );
- require_noerr( err, exit );
-
- err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
- require_noerr( err, exit );
-
-exit:
-
- if ( err )
- {
- TearDownBrowsing();
- }
-
- return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::TearDownBrowsing
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::TearDownBrowsing()
-{
- OSStatus err = kNoErr;
-
- if ( m_browseDomainsRef )
- {
- err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, 0, 0 );
- check_noerr( err );
-
- DNSServiceRefDeallocate( m_browseDomainsRef );
-
- m_browseDomainsRef = NULL;
- }
-
- return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::DecodeDomainName
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded )
-{
- char nextLabel[128] = "\0";
- char decodedDomainString[kDNSServiceMaxDomainName];
- char * buffer = (char *) raw;
- int labels = 0, i;
- char text[64];
- const char *label[128];
- OSStatus err;
-
- // Initialize
-
- decodedDomainString[0] = '\0';
-
- // Count the labels
-
- while ( *buffer )
- {
- label[labels++] = buffer;
- buffer = (char *) GetNextLabel(buffer, text);
- }
-
- buffer = (char*) raw;
-
- for (i = 0; i < labels; i++)
- {
- buffer = (char *)GetNextLabel(buffer, nextLabel);
- strcat_s(decodedDomainString, sizeof(decodedDomainString), nextLabel);
- strcat_s(decodedDomainString, sizeof(decodedDomainString), ".");
- }
-
- // Remove trailing dot from domain name.
-
- decodedDomainString[ strlen( decodedDomainString ) - 1 ] = '\0';
-
- // Convert to Unicode
-
- err = UTF8StringToStringObject( decodedDomainString, decoded );
-
- return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet::BrowseDomainsReply
-//---------------------------------------------------------------------------------------------------------------------------
-
-void DNSSD_API
-CConfigPropertySheet::BrowseDomainsReply
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * replyDomain,
- void * context
- )
-{
- CConfigPropertySheet * self = reinterpret_cast<CConfigPropertySheet*>(context);
- CString decoded;
- OSStatus err;
-
- DEBUG_UNUSED( sdRef );
- DEBUG_UNUSED( interfaceIndex );
-
- if ( errorCode )
- {
- goto exit;
- }
-
- check( replyDomain );
-
- // Ignore local domains
-
- if ( strcmp( replyDomain, "local." ) == 0 )
- {
- goto exit;
- }
-
- err = self->DecodeDomainName( replyDomain, decoded );
- require_noerr( err, exit );
-
- // Remove trailing '.'
-
- decoded.TrimRight( '.' );
-
- if ( flags & kDNSServiceFlagsAdd )
- {
- self->m_browseDomains.push_back( decoded );
- }
- else
- {
- self->m_browseDomains.remove( decoded );
- }
-
-exit:
-
- return;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef _ConfigPropertySheet_h
-#define _ConfigPropertySheet_h
-
-#include "stdafx.h"
-#include "ServicesPage.h"
-#include "RegistrationPage.h"
-#include "BrowsingPage.h"
-
-#include <RegNames.h>
-#include <dns_sd.h>
-#include <list>
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CConfigPropertySheet
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CConfigPropertySheet : public CPropertySheet
-{
-public:
-
- CConfigPropertySheet();
- virtual ~CConfigPropertySheet();
-
- typedef std::list<CString> StringList;
-
- StringList m_browseDomains;
-
-protected:
-
- CServicesPage m_firstPage;
- CRegistrationPage m_secondPage;
- CBrowsingPage m_thirdPage;
-
- //{{AFX_VIRTUAL(CConfigPropertySheet)
- //}}AFX_VIRTUAL
-
- DECLARE_DYNCREATE(CConfigPropertySheet)
-
- //{{AFX_MSG(CConfigPropertySheet)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
- afx_msg BOOL OnInitDialog();
- afx_msg BOOL OnCommand( WPARAM wParam, LPARAM lParam );
- afx_msg LRESULT OnDataReady( WPARAM inWParam, LPARAM inLParam );
- afx_msg LRESULT OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );
- void OnEndDialog();
-
-private:
-
- OSStatus
- SetupBrowsing();
-
- OSStatus
- TearDownBrowsing();
-
- OSStatus
- DecodeDomainName( const char * raw, CString & decoded );
-
- static void DNSSD_API
- BrowseDomainsReply
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * replyDomain,
- void * context
- );
-
- // This thread will watch for registry changes
-
- static unsigned WINAPI
- WatchRegistry
- (
- LPVOID inParam
- );
-
- HKEY m_statusKey;
- HANDLE m_thread;
- HANDLE m_threadExited;
- DNSServiceRef m_browseDomainsRef;
- CRITICAL_SECTION m_lock;
-};
-
-
-#endif
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "ControlPanel.h"
-#include "ConfigDialog.h"
-#include "ConfigPropertySheet.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-
-static CCPApp theApp;
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// GetControlPanelApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp*
-GetControlPanelApp()
-{
- CCPApp * pApp = (CCPApp*) AfxGetApp();
-
- check( pApp );
- check( pApp->IsKindOf( RUNTIME_CLASS( CCPApp ) ) );
-
- return pApp;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CPlApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-LONG APIENTRY
-CPlApplet(HWND hWndCPl, UINT uMsg, LONG lParam1, LONG lParam2)
-{
- AFX_MANAGE_STATE(AfxGetStaticModuleState());
-
- CCPApp * pApp = GetControlPanelApp();
-
- return ( LONG ) pApp->OnCplMsg(hWndCPl, uMsg, lParam1, lParam2);
-}
-
-
-IMPLEMENT_DYNAMIC(CCPApplet, CCmdTarget);
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::CCPApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApplet::CCPApplet(UINT resourceId, UINT descId, CRuntimeClass * uiClass)
-:
- m_resourceId(resourceId),
- m_descId(descId),
- m_uiClass(uiClass),
- m_pageNumber(0)
-{
- check( uiClass );
- check( uiClass->IsDerivedFrom( RUNTIME_CLASS( CDialog ) ) ||
- uiClass->IsDerivedFrom( RUNTIME_CLASS( CPropertySheet ) ) );
-
- m_name.LoadString(resourceId);
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::~CCPApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApplet::~CCPApplet()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::OnStartParms
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnStartParms(CWnd * pParentWnd, LPCTSTR extra)
-{
- DEBUG_UNUSED( pParentWnd );
-
- if ( extra )
- {
- m_pageNumber = ::_ttoi( extra ) - 1;
- }
-
- return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::OnRun
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnRun(CWnd* pParentWnd)
-{
- LRESULT lResult = 1;
- CWnd * pWnd;
-
- InitCommonControls();
-
- pWnd = (CWnd*) m_uiClass->CreateObject();
-
- if ( pWnd )
- {
- lResult = ERROR_SUCCESS;
-
- if ( pWnd->IsKindOf( RUNTIME_CLASS( CPropertySheet ) ) )
- {
- CPropertySheet * pSheet = (CPropertySheet*) pWnd;
-
- pSheet->Construct(m_name, pParentWnd, m_pageNumber);
-
- pSheet->DoModal();
- }
- else
- {
- check( pWnd->IsKindOf( RUNTIME_CLASS( CDialog ) ) );
-
- CDialog * pDialog = (CDialog*) pWnd;
-
- pDialog->DoModal();
- }
-
- delete pWnd;
- }
-
- return lResult;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::OnInquire
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnInquire(CPLINFO* pInfo)
-{
- pInfo->idIcon = m_resourceId;
- pInfo->idName = m_resourceId;
- pInfo->idInfo = m_descId;
- pInfo->lData = reinterpret_cast<LONG>(this);
-
- return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::OnNewInquire
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnNewInquire(NEWCPLINFO* pInfo)
-{
- DEBUG_UNUSED( pInfo );
-
- return 1;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::OnSelect
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnSelect()
-{
- return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet::OnStop
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnStop()
-{
- return 0;
-}
-
-
-IMPLEMENT_DYNAMIC(CCPApp, CWinApp);
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp::CCPApp()
-{
- debug_initialize( kDebugOutputTypeWindowsEventLog, "DNS-SD Control Panel", GetModuleHandle( NULL ) );
- debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::~CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp::~CCPApp()
-{
- while ( !m_applets.IsEmpty() )
- {
- delete m_applets.RemoveHead();
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::AddApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CCPApp::AddApplet( CCPApplet * applet )
-{
- check( applet );
-
- m_applets.AddTail( applet );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::OnInit
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApp::OnInit()
-{
- CCPApplet * applet;
-
- try
- {
- applet = new CCPApplet( IDR_APPLET, IDS_APPLET_DESCRIPTION, RUNTIME_CLASS( CConfigPropertySheet ) );
- }
- catch (...)
- {
- applet = NULL;
- }
-
- require_action( applet, exit, kNoMemoryErr );
-
- AddApplet( applet );
-
-exit:
-
- return m_applets.GetCount();
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::OnExit
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApp::OnExit()
-{
- return 1;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::OnCplMsg
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApp::OnCplMsg(HWND hWndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
-{
- LRESULT lResult = 1;
-
- switch ( uMsg )
- {
- case CPL_INIT:
- {
- lResult = OnInit();
- }
- break;
-
- case CPL_EXIT:
- {
- lResult = OnExit();
- }
- break;
-
- case CPL_GETCOUNT:
- {
- lResult = m_applets.GetCount();
- }
- break;
-
- default:
- {
- POSITION pos = m_applets.FindIndex( lParam1 );
- check( pos );
-
- CCPApplet * applet = m_applets.GetAt( pos );
- check( applet );
-
- switch (uMsg)
- {
- case CPL_INQUIRE:
- {
- LPCPLINFO pInfo = reinterpret_cast<LPCPLINFO>(lParam2);
- lResult = applet->OnInquire(pInfo);
- }
- break;
-
- case CPL_NEWINQUIRE:
- {
- LPNEWCPLINFO pInfo = reinterpret_cast<LPNEWCPLINFO>(lParam2);
- lResult = applet->OnNewInquire(pInfo);
- }
- break;
-
- case CPL_STARTWPARMS:
- {
- CWnd * pParentWnd = CWnd::FromHandle(hWndCPl);
- LPCTSTR lpszExtra = reinterpret_cast<LPCTSTR>(lParam2);
- lResult = applet->OnStartParms(pParentWnd, lpszExtra);
- }
- break;
-
- case CPL_DBLCLK:
- {
- CWnd* pParentWnd = CWnd::FromHandle(hWndCPl);
- lResult = applet->OnRun(pParentWnd);
- }
- break;
-
- case CPL_SELECT:
- {
- lResult = applet->OnSelect();
- }
- break;
-
- case CPL_STOP:
- {
- lResult = applet->OnStop();
- }
- break;
-
- default:
- {
- // TRACE(_T("Warning, Received an unknown control panel message:%d\n"), uMsg);
- lResult = 1;
- }
- break;
- }
- }
- break;
- }
-
- return lResult;
-}
+++ /dev/null
-; -*- 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.
-
-LIBRARY "Bonjour"
-
-EXPORTS
- CPlApplet
+++ /dev/null
-/* -*- 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.
- */
-
-
-#pragma once
-
-#include "stdafx.h"
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CCPApplet : public CCmdTarget
-{
-public:
-
- CCPApplet( UINT nResourceID, UINT nDescriptionID, CRuntimeClass* pUIClass );
-
- virtual ~CCPApplet();
-
-protected:
-
- virtual LRESULT OnRun(CWnd* pParentWnd);
- virtual LRESULT OnStartParms(CWnd* pParentWnd, LPCTSTR lpszExtra);
- virtual LRESULT OnInquire(CPLINFO* pInfo);
- virtual LRESULT OnNewInquire(NEWCPLINFO* pInfo);
- virtual LRESULT OnSelect();
- virtual LRESULT OnStop();
-
- CRuntimeClass * m_uiClass;
- UINT m_resourceId;
- UINT m_descId;
- CString m_name;
- int m_pageNumber;
-
- friend class CCPApp;
-
- DECLARE_DYNAMIC(CCPApplet);
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CCPApp : public CWinApp
-{
-public:
-
- CCPApp();
- virtual ~CCPApp();
-
- void AddApplet( CCPApplet* pApplet );
-
-protected:
-
- CList<CCPApplet*, CCPApplet*&> m_applets;
-
- friend LONG APIENTRY
- CPlApplet(HWND hWndCPl, UINT uMsg, LONG lParam1, LONG lParam2);
-
- virtual LRESULT OnCplMsg(HWND hWndCPl, UINT msg, LPARAM lp1, LPARAM lp2);
- virtual LRESULT OnInit();
- virtual LRESULT OnExit();
-
- DECLARE_DYNAMIC(CCPApp);
-};
-
-
-CCPApp * GetControlPanelApp();
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""afxres.h""\r\n"\r
- "#include ""WinVersRes.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
- "#define _AFX_NO_OLE_RESOURCES\r\n"\r
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
- "\r\n"\r
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
- "LANGUAGE 9, 1\r\n"\r
- "#pragma code_page(1252)\r\n"\r
- "#include ""afxres.rc"" // Standard components\r\n"\r
- "#endif\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Icon\r
-//\r
-\r
-// Icon with lowest ID value placed first to ensure application icon\r
-// remains consistent on all systems.\r
-IDR_APPLET ICON "res\\controlpanel.ico"\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904b0"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "Bonjour Control Panel"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "InternalName", "ControlPanel.cpl"\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "OriginalFilename", "ControlPanel.cpl"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1200\r
- END\r
-END\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// String Table\r
-//\r
-\r
-STRINGTABLE\r
-BEGIN\r
- IDS_REINSTALL "Bonjour Control Panel cannot run because some of its required files are missing. Please reinstall Bonjour Control Panel."\r
- IDS_REINSTALL_CAPTION "Bonjour"\r
-END\r
-#endif // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc" // Standard components\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
-\r
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="ControlPanel"\r
- ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
- RootNamespace="ControlPanel"\r
- Keyword="MFCProj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="false"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderThrough=""\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="0"\r
- DisableSpecificWarnings="4311;4312"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="2"\r
- SuppressStartupBanner="true"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderThrough=""\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="0"\r
- DisableSpecificWarnings="4311;4312"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="2"\r
- SuppressStartupBanner="true"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel64.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="false"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="1"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="false"\r
- RuntimeLibrary="0"\r
- EnableFunctionLevelLinking="true"\r
- TreatWChar_tAsBuiltInType="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- DisableSpecificWarnings="4702"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="1"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="false"\r
- RuntimeLibrary="0"\r
- EnableFunctionLevelLinking="true"\r
- TreatWChar_tAsBuiltInType="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- DisableSpecificWarnings="4702"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel64.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
- >\r
- <File\r
- RelativePath="ConfigDialog.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="ConfigPropertySheet.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath=".\ControlPanelExe.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ServicesPage.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="RegistrationPage.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="..\loclibrary.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="stdafx.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="BrowsingPage.cpp"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl"\r
- >\r
- <File\r
- RelativePath="ConfigDialog.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="ConfigPropertySheet.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ControlPanelExe.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ServicesPage.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="RegistrationPage.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\loclibrary.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="Resource.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="stdafx.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="BrowsingPage.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"\r
- >\r
- <File\r
- RelativePath="res\configurator.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\controlpanel.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ControlPanel.rc"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\res\ControlPanel.rc2"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\res\EnergySaver.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\failure.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\success.ico"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Support"\r
- >\r
- <File\r
- RelativePath="..\..\Clients\ClientCommon.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\Clients\ClientCommon.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dns_sd.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Secret.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Secret.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\WinServices.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\WinServices.h"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}</ProjectGuid>\r
- <RootNamespace>ControlPanel</RootNamespace>\r
- <Keyword>MFCProj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderFile>\r
- </PrecompiledHeaderFile>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ObjectFileName>$(IntDir)</ObjectFileName>\r
- <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>Cdecl</CallingConvention>\r
- <DisableSpecificWarnings>4311;4312;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\ControlPanel.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderFile>\r
- </PrecompiledHeaderFile>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ObjectFileName>$(IntDir)</ObjectFileName>\r
- <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>Cdecl</CallingConvention>\r
- <DisableSpecificWarnings>4311;4312;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\ControlPanel64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
- <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>false</MinimalRebuild>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <FunctionLevelLinking>true</FunctionLevelLinking>\r
- <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ObjectFileName>$(IntDir)</ObjectFileName>\r
- <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\ControlPanel.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
- <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>false</MinimalRebuild>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <FunctionLevelLinking>true</FunctionLevelLinking>\r
- <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ObjectFileName>$(IntDir)</ObjectFileName>\r
- <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\ControlPanel64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="ConfigDialog.cpp">\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- </ClCompile>\r
- <ClCompile Include="ConfigPropertySheet.cpp">\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- </ClCompile>\r
- <ClCompile Include="ControlPanelExe.cpp" />\r
- <ClCompile Include="ServicesPage.cpp" />\r
- <ClCompile Include="RegistrationPage.cpp">\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- </ClCompile>\r
- <ClCompile Include="..\loclibrary.c" />\r
- <ClCompile Include="stdafx.cpp">\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- </PrecompiledHeader>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- </PrecompiledHeader>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- </PrecompiledHeader>\r
- <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
- <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- </PrecompiledHeader>\r
- </ClCompile>\r
- <ClCompile Include="BrowsingPage.cpp" />\r
- <ClCompile Include="..\..\Clients\ClientCommon.c" />\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
- <ClCompile Include="..\Secret.c" />\r
- <ClCompile Include="..\WinServices.cpp" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="ConfigDialog.h" />\r
- <ClInclude Include="ConfigPropertySheet.h" />\r
- <ClInclude Include="ControlPanelExe.h" />\r
- <ClInclude Include="ServicesPage.h" />\r
- <ClInclude Include="RegistrationPage.h" />\r
- <ClInclude Include="..\loclibrary.h" />\r
- <ClInclude Include="Resource.h" />\r
- <ClInclude Include="stdafx.h" />\r
- <ClInclude Include="BrowsingPage.h" />\r
- <ClInclude Include="..\..\Clients\ClientCommon.h" />\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\dns_sd.h" />\r
- <ClInclude Include="..\Secret.h" />\r
- <ClInclude Include="..\WinServices.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="res\configurator.ico" />\r
- <None Include="res\controlpanel.ico" />\r
- <None Include="res\ControlPanel.rc2" />\r
- <None Include="res\EnergySaver.ico" />\r
- <None Include="res\failure.ico" />\r
- <None Include="res\success.ico" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="ControlPanel.rc" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ProjectReference Include="..\DLLStub\DLLStub.vcxproj">\r
- <Project>{3a2b6325-3053-4236-84bd-aa9be2e323e5}</Project>\r
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
- </ProjectReference>\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{d534a12a-5d97-4d9e-87ba-898c97da20fb}</UniqueIdentifier>\r
- <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{e7514699-1b61-4910-a465-8950dd4c3fad}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{dad601b4-0fa4-4692-8c01-8cbb407b5a32}</UniqueIdentifier>\r
- <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe</Extensions>\r
- </Filter>\r
- <Filter Include="Support">\r
- <UniqueIdentifier>{ada5b5c6-cf44-4574-94a0-0e576fda469d}</UniqueIdentifier>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="ConfigDialog.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="ConfigPropertySheet.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="ControlPanelExe.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="ServicesPage.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="RegistrationPage.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\loclibrary.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="stdafx.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="BrowsingPage.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\Clients\ClientCommon.c">\r
- <Filter>Support</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
- <Filter>Support</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\Secret.c">\r
- <Filter>Support</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\WinServices.cpp">\r
- <Filter>Support</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="ConfigDialog.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="ConfigPropertySheet.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="ControlPanelExe.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="ServicesPage.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="RegistrationPage.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\loclibrary.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="Resource.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="stdafx.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="BrowsingPage.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\Clients\ClientCommon.h">\r
- <Filter>Support</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
- <Filter>Support</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
- <Filter>Support</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\dns_sd.h">\r
- <Filter>Support</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\Secret.h">\r
- <Filter>Support</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\WinServices.h">\r
- <Filter>Support</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="res\configurator.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\controlpanel.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\ControlPanel.rc2">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\EnergySaver.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\failure.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\success.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="ControlPanel.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x1L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904e4"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "Bonjour Configuration Applet"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "InternalName", "Bonjour.cpl"\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "OriginalFilename", "Bonjour.cpl"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1252\r
- END\r
-END\r
-\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""afxres.h""\r\n"\r
- "#include ""WinVersRes.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
- "#define _AFX_NO_OLE_RESOURCES\r\n"\r
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
- "\r\n"\r
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
- "LANGUAGE 9, 1\r\n"\r
- "#pragma code_page(1252)\r\n"\r
- "#include ""afxres.rc"" // Standard components\r\n"\r
- "#include ""ControlPanel.rc""\r\n"\r
- "#endif\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-#endif // English (U.S.) resources\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc" // Standard components\r
-#include "ControlPanel.rc"\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "ControlPanelExe.h"
-#include "ConfigDialog.h"
-#include "ConfigPropertySheet.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include "loclibrary.h"
-#include <strsafe.h>
-
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-#ifndef HeapEnableTerminationOnCorruption
-# define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS) 1
-#endif
-
-
-// Stash away pointers to our resource DLLs
-
-static HINSTANCE g_nonLocalizedResources = NULL;
-static HINSTANCE g_localizedResources = NULL;
-
-
-HINSTANCE GetNonLocalizedResources()
-{
- return g_nonLocalizedResources;
-}
-
-
-HINSTANCE GetLocalizedResources()
-{
- return g_localizedResources;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// Static Declarations
-//---------------------------------------------------------------------------------------------------------------------------
-DEFINE_GUID(CLSID_ControlPanel,
-
-0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);
-
-static LPCTSTR g_controlPanelGUID = TEXT( "{1207552C-0E59-4d9f-8554-F1F806CD7FA9}" );
-static LPCTSTR g_controlPanelName = TEXT( "Bonjour" );
-static LPCTSTR g_controlPanelCanonicalName = TEXT( "Apple.Bonjour" );
-static LPCTSTR g_controlPanelCategory = TEXT( "3,8" );
-
-static CCPApp theApp;
-
-//===========================================================================================================================
-// MyRegDeleteKey
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus MyRegDeleteKey( HKEY hKeyRoot, LPTSTR lpSubKey )
-{
- LPTSTR lpEnd;
- OSStatus err;
- DWORD dwSize;
- TCHAR szName[MAX_PATH];
- HKEY hKey;
- FILETIME ftWrite;
-
- // First, see if we can delete the key without having to recurse.
-
- err = RegDeleteKey( hKeyRoot, lpSubKey );
-
- if ( !err )
- {
- goto exit;
- }
-
- err = RegOpenKeyEx( hKeyRoot, lpSubKey, 0, KEY_READ, &hKey );
- require_noerr( err, exit );
-
- // Check for an ending slash and add one if it is missing.
-
- lpEnd = lpSubKey + lstrlen(lpSubKey);
-
- if ( *( lpEnd - 1 ) != TEXT( '\\' ) )
- {
- *lpEnd = TEXT('\\');
- lpEnd++;
- *lpEnd = TEXT('\0');
- }
-
- // Enumerate the keys
-
- dwSize = MAX_PATH;
- err = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite);
-
- if ( !err )
- {
- do
- {
- lstrcpy (lpEnd, szName);
-
- if ( !MyRegDeleteKey( hKeyRoot, lpSubKey ) )
- {
- break;
- }
-
- dwSize = MAX_PATH;
-
- err = RegEnumKeyEx( hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite );
-
- }
- while ( !err );
- }
-
- lpEnd--;
- *lpEnd = TEXT('\0');
-
- RegCloseKey( hKey );
-
- // Try again to delete the key.
-
- err = RegDeleteKey(hKeyRoot, lpSubKey);
- require_noerr( err, exit );
-
-exit:
-
- return err;
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC(CCPApp, CWinApp);
-
-CCPApp::CCPApp()
-{
- debug_initialize( kDebugOutputTypeWindowsEventLog, "DNS-SD Control Panel", GetModuleHandle( NULL ) );
- debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CCPApp::~CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp::~CCPApp()
-{
-}
-
-
-void
-CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath )
-{
- typedef struct RegistryBuilder RegistryBuilder;
-
- struct RegistryBuilder
- {
- HKEY rootKey;
- LPCTSTR subKey;
- LPCTSTR valueName;
- DWORD valueType;
- LPCTSTR data;
- };
-
- OSStatus err;
- size_t n;
- size_t i;
- HKEY key;
- TCHAR keyName[ MAX_PATH ];
- RegistryBuilder entries[] =
- {
- { HKEY_LOCAL_MACHINE, TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s" ), NULL, REG_SZ, inName },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), NULL, NULL, NULL },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "System.ApplicationName" ), REG_SZ, inCanonicalName },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "System.ControlPanel.Category" ), REG_SZ, inCategory },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "LocalizedString" ), REG_SZ, inLocalizedName },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s" ), TEXT( "InfoTip" ), REG_SZ, inInfoTip },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\DefaultIcon" ), NULL, REG_SZ, inIconPath },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\Shell" ), NULL, NULL, NULL },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\Shell\\Open" ), NULL, NULL, NULL },
- { HKEY_CLASSES_ROOT, TEXT( "CLSID\\%s\\Shell\\Open\\Command" ), NULL, REG_SZ, inExePath }
- };
- DWORD size;
-
- // Register the registry entries.
-
- n = sizeof_array( entries );
- for( i = 0; i < n; ++i )
- {
- StringCbPrintf( keyName, sizeof( keyName ), entries[ i ].subKey, inClsidString );
- err = RegCreateKeyEx( entries[ i ].rootKey, keyName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- if ( entries[ i ].data )
- {
- size = (DWORD)( ( lstrlen( entries[ i ].data ) + 1 ) * sizeof( TCHAR ) );
- err = RegSetValueEx( key, entries[ i ].valueName, 0, entries[ i ].valueType, (LPBYTE) entries[ i ].data, size );
- require_noerr( err, exit );
- }
-
- RegCloseKey( key );
- }
-
-exit:
- return;
-}
-
-
-//-----------------------------------------------------------
-// CCPApp::Unregister
-//-----------------------------------------------------------
-void
-CCPApp::Unregister( LPCTSTR clsidString )
-{
- TCHAR keyName[ MAX_PATH * 2 ];
-
- StringCbPrintf( keyName, sizeof( keyName ), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString );
- MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName );
-
- StringCbPrintf( keyName, sizeof( keyName ), L"CLSID\\%s", clsidString );
- MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName );
-}
-
-
-
-//-----------------------------------------------------------
-// CCPApp::InitInstance
-//-----------------------------------------------------------
-
-BOOL
-CCPApp::InitInstance()
-{
- CCommandLineInfo commandLine;
- wchar_t resource[MAX_PATH];
- CString errorMessage;
- CString errorCaption;
- int res;
- OSStatus err = kNoErr;
-
- HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
-
- //
- // initialize the debugging framework
- //
- debug_initialize( kDebugOutputTypeWindowsDebugger, "ControlPanel", NULL );
- debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
-
- // Before we load the resources, let's load the error string
-
- errorMessage.LoadString( IDS_REINSTALL );
- errorCaption.LoadString( IDS_REINSTALL_CAPTION );
-
- res = PathForResource( NULL, L"ControlPanelResources.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 );
-
- res = PathForResource( NULL, L"ControlPanelLocalized.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 );
-
- // InitCommonControls() is required on Windows XP if an application
- // manifest specifies use of ComCtl32.dll version 6 or later to enable
- // visual styles. Otherwise, any window creation will fail.
-
- InitCommonControls();
-
- CWinApp::InitInstance();
-
- AfxEnableControlContainer();
-
- ParseCommandLine( commandLine );
-
- if ( commandLine.m_nShellCommand == CCommandLineInfo::AppRegister )
- {
- CString localizedName;
- CString toolTip;
- TCHAR iconPath[ MAX_PATH + 12 ] = TEXT( "" );
- TCHAR exePath[ MAX_PATH ] = TEXT( "" );
- DWORD nChars;
- OSStatus err;
-
- nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );
-
- err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
-
- require_noerr( err, exit );
-
- StringCbPrintf( iconPath, sizeof( iconPath ), L"%s,-%d", exePath, IDR_APPLET );
-
- localizedName.LoadString( IDS_APPLET_NAME );
- toolTip.LoadString( IDS_APPLET_TOOLTIP );
-
- Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCanonicalName, g_controlPanelCategory, localizedName, toolTip, iconPath, exePath );
- }
- else if ( commandLine.m_nShellCommand == CCommandLineInfo::AppUnregister )
- {
- Unregister( g_controlPanelGUID );
- }
- else
- {
- CString name;
- CConfigPropertySheet dlg;
-
- name.LoadString( IDR_APPLET );
- dlg.Construct( name, NULL, 0 );
-
- m_pMainWnd = &dlg;
-
- try
- {
- INT_PTR nResponse = dlg.DoModal();
-
- if (nResponse == IDOK)
- {
- // TODO: Place code here to handle when the dialog is
- // dismissed with OK
- }
- else if (nResponse == IDCANCEL)
- {
- // TODO: Place code here to handle when the dialog is
- // dismissed with Cancel
- }
- }
- catch (...)
- {
- MessageBox(NULL, L"", L"", MB_OK|MB_ICONEXCLAMATION);
- }
- }
-
- if ( err )
- {
- MessageBox( NULL, L"", L"", MB_ICONERROR | MB_OK );
- }
-
-exit:
-
- if ( err )
- {
- MessageBox( NULL, errorMessage, errorCaption, MB_ICONERROR | MB_OK );
- }
-
- // Since the dialog has been closed, return FALSE so that we exit the
- // application, rather than start the application's message pump.
- return FALSE;
-}
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#pragma once
-
-#include "stdafx.h"
-
-extern HINSTANCE GetNonLocalizedResources();
-extern HINSTANCE GetLocalizedResources();
-
-//-------------------------------------------------
-// CCPApp
-//-------------------------------------------------
-
-class CCPApp : public CWinApp
-{
-public:
-
- CCPApp();
- virtual ~CCPApp();
-
-protected:
-
- virtual BOOL InitInstance();
-
- void
- Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath );
-
- void
- Unregister( LPCTSTR clsidString );
-
- DECLARE_DYNAMIC(CCPApp);
-};
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x1L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904e4"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "Bonjour Configuration Applet"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "InternalName", "ControlPanel.exe"\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "OriginalFilename", "ControlPanel.exe"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1252\r
- END\r
-END\r
-\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""afxres.h""\r\n"\r
- "#include ""WinVersRes.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
- "#define _AFX_NO_OLE_RESOURCES\r\n"\r
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
- "\r\n"\r
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
- "LANGUAGE 9, 1\r\n"\r
- "#pragma code_page(1252)\r\n"\r
- "#include ""afxres.rc"" // Standard components\r\n"\r
- "#include ""ControlPanel.rc""\r\n"\r
- "#endif\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-#endif // English (U.S.) resources\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc" // Standard components\r
-#include "ControlPanel.rc"\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="ControlPanel (Vista)"\r
- ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
- Keyword="MFCProj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="false"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderThrough=""\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="0"\r
- DisableSpecificWarnings="4311;4312"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="2"\r
- SuppressStartupBanner="true"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderThrough=""\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="0"\r
- DisableSpecificWarnings="4311;4312"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="2"\r
- SuppressStartupBanner="true"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel64.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="false"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="1"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="false"\r
- RuntimeLibrary="0"\r
- EnableFunctionLevelLinking="true"\r
- TreatWChar_tAsBuiltInType="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- DisableSpecificWarnings="4702"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="1"\r
- AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="false"\r
- RuntimeLibrary="0"\r
- EnableFunctionLevelLinking="true"\r
- TreatWChar_tAsBuiltInType="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ObjectFile="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
- WarningLevel="4"\r
- SuppressStartupBanner="true"\r
- DisableSpecificWarnings="4702"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)/ControlPanel.exe"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- EntryPointSymbol="wWinMainCRTStartup"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\ControlPanel64.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
- >\r
- <File\r
- RelativePath="ConfigDialog.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="ConfigPropertySheet.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath=".\ControlPanelExe.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\FifthPage.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="FirstPage.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath=".\FourthPage.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="SecondPage.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="SharedSecret.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="stdafx.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- PreprocessorDefinitions=""\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="ThirdPage.cpp"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl"\r
- >\r
- <File\r
- RelativePath="ConfigDialog.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="ConfigPropertySheet.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ControlPanelExe.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\FifthPage.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="FirstPage.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\FourthPage.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="Resource.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="SecondPage.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="SharedSecret.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="stdafx.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="ThirdPage.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"\r
- >\r
- <File\r
- RelativePath="res\configurator.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\controlpanel.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\res\ControlPanel.rc2"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\ControlPanelExe.rc"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\failure.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\success.ico"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Support"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dns_sd.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Secret.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Secret.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\WinServices.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\WinServices.h"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""afxres.h""\r\n"\r
- "#include ""WinVersRes.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
- "#define _AFX_NO_OLE_RESOURCES\r\n"\r
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
- "\r\n"\r
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
- "LANGUAGE 9, 1\r\n"\r
- "#pragma code_page(1252)\r\n"\r
- "#include ""afxres.rc"" // Standard components\r\n"\r
- "#endif\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904b0"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "Bonjour Resource Module"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "InternalName", "ControlPanelLocalized.dll"\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "OriginalFilename", "ControlPanelLocalized.dll"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1200\r
- END\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Dialog\r
-//\r
-\r
-IDR_APPLET_PAGE1 DIALOGEX 0, 0, 262, 140\r
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
-CAPTION "Registration"\r
-FONT 8, "MS Sans Serif", 0, 0, 0x0\r
-BEGIN\r
- LTEXT "Hostname:",IDC_STATIC,13,22,35,8\r
- EDITTEXT IDC_HOSTNAME,55,20,184,12,ES_AUTOHSCROLL\r
- LTEXT "User:",IDC_STATIC,13,38,35,8\r
- EDITTEXT IDC_USERNAME,55,36,184,12,ES_AUTOHSCROLL\r
- LTEXT "Password:",IDC_STATIC,13,54,35,8\r
- EDITTEXT IDC_PASSWORD,55,52,184,12,ES_PASSWORD | ES_AUTOHSCROLL\r
- CONTROL "Advertise services in this domain using Bonjour",IDC_ADVERTISE_SERVICES,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,80,199,8\r
-END\r
-\r
-IDR_APPLET_PAGE3 DIALOGEX 0, 0, 262, 140\r
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
-CAPTION "Browsing"\r
-FONT 8, "MS Sans Serif", 0, 0, 0x0\r
-BEGIN\r
- LTEXT "Choose which domains to browse using wide-area Bonjour",\r
- -1,7,16,248,12\r
- CONTROL "",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT | \r
- LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | \r
- WS_TABSTOP,7,37,248,57\r
- PUSHBUTTON "Add",IDC_ADD_BROWSE_DOMAIN,152,100,50,14\r
- PUSHBUTTON "Remove",IDC_REMOVE_BROWSE_DOMAIN,205,100,50,14\r
-END\r
-\r
-IDR_APPLET_PAGE5 DIALOGEX 0, 0, 262, 140\r
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
-CAPTION "Services"\r
-FONT 8, "MS Sans Serif", 0, 0, 0x0\r
-BEGIN\r
- CONTROL "Advertise shared folders using Bonjour",IDC_ADVERTISE_SMB,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,199,8\r
- CONTROL "Enable Wake on Demand",IDC_POWER_MANAGEMENT,\r
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,199,8\r
-END\r
-\r
-IDR_POWER_MANAGEMENT_WARNING DIALOGEX 0, 0, 230, 95\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
- WS_SYSMENU\r
-CAPTION "Power Management"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
- DEFPUSHBUTTON "OK",IDOK,173,74,50,14\r
- LTEXT "When 'Wake On Demand' is enabled, you may hear your computer wake up occasionally.",\r
- IDC_STATIC,50,12,175,26\r
- LTEXT "This informs other devices that your computer is still available on the network.",\r
- IDC_STATIC,50,38,175,26\r
- ICON IDI_ENERGY_SAVER,IDC_ENERGY_SAVER,2,10,64,64,SS_REALSIZEIMAGE\r
-END\r
-\r
-IDR_ADD_BROWSE_DOMAIN DIALOGEX 0, 0, 230, 95\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
- WS_SYSMENU\r
-CAPTION "Add Browse Domain"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
- DEFPUSHBUTTON "OK",IDOK,117,74,50,14\r
- PUSHBUTTON "Cancel",IDCANCEL,173,74,50,14\r
- COMBOBOX IDC_COMBO1,35,42,188,100,CBS_DROPDOWN | CBS_SORT | \r
- WS_VSCROLL | WS_TABSTOP\r
- LTEXT "Domain:",IDC_STATIC,7,43,27,8\r
- LTEXT "The following domain will be added to your list of Bonjour browse domains.",\r
- IDC_STATIC,7,15,216,16\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// DESIGNINFO\r
-//\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-GUIDELINES DESIGNINFO \r
-BEGIN\r
- IDR_APPLET_PAGE1, DIALOG\r
- BEGIN\r
- LEFTMARGIN, 7\r
- RIGHTMARGIN, 255\r
- TOPMARGIN, 7\r
- BOTTOMMARGIN, 133\r
- END\r
-\r
- IDR_APPLET_PAGE2, DIALOG\r
- BEGIN\r
- LEFTMARGIN, 7\r
- RIGHTMARGIN, 255\r
- TOPMARGIN, 7\r
- BOTTOMMARGIN, 133\r
- END\r
-\r
- IDR_SECRET, DIALOG\r
- BEGIN\r
- LEFTMARGIN, 7\r
- RIGHTMARGIN, 244\r
- TOPMARGIN, 7\r
- BOTTOMMARGIN, 83\r
- END\r
-\r
- IDR_APPLET_PAGE3, DIALOG\r
- BEGIN\r
- LEFTMARGIN, 7\r
- RIGHTMARGIN, 255\r
- TOPMARGIN, 7\r
- BOTTOMMARGIN, 133\r
- END\r
-\r
- IDR_POWER_MANAGEMENT_WARNING, DIALOG\r
- BEGIN\r
- LEFTMARGIN, 7\r
- RIGHTMARGIN, 223\r
- TOPMARGIN, 7,\r
- BOTTOMMARGIN, 88\r
- END\r
-\r
- IDR_ADD_BROWSE_DOMAIN, DIALOG\r
- BEGIN\r
- LEFTMARGIN, 7\r
- RIGHTMARGIN, 223\r
- TOPMARGIN, 7\r
- BOTTOMMARGIN, 88\r
- END\r
-END\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// String Table\r
-//\r
-\r
-STRINGTABLE \r
-BEGIN\r
- IDR_APPLET "Bonjour"\r
- IDS_APPLET_NAME "Bonjour"\r
- IDS_APPLET_DESCRIPTION "Bonjour"\r
- IDS_APPLET_TOOLTIP "Change Bonjour settings for this computer."\r
-END\r
-\r
-#endif // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc" // Standard components\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
-\r
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="ControlPanelLocRes"\r
- ProjectGUID="{4490229E-025A-478F-A2CF-51154DA83E39}"\r
- RootNamespace="ControlPanelLocRes"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="1"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
- StringPooling="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Debug/"\r
- ObjectFile=".\Debug/"\r
- ProgramDataBaseFileName=".\Debug/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- AdditionalDependencies=""\r
- OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
- SubSystem="2"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="3"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
- StringPooling="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Debug/"\r
- ObjectFile=".\Debug/"\r
- ProgramDataBaseFileName=".\Debug/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- AdditionalDependencies=""\r
- OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
- SubSystem="2"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="1"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="2"\r
- FavorSizeOrSpeed="2"\r
- OmitFramePointers="true"\r
- AdditionalIncludeDirectories=".."\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
- StringPooling="true"\r
- RuntimeLibrary="0"\r
- BufferSecurityCheck="false"\r
- EnableFunctionLevelLinking="false"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Release/"\r
- ObjectFile=".\Release/"\r
- ProgramDataBaseFileName=".\Release/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- AdditionalDependencies=""\r
- OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- ProgramDatabaseFile=""\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="3"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="2"\r
- FavorSizeOrSpeed="2"\r
- OmitFramePointers="true"\r
- AdditionalIncludeDirectories=".."\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
- StringPooling="true"\r
- RuntimeLibrary="0"\r
- BufferSecurityCheck="false"\r
- EnableFunctionLevelLinking="false"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Release/"\r
- ObjectFile=".\Release/"\r
- ProgramDataBaseFileName=".\Release/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- AdditionalDependencies=""\r
- OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- ProgramDatabaseFile=""\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc"\r
- >\r
- <File\r
- RelativePath="resource_loc_res.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
- >\r
- <File\r
- RelativePath="ControlPanelLocRes.rc"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- <Global\r
- Name="RESOURCE_FILE"\r
- Value="ControlPanelLocRes.rc"\r
- />\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Template|Win32">\r
- <Configuration>Template</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Template|x64">\r
- <Configuration>Template</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{4490229E-025A-478F-A2CF-51154DA83E39}</ProjectGuid>\r
- <RootNamespace>ControlPanelLocRes</RootNamespace>\r
- <ProjectName>ControlPanelLocRes</ProjectName>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ControlPanelLocalized</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ControlPanelLocalized</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">ControlPanelLocalized</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ControlPanelLocalized</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ControlPanelLocalized</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|x64'">ControlPanelLocalized</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.dll</TargetExt>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.dll</TargetExt>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">.dll</TargetExt>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.dll</TargetExt>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.dll</TargetExt>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|x64'">.dll</TargetExt>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
- <ObjectFileName>.\Debug/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
- <ObjectFileName>.\Debug/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
- <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
- <OmitFramePointers>true</OmitFramePointers>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <BufferSecurityCheck>false</BufferSecurityCheck>\r
- <FunctionLevelLinking>false</FunctionLevelLinking>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
- <ObjectFileName>.\Release/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <ProgramDatabaseFile>\r
- </ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
- <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
- <OmitFramePointers>true</OmitFramePointers>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <BufferSecurityCheck>false</BufferSecurityCheck>\r
- <FunctionLevelLinking>false</FunctionLevelLinking>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
- <ObjectFileName>.\Release/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <ProgramDatabaseFile>\r
- </ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClInclude Include="resource_loc_res.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="ControlPanelLocRes.rc" />\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
- <ProjectExtensions>\r
- <VisualStudio>\r
- <UserProperties RESOURCE_FILE="ControlPanelLocRes.rc" />\r
- </VisualStudio>\r
- </ProjectExtensions>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{acc11657-b2ba-42ef-9f3e-c4c55cb6d9e9}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{7625f01d-dd41-4ede-9371-d3993f0779ac}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="resource_loc_res.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="ControlPanelLocRes.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""afxres.h""\r\n"\r
- "#include ""WinVersRes.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
- "#define _AFX_NO_OLE_RESOURCES\r\n"\r
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
- "\r\n"\r
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
- "LANGUAGE 9, 1\r\n"\r
- "#pragma code_page(1252)\r\n"\r
- "#include ""afxres.rc"" // Standard components\r\n"\r
- "#endif\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904b0"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "Bonjour Resource Module"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "InternalName", "ControlPanelResources.dll"\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "OriginalFilename", "ControlPanelResources.dll"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1200\r
- END\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Icon\r
-//\r
-\r
-// Icon with lowest ID value placed first to ensure application icon\r
-// remains consistent on all systems.\r
-IDR_APPLET ICON "res\\controlpanel.ico"\r
-IDI_FAILURE ICON "res\\failure.ico"\r
-IDI_SUCCESS ICON "res\\success.ico"\r
-IDI_ENERGY_SAVER ICON "res\\EnergySaver.ico"\r
-#endif // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc" // Standard components\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
-\r
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="ControlPanelRes"\r
- ProjectGUID="{5254AA9C-3D2E-4539-86D9-5EB0F4151215}"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="1"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
- StringPooling="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Debug/"\r
- ObjectFile=".\Debug/"\r
- ProgramDataBaseFileName=".\Debug/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
- SubSystem="2"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="3"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".."\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
- StringPooling="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Debug/"\r
- ObjectFile=".\Debug/"\r
- ProgramDataBaseFileName=".\Debug/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
- SubSystem="2"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="1"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="2"\r
- FavorSizeOrSpeed="2"\r
- OmitFramePointers="true"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;.."\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
- StringPooling="true"\r
- RuntimeLibrary="0"\r
- BufferSecurityCheck="false"\r
- EnableFunctionLevelLinking="false"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Release/"\r
- ObjectFile=".\Release/"\r
- ProgramDataBaseFileName=".\Release/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- ProgramDatabaseFile=""\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- UseOfMFC="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="true"\r
- SuppressStartupBanner="true"\r
- TargetEnvironment="3"\r
- TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- InlineFunctionExpansion="2"\r
- FavorSizeOrSpeed="2"\r
- OmitFramePointers="true"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;.."\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
- StringPooling="true"\r
- RuntimeLibrary="0"\r
- BufferSecurityCheck="false"\r
- EnableFunctionLevelLinking="false"\r
- ForceConformanceInForLoopScope="true"\r
- UsePrecompiledHeader="0"\r
- PrecompiledHeaderFile=""\r
- AssemblerListingLocation=".\Release/"\r
- ObjectFile=".\Release/"\r
- ProgramDataBaseFileName=".\Release/"\r
- BrowseInformation="1"\r
- WarningLevel="4"\r
- WarnAsError="false"\r
- SuppressStartupBanner="true"\r
- Detect64BitPortabilityProblems="true"\r
- CompileAs="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories=".."\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- Description="Building Output Directories"\r
- CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources
"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
- OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
- LinkIncremental="1"\r
- SuppressStartupBanner="true"\r
- IgnoreDefaultLibraryNames=""\r
- ModuleDefinitionFile=""\r
- ProgramDatabaseFile=""\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- ResourceOnlyDLL="true"\r
- ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc"\r
- >\r
- <File\r
- RelativePath="resource_res.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
- >\r
- <File\r
- RelativePath="res\about.bmp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\about.bmp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\button-2k.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\button-xp.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\res\cold.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="ControlPanelRes.rc"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\hot.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath="res\logo.bmp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\logo.bmp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="Web.ico"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- <Global\r
- Name="RESOURCE_FILE"\r
- Value="ControlPanelRes.rc"\r
- />\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Template|Win32">\r
- <Configuration>Template</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Template|x64">\r
- <Configuration>Template</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{5254AA9C-3D2E-4539-86D9-5EB0F4151215}</ProjectGuid>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>Static</UseOfMfc>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ControlPanelResources</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.dll</TargetExt>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ControlPanelResources</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.dll</TargetExt>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">ControlPanelResources</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">.dll</TargetExt>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ControlPanelResources</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.dll</TargetExt>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ControlPanelResources</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.dll</TargetExt>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|x64'">ControlPanelResources</TargetName>\r
- <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|x64'">.dll</TargetExt>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
- <ObjectFileName>.\Debug/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
- <ObjectFileName>.\Debug/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
- <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
- <OmitFramePointers>true</OmitFramePointers>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <BufferSecurityCheck>false</BufferSecurityCheck>\r
- <FunctionLevelLinking>false</FunctionLevelLinking>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
- <ObjectFileName>.\Release/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <ProgramDatabaseFile>\r
- </ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>true</MkTypLibCompatible>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
- <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
- <OmitFramePointers>true</OmitFramePointers>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <BufferSecurityCheck>false</BufferSecurityCheck>\r
- <FunctionLevelLinking>false</FunctionLevelLinking>\r
- <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
- <ObjectFileName>.\Release/</ObjectFileName>\r
- <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
- <BrowseInformation>true</BrowseInformation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <TreatWarningAsError>false</TreatWarningAsError>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <CompileAs>Default</CompileAs>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <PreLinkEvent>\r
- <Message>Building Output Directories</Message>\r
- <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
- </PreLinkEvent>\r
- <Link>\r
- <AdditionalOptions>/MACHINE:I386 /IGNORE:4089 %(AdditionalOptions)</AdditionalOptions>\r
- <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
- <SuppressStartupBanner>true</SuppressStartupBanner>\r
- <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
- <ModuleDefinitionFile>\r
- </ModuleDefinitionFile>\r
- <ProgramDatabaseFile>\r
- </ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <NoEntryPoint>true</NoEntryPoint>\r
- <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">\r
- <Link>\r
- <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'">\r
- <Link>\r
- <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClInclude Include="resource_res.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="res\about.bmp" />\r
- <None Include="about.bmp" />\r
- <None Include="res\button-2k.ico" />\r
- <None Include="res\button-xp.ico" />\r
- <None Include="res\cold.ico" />\r
- <None Include="hot.ico" />\r
- <None Include="res\logo.bmp" />\r
- <None Include="logo.bmp" />\r
- <None Include="Web.ico" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="ControlPanelRes.rc" />\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
- <ProjectExtensions>\r
- <VisualStudio>\r
- <UserProperties RESOURCE_FILE="ControlPanelRes.rc" />\r
- </VisualStudio>\r
- </ProjectExtensions>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{46e7bad9-15a3-43d9-ad60-c91ea9693b5d}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{6f549e07-210f-4cd6-96ae-8eda3aaae73b}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="resource_res.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="res\about.bmp">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="about.bmp">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\button-2k.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\button-xp.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\cold.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="hot.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="res\logo.bmp">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="logo.bmp">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="Web.ico">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="ControlPanelRes.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "FourthPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
-
-#include <WinServices.h>
-
-#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<CConfigPropertySheet*>(GetParent());
- require_quiet( psheet, exit );
-
- m_checkBox.SetCheck( 0 );
-
- // Now populate the browse domain box
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- 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 = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- 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 ];
-
-
-
- snprintf( buf, sizeof( buf ), "check box: %d", m_checkBox.GetCheck() );
-
- OutputDebugStringA( buf );
-
- // TODO: Add your control notification handler code here
-
-
-
- SetModified( TRUE );
-
-}
-
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#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<CString> 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();
-
-};
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <Secret.h>
-#include "RegistrationPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-extern "C"
-{
-#include <ClientCommon.h>
-}
-#include <WinServices.h>
-
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CRegistrationPage, CPropertyPage)
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::CRegistrationPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CRegistrationPage::CRegistrationPage()
-:
- CPropertyPage(CRegistrationPage::IDD),
- m_ignoreChanges( false ),
- m_hostnameSetupKey( NULL ),
- m_registrationSetupKey( NULL ),
- m_statusKey( NULL )
-{
- //{{AFX_DATA_INIT(CRegistrationPage)
- //}}AFX_DATA_INIT
-
- OSStatus err;
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\Hostnames", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_hostnameSetupKey, NULL );
- check_noerr( err );
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_registrationSetupKey, NULL );
- check_noerr( err );
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\State\\Hostnames", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_statusKey, NULL );
- check_noerr( err );
-
-
-}
-
-CRegistrationPage::~CRegistrationPage()
-{
- if ( m_hostnameSetupKey )
- {
- RegCloseKey( m_hostnameSetupKey );
- m_hostnameSetupKey = NULL;
- }
-
- if ( m_registrationSetupKey )
- {
- RegCloseKey( m_registrationSetupKey );
- m_registrationSetupKey = NULL;
- }
-
- if ( m_statusKey )
- {
- RegCloseKey( m_statusKey );
- m_statusKey = NULL;
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::DoDataExchange(CDataExchange* pDX)
-{
- CPropertyPage::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CRegistrationPage)
- //}}AFX_DATA_MAP
- DDX_Control(pDX, IDC_HOSTNAME, m_hostnameControl);
- DDX_Control(pDX, IDC_USERNAME, m_usernameControl);
- DDX_Control(pDX, IDC_PASSWORD, m_passwordControl);
- DDX_Control(pDX, IDC_ADVERTISE_SERVICES, m_advertiseServices);
-}
-
-BEGIN_MESSAGE_MAP(CRegistrationPage, CPropertyPage)
- //{{AFX_MSG_MAP(CRegistrationPage)
- //}}AFX_MSG_MAP
- ON_EN_CHANGE(IDC_HOSTNAME, OnEnChangeHostname)
- ON_EN_CHANGE(IDC_USERNAME, OnEnChangeUsername)
- ON_EN_CHANGE(IDC_PASSWORD, OnEnChangePassword)
- ON_BN_CLICKED(IDC_ADVERTISE_SERVICES, OnBnClickedAdvertiseServices)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::OnEnChangedHostname
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnEnChangeHostname()
-{
- if ( !m_ignoreChanges )
- {
- SetModified( TRUE );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::OnEnChangedUsername
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnEnChangeUsername()
-{
- if ( !m_ignoreChanges )
- {
- SetModified( TRUE );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::OnEnChangedPassword
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnEnChangePassword()
-{
- if ( !m_ignoreChanges )
- {
- SetModified( TRUE );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::OnBnClickedAdvertiseServices
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnBnClickedAdvertiseServices()
-{
- if ( !m_ignoreChanges )
- {
- SetModified( TRUE );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::SetModified( BOOL bChanged )
-{
- m_modified = bChanged ? true : false;
-
- CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CRegistrationPage::OnSetActive()
-{
- TCHAR name[kDNSServiceMaxDomainName + 1];
- DWORD nameLen = ( kDNSServiceMaxDomainName + 1 ) * sizeof( TCHAR );
- DWORD err;
-
- BOOL b = CPropertyPage::OnSetActive();
-
- m_ignoreChanges = true;
- m_modified = FALSE;
-
- if ( m_hostnameSetupKey )
- {
- err = RegQueryValueEx( m_hostnameSetupKey, L"", NULL, NULL, (LPBYTE) name, &nameLen );
-
- if ( !err )
- {
- char hostnameUTF8[ 256 ];
- char outDomain[ 256 ];
- char outUsername[ 256 ];
- char outPassword[ 256 ];
- CString hostname = name;
- CString username;
- CString password;
-
- m_hostnameControl.SetWindowText( hostname );
-
- StringObjectToUTF8String( hostname, hostnameUTF8, sizeof( hostnameUTF8 ) );
-
- if ( LsaGetSecret( hostnameUTF8, outDomain, sizeof( outDomain ) / sizeof( TCHAR ), outUsername, sizeof( outUsername ) / sizeof( TCHAR ), outPassword, sizeof( outPassword ) / sizeof( TCHAR ) ) )
- {
- username = outUsername;
- m_usernameControl.SetWindowText( username );
-
- password = outPassword;
- m_passwordControl.SetWindowText( password );
- }
- }
- }
-
- m_advertiseServices.SetCheck( 0 );
-
- if ( m_registrationSetupKey )
- {
- HKEY subKey = NULL;
- DWORD dwSize;
- DWORD enabled = 0;
- TCHAR subKeyName[MAX_KEY_LENGTH];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- OSStatus err;
-
- err = RegQueryInfoKey( m_registrationSetupKey, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- if ( !err )
- {
- if ( cSubKeys > 0 )
- {
- dwSize = MAX_KEY_LENGTH;
-
- err = RegEnumKeyEx( m_registrationSetupKey, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
- if ( !err )
- {
- err = RegOpenKey( m_registrationSetupKey, subKeyName, &subKey );
- if ( !err )
- {
- dwSize = sizeof( DWORD );
- err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
- if ( !err && enabled )
- {
- m_advertiseServices.SetCheck( enabled );
- }
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
- }
- }
- }
- }
-
- m_ignoreChanges = false;
-
- return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CRegistrationPage::OnOK()
-{
- if ( m_modified )
- {
- Commit();
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CRegistrationPage::Commit()
-{
- CString hostname;
- char hostnameUTF8[ 256 ];
- CString username;
- char usernameUTF8[ 256 ];
- CString password;
- char passwordUTF8[ 256 ];
- DWORD enabled = 1;
- BOOL secret = FALSE;
- DWORD err;
-
- m_hostnameControl.GetWindowText( hostname );
- hostname.MakeLower();
- hostname.TrimRight( '.' );
- StringObjectToUTF8String( hostname, hostnameUTF8, sizeof( hostnameUTF8 ) );
-
- m_usernameControl.GetWindowText( username );
- m_passwordControl.GetWindowText( password );
-
- if ( username.GetLength() && password.GetLength() )
- {
- StringObjectToUTF8String( username, usernameUTF8, sizeof( usernameUTF8 ) );
- StringObjectToUTF8String( password, passwordUTF8, sizeof( passwordUTF8 ) );
- secret = TRUE;
- }
-
- if ( m_hostnameSetupKey != NULL )
- {
- err = RegSetValueEx( m_hostnameSetupKey, L"", 0, REG_SZ, (LPBYTE) (LPCTSTR) hostname, ( hostname.GetLength() + 1 ) * sizeof( TCHAR ) );
- require_noerr( err, exit );
-
- err = RegSetValueEx( m_hostnameSetupKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
- require_noerr( err, exit );
-
- if ( secret )
- {
- LsaSetSecret( hostnameUTF8, usernameUTF8, passwordUTF8 );
- }
- }
-
- if ( m_registrationSetupKey != NULL )
- {
- TCHAR subKeyName[MAX_KEY_LENGTH];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- DWORD dwSize;
- int i;
- OSStatus err = kNoErr;
-
- // First, remove all the entries that are there
-
- err = RegQueryInfoKey( m_registrationSetupKey, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- if ( !err )
- {
- for ( i = 0; i < (int) cSubKeys; i++ )
- {
- dwSize = MAX_KEY_LENGTH;
-
- err = RegEnumKeyEx( m_registrationSetupKey, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- err = RegDeleteKey( m_registrationSetupKey, subKeyName );
- require_noerr( err, exit );
- }
- }
-
- if ( m_advertiseServices.GetCheck() )
- {
- const char * domainUTF8;
- CString domain;
- char label[ 64 ];
- HKEY subKey = NULL;
-
- domainUTF8 = GetNextLabel( hostnameUTF8, label );
- domain = domainUTF8;
-
- err = RegCreateKeyEx( m_registrationSetupKey, domain, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &subKey, NULL );
- if ( !err )
- {
- err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
- check_noerr( err );
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
-
- if ( secret )
- {
- LsaSetSecret( domainUTF8, usernameUTF8, passwordUTF8 );
- }
- }
- }
-
-exit:
-
- return;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-#include <DebugServices.h>
-#include "afxwin.h"
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CRegistrationPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CRegistrationPage : public CPropertyPage
-{
-public:
- CRegistrationPage();
- ~CRegistrationPage();
-
-protected:
- //{{AFX_DATA(CRegistrationPage)
- enum { IDD = IDR_APPLET_PAGE1 };
- //}}AFX_DATA
-
- //{{AFX_VIRTUAL(CRegistrationPage)
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- DECLARE_DYNCREATE(CRegistrationPage)
-
- //{{AFX_MSG(CRegistrationPage)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
-private:
-
- afx_msg BOOL OnSetActive();
- afx_msg void OnOK();
-
- void SetModified( BOOL bChanged = TRUE );
- void Commit();
-
- CEdit m_hostnameControl;
- CEdit m_usernameControl;
- CEdit m_passwordControl;
- CButton m_advertiseServices;
- bool m_ignoreChanges;
- bool m_modified;
- HKEY m_hostnameSetupKey;
- HKEY m_registrationSetupKey;
- HKEY m_statusKey;
-
-public:
-
- afx_msg void OnEnChangeHostname();
- afx_msg void OnEnChangeUsername();
- afx_msg void OnEnChangePassword();
- afx_msg void OnBnClickedAdvertiseServices();
-};
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SecondPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
-
-#include <WinServices.h>
-
-#define MAX_KEY_LENGTH 255
-
-IMPLEMENT_DYNCREATE(CSecondPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::CSecondPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSecondPage::CSecondPage()
-:
- CPropertyPage(CSecondPage::IDD),
- m_setupKey( NULL )
-{
- //{{AFX_DATA_INIT(CSecondPage)
- //}}AFX_DATA_INIT
-
- OSStatus err;
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_setupKey, NULL );
- check_noerr( err );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::~CSecondPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSecondPage::~CSecondPage()
-{
- if ( m_setupKey )
- {
- RegCloseKey( m_setupKey );
- m_setupKey = NULL;
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::DoDataExchange(CDataExchange* pDX)
-{
- CPropertyPage::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CSecondPage)
- //}}AFX_DATA_MAP
- DDX_Control(pDX, IDC_CHECK1, m_advertiseServicesButton);
- DDX_Control(pDX, IDC_BUTTON1, m_sharedSecretButton);
- DDX_Control(pDX, IDC_COMBO2, m_regDomainsBox);
-}
-
-BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage)
- //{{AFX_MSG_MAP(CSecondPage)
- //}}AFX_MSG_MAP
- ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSharedSecret)
- ON_BN_CLICKED(IDC_CHECK1, OnBnClickedAdvertise)
- ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelChange)
- ON_CBN_EDITCHANGE(IDC_COMBO1, OnCbnEditChange)
- ON_CBN_EDITCHANGE(IDC_COMBO2, OnCbnEditChange)
- ON_CBN_SELCHANGE(IDC_COMBO2, OnCbnSelChange)
-
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::SetModified( BOOL bChanged )
-{
- m_modified = bChanged;
-
- CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CSecondPage::OnSetActive()
-{
- CConfigPropertySheet * psheet;
- DWORD err;
- BOOL b = CPropertyPage::OnSetActive();
-
- psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
- require_quiet( psheet, exit );
-
- m_modified = FALSE;
-
- // Clear out what's there
-
- EmptyComboBox( m_regDomainsBox );
-
- // Now populate the registration domain box
-
- err = Populate( m_regDomainsBox, m_setupKey, psheet->m_regDomains );
- check_noerr( err );
-
-exit:
-
- return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::OnOK()
-{
- if ( m_modified )
- {
- Commit();
- }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::Commit()
-{
- DWORD err;
-
- if ( m_setupKey != NULL )
- {
- err = Commit( m_regDomainsBox, m_setupKey, m_advertiseServicesButton.GetCheck() == BST_CHECKED );
- check_noerr( err );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::Commit( CComboBox & box, HKEY key, DWORD enabled )
-{
- CString selected;
- HKEY subKey = NULL;
- TCHAR subKeyName[MAX_KEY_LENGTH];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- DWORD dwSize;
- int i;
- OSStatus err = kNoErr;
-
- // First, remove all the entries that are there
-
- err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- for ( i = 0; i < (int) cSubKeys; i++ )
- {
- dwSize = MAX_KEY_LENGTH;
-
- err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- err = RegDeleteKey( key, subKeyName );
- require_noerr( err, exit );
- }
-
- // Get selected text
-
- box.GetWindowText( selected );
-
- // If we haven't seen this string before, add the string to the box and
- // the registry
-
- if ( ( selected.GetLength() > 0 ) && ( box.FindStringExact( -1, selected ) == CB_ERR ) )
- {
- CString string;
-
- box.AddString( selected );
-
- err = RegQueryString( key, L"UserDefined", string );
- check_noerr( err );
-
- if ( string.GetLength() )
- {
- string += L"," + selected;
- }
- else
- {
- string = selected;
- }
-
- err = RegSetValueEx( key, L"UserDefined", 0, REG_SZ, (LPBYTE) (LPCTSTR) string, ( string.GetLength() + 1) * sizeof( TCHAR ) );
- check_noerr ( err );
- }
-
- // Save selected text in registry. This will trigger mDNSResponder to setup
- // DynDNS config again
-
- err = RegCreateKeyEx( key, selected, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &subKey, NULL );
- require_noerr( err, exit );
-
- err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
- check_noerr( err );
-
-exit:
-
- if ( subKey )
- {
- RegCloseKey( subKey );
- subKey = NULL;
- }
-
- return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnBnClickedSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnBnClickedSharedSecret()
-{
- CString name;
-
- m_regDomainsBox.GetWindowText( name );
-
- CSharedSecret dlg;
-
- dlg.Load( name );
-
- if ( dlg.DoModal() == IDOK )
- {
- DWORD wakeup = 0;
- DWORD dwSize = sizeof( DWORD );
- OSStatus err;
-
- dlg.Commit( name );
-
- // We have now updated the secret, however the system service
- // doesn't know about it yet. So we're going to update the
- // registry with a dummy value which will cause the system
- // service to re-initialize it's DynDNS setup
- //
-
- RegQueryValueEx( m_setupKey, L"Wakeup", NULL, NULL, (LPBYTE) &wakeup, &dwSize );
-
- wakeup++;
-
- err = RegSetValueEx( m_setupKey, L"Wakeup", 0, REG_DWORD, (LPBYTE) &wakeup, sizeof( DWORD ) );
- require_noerr( err, exit );
- }
-
-exit:
-
- return;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnBnClickedAdvertise
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnBnClickedAdvertise()
-{
- int state;
-
- state = m_advertiseServicesButton.GetCheck();
-
- m_regDomainsBox.EnableWindow( state );
- m_sharedSecretButton.EnableWindow( state );
-
- SetModified( TRUE );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnCbnSelChange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnCbnSelChange()
-{
- SetModified( TRUE );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnCbnEditChange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnCbnEditChange()
-{
- SetModified( TRUE );
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnAddRegistrationDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::OnAddRegistrationDomain( CString & domain )
-{
- int index = m_regDomainsBox.FindStringExact( -1, domain );
-
- if ( index == CB_ERR )
- {
- m_regDomainsBox.AddString( domain );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::OnRemoveRegistrationDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::OnRemoveRegistrationDomain( CString & domain )
-{
- int index = m_regDomainsBox.FindStringExact( -1, domain );
-
- if ( index != CB_ERR )
- {
- m_regDomainsBox.DeleteString( index );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::EmptyComboBox
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::EmptyComboBox( CComboBox & box )
-{
- while ( box.GetCount() > 0 )
- {
- box.DeleteString( 0 );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::Populate
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::Populate( CComboBox & box, HKEY key, StringList & l )
-{
- CString string;
- HKEY subKey = NULL;
- DWORD dwSize;
- DWORD enabled = 0;
- TCHAR subKeyName[MAX_KEY_LENGTH];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- OSStatus err;
-
- err = RegQueryString( key, L"UserDefined", string );
-
- if ( !err && string.GetLength() )
- {
- bool done = false;
-
- while ( !done )
- {
- CString tok;
-
- tok = string.SpanExcluding( L"," );
-
- box.AddString( tok );
-
- if ( tok != string )
- {
- // Get rid of that string and comma
-
- string = string.Right( string.GetLength() - tok.GetLength() - 1 );
- }
- else
- {
- done = true;
- }
- }
- }
-
- StringList::iterator it;
-
- for ( it = l.begin(); it != l.end(); it++ )
- {
- if ( box.FindStringExact( -1, *it ) == CB_ERR )
- {
- box.AddString( *it );
- }
- }
-
- err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- if ( cSubKeys > 0 )
- {
- dwSize = MAX_KEY_LENGTH;
-
- err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- err = RegOpenKey( key, subKeyName, &subKey );
- require_noerr( err, exit );
-
- dwSize = sizeof( DWORD );
- err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
- require_noerr( err, exit );
-
- // See if it's there
-
- if ( box.SelectString( -1, subKeyName ) == CB_ERR )
- {
- // If not, add it
-
- box.AddString( subKeyName );
- }
-
- box.SelectString( -1, subKeyName );
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
-
-exit:
-
- m_advertiseServicesButton.SetCheck( ( !err && enabled ) ? BST_CHECKED : BST_UNCHECKED );
- m_regDomainsBox.EnableWindow( ( !err && enabled ) );
- m_sharedSecretButton.EnableWindow( (!err && enabled ) );
-
- return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::CreateKey
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::CreateKey( CString & name, DWORD enabled )
-{
- HKEY key = NULL;
- OSStatus err;
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, (LPCTSTR) name, 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- err = RegSetValueEx( key, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
- check_noerr( err );
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage::RegQueryString
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::RegQueryString( HKEY key, CString valueName, CString & value )
-{
- TCHAR * string;
- DWORD stringLen;
- int i;
- OSStatus err;
-
- stringLen = 1024;
- string = NULL;
- i = 0;
-
- do
- {
- if ( string )
- {
- free( string );
- }
-
- string = (TCHAR*) malloc( stringLen );
- require_action( string, exit, err = kUnknownErr );
- *string = '\0';
-
- err = RegQueryValueEx( key, valueName, 0, NULL, (LPBYTE) string, &stringLen );
-
- i++;
- }
- while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
-
- value = string;
-
-exit:
-
- if ( string )
- {
- free( string );
- }
-
- return err;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSecondPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CSecondPage : public CPropertyPage
-{
-public:
- CSecondPage();
- ~CSecondPage();
-
-protected:
-
- //{{AFX_DATA(CSecondPage)
- enum { IDD = IDR_APPLET_PAGE2 };
- //}}AFX_DATA
-
- //{{AFX_VIRTUAL(CSecondPage)
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- DECLARE_DYNCREATE(CSecondPage)
-
- //{{AFX_MSG(CSecondPage)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-public:
-
- afx_msg void OnBnClickedSharedSecret();
- afx_msg void OnBnClickedAdvertise();
-
- void OnAddRegistrationDomain( CString & domain );
- void OnRemoveRegistrationDomain( CString & domain );
-
-private:
-
- typedef std::list<CString> StringList;
-
- afx_msg BOOL
- OnSetActive();
-
- afx_msg void
- OnOK();
-
- void
- EmptyComboBox
- (
- CComboBox & box
- );
-
- OSStatus
- Populate(
- CComboBox & box,
- HKEY key,
- StringList & l
- );
-
- void
- SetModified( BOOL bChanged = TRUE );
-
- void
- Commit();
-
- OSStatus
- Commit( CComboBox & box, HKEY key, DWORD enabled );
-
- OSStatus
- CreateKey( CString & name, DWORD enabled );
-
- OSStatus
- RegQueryString( HKEY key, CString valueName, CString & value );
-
- CComboBox m_regDomainsBox;
- CButton m_advertiseServicesButton;
- CButton m_sharedSecretButton;
- BOOL m_modified;
- HKEY m_setupKey;
-
-public:
- afx_msg void OnCbnSelChange();
- afx_msg void OnCbnEditChange();
-};
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ServicesPage.h"
-#include "resource.h"
-
-#include "ControlPanelExe.h"
-#include "ConfigPropertySheet.h"
-
-#include <WinServices.h>
-
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CServicesPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::CServicesPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CServicesPage::CServicesPage()
-:
- CPropertyPage(CServicesPage::IDD)
-{
- //{{AFX_DATA_INIT(CServicesPage)
- //}}AFX_DATA_INIT
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::~CServicesPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CServicesPage::~CServicesPage()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::DoDataExchange(CDataExchange* pDX)
-{
- CPropertyPage::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(CServicesPage)
- //}}AFX_DATA_MAP
- DDX_Control(pDX, IDC_ADVERTISE_SMB, m_SMBCheckBox);
- DDX_Control(pDX, IDC_POWER_MANAGEMENT, m_powerManagementCheckBox);
-}
-
-BEGIN_MESSAGE_MAP(CServicesPage, CPropertyPage)
- //{{AFX_MSG_MAP(CServicesPage)
- //}}AFX_MSG_MAP
-
- ON_BN_CLICKED(IDC_ADVERTISE_SMB, &CServicesPage::OnBnClickedAdvertiseSMB)
- ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CServicesPage::OnBnClickedPowerManagement)
-
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::SetModified( BOOL bChanged )
-{
- m_modified = bChanged;
-
- CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CServicesPage::OnSetActive()
-{
- CConfigPropertySheet * psheet;
- HKEY key = NULL;
- DWORD dwSize;
- DWORD enabled;
- DWORD err;
- BOOL b = CPropertyPage::OnSetActive();
-
- psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
- require_quiet( psheet, exit );
-
- m_SMBCheckBox.SetCheck( 0 );
-
- // Now populate the browse domain box
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- dwSize = sizeof( DWORD );
- err = RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &enabled, &dwSize );
- require_noerr( err, exit );
-
- m_SMBCheckBox.SetCheck( enabled );
-
- RegCloseKey( key );
- key = NULL;
-
- m_powerManagementCheckBox.SetCheck( 0 );
-
- // Now populate the browse domain box
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- dwSize = sizeof( DWORD );
- err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
- require_noerr( err, exit );
-
- m_powerManagementCheckBox.SetCheck( enabled );
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CServicesPage::OnOK()
-{
- if ( m_modified )
- {
- Commit();
- }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CServicesPage::Commit()
-{
- HKEY key = NULL;
- DWORD enabled;
- DWORD err;
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- enabled = m_SMBCheckBox.GetCheck();
- err = RegSetValueEx( key, L"Advertise", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
- require_noerr( err, exit );
-
- RegCloseKey( key );
- key = NULL;
-
- err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
- NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
- require_noerr( err, exit );
-
- enabled = m_powerManagementCheckBox.GetCheck();
- err = RegSetValueEx( key, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
- require_noerr( err, exit );
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::OnBnClickedAdvertiseSMB
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::OnBnClickedAdvertiseSMB()
-{
- SetModified( TRUE );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage::OnBnClickedPowerManagement
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::OnBnClickedPowerManagement()
-{
- SetModified( TRUE );
-
- if ( m_powerManagementCheckBox.GetCheck() )
- {
- CPowerManagementWarning dlg( GetParent() );
-
- dlg.DoModal();
- }
-}
-
-
-// CPowerManagementWarning dialog
-
-IMPLEMENT_DYNAMIC(CPowerManagementWarning, CDialog)
-CPowerManagementWarning::CPowerManagementWarning(CWnd* pParent /*=NULL*/)
- : CDialog(CPowerManagementWarning::IDD, pParent)
-{
-}
-
-CPowerManagementWarning::~CPowerManagementWarning()
-{
-}
-
-void CPowerManagementWarning::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- DDX_Control(pDX, IDC_ENERGY_SAVER, m_energySaverIcon);
-}
-
-
-BOOL
-CPowerManagementWarning::OnInitDialog()
-{
- BOOL b = CDialog::OnInitDialog();
-
- const HICON hIcon = ( HICON ) ::LoadImage( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_ENERGY_SAVER ), IMAGE_ICON, 0, 0, 0);
-
- if ( hIcon )
- {
- m_energySaverIcon.SetIcon( hIcon );
- }
-
- return b;
-}
-
-
-void
-CPowerManagementWarning::OnOK()
-{
- CDialog::OnOK();
-}
-
-
-BEGIN_MESSAGE_MAP(CPowerManagementWarning, CDialog)
-END_MESSAGE_MAP()
-
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#include "afxcmn.h"
-
-#include "afxwin.h"
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CServicesPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CServicesPage : public CPropertyPage
-{
-public:
- CServicesPage();
- ~CServicesPage();
-
-protected:
-
- //{{AFX_DATA(CServicesPage)
- enum { IDD = IDR_APPLET_PAGE5 };
- //}}AFX_DATA
-
- //{{AFX_VIRTUAL(CServicesPage)
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- DECLARE_DYNCREATE(CServicesPage)
-
- //{{AFX_MSG(CServicesPage)
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-
-private:
-
- typedef std::list<CString> StringList;
-
- afx_msg BOOL
- OnSetActive();
-
- afx_msg void
- OnOK();
-
- void
- SetModified( BOOL bChanged = TRUE );
-
- void
- Commit();
-
- BOOL m_modified;
-
-public:
-private:
-
- CButton m_SMBCheckBox;
- CButton m_powerManagementCheckBox;
-
-public:
-
-
- afx_msg void OnBnClickedAdvertiseSMB();
- afx_msg void OnBnClickedPowerManagement();
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CPowerManagementWarning
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CPowerManagementWarning : public CDialog
-{
- DECLARE_DYNAMIC(CPowerManagementWarning)
-
-public:
-
- CPowerManagementWarning(CWnd* pParent = NULL); // standard constructor
-
- virtual ~CPowerManagementWarning();
-
-// Dialog Data
-
- enum { IDD = IDR_POWER_MANAGEMENT_WARNING };
-
-protected:
-
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
-
- virtual BOOL OnInitDialog();
-
- virtual void OnOK();
-
- DECLARE_MESSAGE_MAP()
-
-public:
-
- CStatic m_energySaverIcon;
-};
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-// SharedSecret.cpp : implementation file
-//
-
-
-#include <Secret.h>
-#include "stdafx.h"
-#include "SharedSecret.h"
-#include <WinServices.h>
-
-#include <DebugServices.h>
-
-
-// SharedSecret dialog
-
-IMPLEMENT_DYNAMIC(CSharedSecret, CDialog)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSharedSecret::CSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSharedSecret::CSharedSecret(CWnd* pParent /*=NULL*/)
- : CDialog(CSharedSecret::IDD, pParent)
- , m_key(_T(""))
- , m_secret(_T(""))
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSharedSecret::~CSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSharedSecret::~CSharedSecret()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSharedSecret::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSharedSecret::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- DDX_Text(pDX, IDC_KEY, m_key );
- DDX_Text(pDX, IDC_SECRET, m_secret );
-}
-
-
-BEGIN_MESSAGE_MAP(CSharedSecret, CDialog)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSharedSecret::Load
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSharedSecret::Load( CString zone )
-{
- char zoneUTF8[ 256 ];
- char outDomain[ 256 ];
- char outKey[ 256 ];
- char outSecret[ 256 ];
-
- 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 = outKey;
- m_secret = outSecret;
- }
- else
- {
- m_key = zone;
- }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSharedSecret::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSharedSecret::Commit( CString zone )
-{
- char zoneUTF8[ 256 ];
- char keyUTF8[ 256 ];
- char secretUTF8[ 256 ];
-
- StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) );
- StringObjectToUTF8String( m_key, keyUTF8, sizeof( keyUTF8 ) );
- StringObjectToUTF8String( m_secret, secretUTF8, sizeof( secretUTF8 ) );
-
- LsaSetSecret( zoneUTF8, keyUTF8, secretUTF8 );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-
-#pragma once
-
-#include "resource.h"
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-// CSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CSharedSecret : public CDialog
-{
- DECLARE_DYNAMIC(CSharedSecret)
-
-public:
- CSharedSecret(CWnd* pParent = NULL); // standard constructor
- virtual ~CSharedSecret();
-
-// Dialog Data
- enum { IDD = IDR_SECRET };
-
- void
- Load( CString zone );
-
- void
- Commit( CString zone );
-
-protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
-
- DECLARE_MESSAGE_MAP()
-
-public:
-
- CString m_key;
- CString m_secret;
-};
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
- <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
- </dependentAssembly>
- </dependency>
-</assembly>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
- <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
- </dependentAssembly>
- </dependency>
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
- </requestedPrivileges>
- </security>
- </trustInfo>
-</assembly>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
- <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
- </dependentAssembly>
- </dependency>
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
- </requestedPrivileges>
- </security>
- </trustInfo>
-</assembly>
+++ /dev/null
-//\r
-// CPL_PP.RC2 - resources Microsoft Visual C++ does not edit directly\r
-//\r
-\r
-#ifdef APSTUDIO_INVOKED\r
- #error this file is not editable by Microsoft Visual C++\r
-#endif //APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Add manually edited resources here...\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
- <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
- <dependency>
- <dependentAssembly>
- <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*" />
- </dependentAssembly>
- </dependency>
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
- </requestedPrivileges>
- </security>
- </trustInfo>
-</assembly>
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by ControlPanel.rc
-//
-#define IDR_APPLET 131
-#define IDR_APPLET_PAGE1 131
-#define IDS_APPLET_DESCRIPTION 132
-#define IDR_APPLET_PAGE2 132
-#define IDR_SECRET 133
-#define IDR_APPLET_PAGE3 134
-#define IDR_APPLET_PAGE4 135
-#define IDR_APPLET_PAGE5 136
-#define IDI_FAILURE 140
-#define IDI_SUCCESS 141
-#define IDI_ENERGY_SAVER 142
-#define IDR_ADD_BROWSE_DOMAIN 143
-#define IDR_POWER_MANAGEMENT_WARNING 144
-#define IDS_REINSTALL 145
-#define IDS_REINSTALL_CAPTION 146
-#define IDS_APPLET_NAME 147
-#define IDS_APPLET_TOOLTIP 148
-#define IDC_HOSTNAME 1000
-#define IDC_USERNAME 1001
-#define IDC_PASSWORD 1002
-#define IDC_ADVERTISE_SERVICES 1003
-#define IDC_BUTTON1 1004
-#define IDC_COMBO1 1005
-#define IDC_CHECK1 1006
-#define IDC_COMBO2 1007
-#define IDC_EDIT2 1008
-#define IDC_SECRET 1009
-#define IDC_COMBO3 1010
-#define IDC_FAILURE 1011
-#define IDC_SUCCESS 1012
-#define IDC_SECRET_NAME 1013
-#define IDC_NAME 1014
-#define IDC_KEY 1015
-#define IDC_LIST1 1016
-#define IDC_BROWSE_LIST 1017
-#define IDC_BUTTON2 1018
-#define IDC_REMOVE_BROWSE_DOMAIN 1019
-#define IDC_ADD_BROWSE_DOMAIN 1020
-#define IDC_POWER_MANAGEMENT 1021
-#define IDC_ADVERTISE_SMB 1022
-#define IDC_ENERGY_SAVER 1023
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 149
-#define _APS_NEXT_COMMAND_VALUE 32771
-#define _APS_NEXT_CONTROL_VALUE 1024
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+++ /dev/null
-/* -*- 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.
- */
-
-#include "stdafx.h"
-
-
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#ifndef VC_EXTRALEAN
-#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
-#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 95 and Windows NT 4 or later.
-#define WINVER 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
-#endif
-
-#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
-#define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
-#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
-
-// Step 3: We want to see one image, but not a tile
-#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later.
-#define _WIN32_IE 0x0500 // Change this to the appropriate value to target IE 5.0 or later.
-#endif
-
-#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
-
-// turns off MFC's hiding of some common and often safely ignored warning messages
-#define _AFX_ALL_WARNINGS
-
-#if !defined(_WSPIAPI_COUNTOF)
-# define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
-#endif
-
-#include <afxwin.h> // MFC core and standard components
-#include <afxext.h> // MFC extensions
-#include <afxdisp.h> // MFC Automation classes
-
-#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-#include <afxcmn.h> // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-#include <afxdlgs.h>
-
-#include <cpl.h> // Control Panel Applet functions and defines
-
-#include <afxtempl.h> // MFC Template support
+++ /dev/null
-/* -*- 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.
- */
-
-#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
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-//
-[assembly:AssemblyTitleAttribute("dnssd.NET")];
-[assembly:AssemblyDescriptionAttribute(".NET wrapper for DNS-SD services")];
-[assembly:AssemblyConfigurationAttribute("")];
-[assembly:AssemblyCompanyAttribute("Apple Inc.")];
-[assembly:AssemblyProductAttribute("")];
-[assembly:AssemblyCopyrightAttribute("Apple Inc.")];
-[assembly:AssemblyTrademarkAttribute("")];
-[assembly:AssemblyCultureAttribute("")];
-
-//
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the value or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-
-[assembly:AssemblyVersionAttribute(MASTER_PROD_VERS_STR2)];
-
-//
-// In order to sign your assembly you must specify a key to use. Refer to the
-// Microsoft .NET Framework documentation for more information on assembly
-// signing.
-//
-// Use the attributes below to control which key is used for signing.
-//
-// Notes:
-// (*) If no key is specified, the assembly is not signed.
-// (*) KeyName refers to a key that has been installed in the Crypto Service
-// Provider (CSP) on your machine. KeyFile refers to a file which contains
-// a key.
-// (*) If the KeyFile and the KeyName values are both specified, the
-// following processing occurs:
-// (1) If the KeyName can be found in the CSP, that key is used.
-// (2) If the KeyName does not exist and the KeyFile does exist, the key
-// in the KeyFile is installed into the CSP and used.
-// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name)
-// utility
-// When specifying the KeyFile, the location of the KeyFile should be
-// relative to the project directory.
-// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
-// documentation for more information on this.
-//
-[assembly:AssemblyDelaySignAttribute(false)];
-[assembly:AssemblyKeyFileAttribute("dnssd_NET.snk")];
-[assembly:AssemblyKeyNameAttribute("")];
-
-[assembly:ComVisible(false)];
-[assembly:CLSCompliantAttribute(true)];
-[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-using namespace System;
-using namespace System::Text;
-
-namespace Apple
-{
- __gc class PString
- {
- public:
-
- PString(String* string)
- {
- if (string != NULL)
- {
- Byte unicodeBytes[] = Encoding::Unicode->GetBytes(string);
- Byte utf8Bytes[] = Encoding::Convert(Encoding::Unicode, Encoding::UTF8, unicodeBytes);
- m_p = Marshal::AllocHGlobal(utf8Bytes->Length + 1);
-
- Byte __pin * p = &utf8Bytes[0];
- char * hBytes = static_cast<char*>(m_p.ToPointer());
- memcpy(hBytes, p, utf8Bytes->Length);
- hBytes[utf8Bytes->Length] = '\0';
- }
- else
- {
- m_p = NULL;
- }
- }
-
- ~PString()
- {
- Marshal::FreeHGlobal(m_p);
- }
-
- const char*
- c_str()
- {
- if (m_p != NULL)
- {
- return static_cast<const char*>(m_p.ToPointer());
- }
- else
- {
- return NULL;
- }
- }
-
- protected:
-
- IntPtr m_p;
- };
-}
+++ /dev/null
-/* -*- 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.
- */
-
-// stdafx.cpp : source file that includes just the standard includes
-// dotNET.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
+++ /dev/null
-/* -*- 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.
- */
-
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently,
-// but are changed infrequently
-
-#pragma once
-
-#if !defined(_WSPIAPI_COUNTOF)
-# define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
-#endif
-
-#using <mscorlib.dll>
-#using <System.dll>
-
-struct _DNSServiceRef_t {};
-struct _DNSRecordRef_t {};
-
+++ /dev/null
-/* -*- 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.
- */
-
-// This is the main DLL file.
-
-#include "stdafx.h"
-
-#include "dnssd_NET.h"
-#include "DebugServices.h"
-#include "PString.h"
-
-
-using namespace System::Net::Sockets;
-using namespace System::Diagnostics;
-using namespace Apple;
-using namespace Apple::DNSSD;
-
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME "[dnssd.NET] "
-
-//
-// ConvertToString
-//
-static String*
-ConvertToString(const char * utf8String)
-{
- return __gc new String(utf8String, 0, strlen(utf8String), __gc new UTF8Encoding(true, true));
-}
-
-
-//
-// class ServiceRef
-//
-// ServiceRef serves as the base class for all DNSService operations.
-//
-// It manages the DNSServiceRef, and implements processing the
-// result
-//
-ServiceRef::ServiceRef(Object * callback)
-:
- m_bDisposed(false),
- m_callback(callback),
- m_thread(NULL)
-{
- m_impl = new ServiceRefImpl(this);
-}
-
-
-ServiceRef::~ServiceRef()
-{
-}
-
-
-//
-// StartThread
-//
-// Starts the main processing thread
-//
-void
-ServiceRef::StartThread()
-{
- check( m_impl != NULL );
-
- m_impl->SetupEvents();
-
- m_thread = new Thread(new ThreadStart(this, &Apple::DNSSD::ServiceRef::ProcessingThread));
- m_thread->Name = S"DNSService Thread";
- m_thread->IsBackground = true;
-
- m_thread->Start();
-}
-
-
-//
-// ProcessingThread
-//
-// The Thread class can only invoke methods in MC++ types. So we
-// make a ProcessingThread method that forwards to the impl
-//
-void
-ServiceRef::ProcessingThread()
-{
- m_impl->ProcessingThread();
-}
-
-
-//
-// Dispose
-//
-// Calls impl-Dispose(). This ultimately will call DNSServiceRefDeallocate()
-//
-void
-ServiceRef::Dispose()
-{
- check(m_impl != NULL);
- check(m_bDisposed == false);
-
- if (!m_bDisposed)
- {
- m_bDisposed = true;
-
- //
- // Call Dispose. This won't call DNSServiceRefDeallocate()
- // necessarily. It depends on what thread this is being
- // called in.
- //
- m_impl->Dispose();
- m_impl = NULL;
-
- m_thread = NULL;
-
- GC::SuppressFinalize(this);
- }
-}
-
-
-//
-// EnumerateDomainsDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::EnumerateDomainsDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * replyDomain
- )
-{
- if ((m_callback != NULL) && (m_impl != NULL))
- {
- DNSService::EnumerateDomainsReply * OnEnumerateDomainsReply = static_cast<DNSService::EnumerateDomainsReply*>(m_callback);
- OnEnumerateDomainsReply(this, flags, interfaceIndex, errorCode, replyDomain);
- }
-}
-
-
-//
-// RegisterDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::RegisterDispatch
- (
- ServiceFlags flags,
- ErrorCode errorCode,
- String * name,
- String * regtype,
- String * domain
- )
-{
- if ((m_callback != NULL) && (m_impl != NULL))
- {
- DNSService::RegisterReply * OnRegisterReply = static_cast<DNSService::RegisterReply*>(m_callback);
- OnRegisterReply(this, flags, errorCode, name, regtype, domain);
- }
-}
-
-
-//
-// BrowseDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::BrowseDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * serviceName,
- String * regtype,
- String * replyDomain
- )
-{
- if ((m_callback != NULL) && (m_impl != NULL))
- {
- DNSService::BrowseReply * OnBrowseReply = static_cast<DNSService::BrowseReply*>(m_callback);
- OnBrowseReply(this, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
- }
-}
-
-
-//
-// ResolveDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::ResolveDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * fullname,
- String * hosttarget,
- int port,
- Byte txtRecord[]
- )
-{
- if ((m_callback != NULL) && (m_impl != NULL))
- {
- DNSService::ResolveReply * OnResolveReply = static_cast<DNSService::ResolveReply*>(m_callback);
- OnResolveReply(this, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord);
- }
-}
-
-
-//
-// RegisterRecordDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::RegisterRecordDispatch
- (
- ServiceFlags flags,
- ErrorCode errorCode,
- RecordRef * record
- )
-{
- if ((m_callback != NULL) && (m_impl != NULL))
- {
- DNSService::RegisterRecordReply * OnRegisterRecordReply = static_cast<DNSService::RegisterRecordReply*>(m_callback);
- OnRegisterRecordReply(this, flags, errorCode, record);
- }
-}
-
-
-//
-// QueryRecordDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::QueryRecordDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * fullname,
- int rrtype,
- int rrclass,
- Byte rdata[],
- int ttl
- )
-{
- if ((m_callback != NULL) && (m_impl != NULL))
- {
- DNSService::QueryRecordReply * OnQueryRecordReply = static_cast<DNSService::QueryRecordReply*>(m_callback);
- OnQueryRecordReply(this, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdata, ttl);
- }
-}
-
-
-//
-// ServiceRefImpl::ServiceRefImpl()
-//
-// Constructs a new ServiceRefImpl. We save the pointer to our enclosing
-// class in a gcroot handle. This satisfies the garbage collector as
-// the outer class is a managed type
-//
-ServiceRef::ServiceRefImpl::ServiceRefImpl(ServiceRef * outer)
-:
- m_socketEvent(NULL),
- m_stopEvent(NULL),
- m_disposed(false),
- m_outer(outer),
- m_ref(NULL)
-{
- m_threadId = GetCurrentThreadId();
-}
-
-
-//
-// ServiceRefImpl::~ServiceRefImpl()
-//
-// Deallocate all resources associated with the ServiceRefImpl
-//
-ServiceRef::ServiceRefImpl::~ServiceRefImpl()
-{
- if (m_socketEvent != NULL)
- {
- CloseHandle(m_socketEvent);
- m_socketEvent = NULL;
- }
-
- if (m_stopEvent != NULL)
- {
- CloseHandle(m_stopEvent);
- m_stopEvent = NULL;
- }
-
- if (m_ref != NULL)
- {
- DNSServiceRefDeallocate(m_ref);
- m_ref = NULL;
- }
-}
-
-
-//
-// ServiceRefImpl::SetupEvents()
-//
-// Setup the events necessary to manage multi-threaded dispatch
-// of DNSService Events
-//
-void
-ServiceRef::ServiceRefImpl::SetupEvents()
-{
- check(m_ref != NULL);
-
- m_socket = (SOCKET) DNSServiceRefSockFD(m_ref);
- check(m_socket != INVALID_SOCKET);
-
- m_socketEvent = CreateEvent(NULL, 0, 0, NULL);
-
- if (m_socketEvent == NULL)
- {
- throw new DNSServiceException(Unknown);
- }
-
- int err = WSAEventSelect(m_socket, m_socketEvent, FD_READ|FD_CLOSE);
-
- if (err != 0)
- {
- throw new DNSServiceException(Unknown);
- }
-
- m_stopEvent = CreateEvent(NULL, 0, 0, NULL);
-
- if (m_stopEvent == NULL)
- {
- throw new DNSServiceException(Unknown);
- }
-}
-
-
-//
-// ServiceRefImpl::ProcessingThread()
-//
-// Wait for socket events on the DNSServiceRefSockFD(). Also wait
-// for stop events
-//
-void
-ServiceRef::ServiceRefImpl::ProcessingThread()
-{
- check( m_socketEvent != NULL );
- check( m_stopEvent != NULL );
- check( m_ref != NULL );
-
- HANDLE handles[2];
-
- handles[0] = m_socketEvent;
- handles[1] = m_stopEvent;
-
- while (m_disposed == false)
- {
- int ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
-
- //
- // it's a socket event
- //
- if (ret == WAIT_OBJECT_0)
- {
- DNSServiceProcessResult(m_ref);
- }
- //
- // else it's a stop event
- //
- else if (ret == WAIT_OBJECT_0 + 1)
- {
- break;
- }
- else
- {
- //
- // unexpected wait result
- //
- dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, ret );
- }
- }
-
- delete this;
-}
-
-
-//
-// ServiceRefImpl::Dispose()
-//
-// Calls DNSServiceRefDeallocate()
-//
-void
-ServiceRef::ServiceRefImpl::Dispose()
-{
- OSStatus err;
- BOOL ok;
-
- check(m_disposed == false);
-
- m_disposed = true;
-
- ok = SetEvent(m_stopEvent);
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
-
- return;
-}
-
-
-//
-// ServiceRefImpl::EnumerateDomainsCallback()
-//
-// This is the callback from dnssd.dll. We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * replyDomain,
- void * context
- )
-{
- ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
- check( self != NULL );
- check( self->m_outer != NULL );
-
- if (self->m_disposed == false)
- {
- self->m_outer->EnumerateDomainsDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(replyDomain));
- }
-}
-
-
-//
-// ServiceRefImpl::RegisterCallback()
-//
-// This is the callback from dnssd.dll. We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::RegisterCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- const char * name,
- const char * regtype,
- const char * domain,
- void * context
- )
-{
- ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
- check( self != NULL );
- check( self->m_outer != NULL );
-
- if (self->m_disposed == false)
- {
- self->m_outer->RegisterDispatch((ServiceFlags) flags, (ErrorCode) errorCode, ConvertToString(name), ConvertToString(regtype), ConvertToString(domain));
- }
-}
-
-
-//
-// ServiceRefImpl::BrowseCallback()
-//
-// This is the callback from dnssd.dll. We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::BrowseCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * serviceName,
- const char * regtype,
- const char * replyDomain,
- void * context
- )
-{
- ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
- check( self != NULL );
- check( self->m_outer != NULL );
-
- if (self->m_disposed == false)
- {
- self->m_outer->BrowseDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(serviceName), ConvertToString(regtype), ConvertToString(replyDomain));
- }
-}
-
-
-//
-// ServiceRefImpl::ResolveCallback()
-//
-// This is the callback from dnssd.dll. We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::ResolveCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * fullname,
- const char * hosttarget,
- uint16_t notAnIntPort,
- uint16_t txtLen,
- const char * txtRecord,
- void * context
- )
-{
- ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
- check( self != NULL );
- check( self->m_outer != NULL );
-
- if (self->m_disposed == false)
- {
- Byte txtRecordBytes[];
-
- txtRecordBytes = NULL;
-
- if (txtLen > 0)
- {
- //
- // copy raw memory into managed byte array
- //
- txtRecordBytes = new Byte[txtLen];
- Byte __pin * p = &txtRecordBytes[0];
- memcpy(p, txtRecord, txtLen);
- }
-
- self->m_outer->ResolveDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), ConvertToString(hosttarget), ntohs(notAnIntPort), txtRecordBytes);
- }
-}
-
-
-//
-// ServiceRefImpl::RegisterRecordCallback()
-//
-// This is the callback from dnssd.dll. We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::RegisterRecordCallback
- (
- DNSServiceRef sdRef,
- DNSRecordRef rrRef,
- DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- void * context
- )
-{
- ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
- check( self != NULL );
- check( self->m_outer != NULL );
-
- if (self->m_disposed == false)
- {
- RecordRef * record = NULL;
-
- if (errorCode == 0)
- {
- record = new RecordRef;
-
- record->m_impl->m_ref = rrRef;
- }
-
- self->m_outer->RegisterRecordDispatch((ServiceFlags) flags, (ErrorCode) errorCode, record);
- }
-}
-
-
-//
-// ServiceRefImpl::QueryRecordCallback()
-//
-// This is the callback from dnssd.dll. We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::QueryRecordCallback
- (
- DNSServiceRef DNSServiceRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void * rdata,
- uint32_t ttl,
- void * context
- )
-{
- ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
- check( self != NULL );
- check( self->m_outer != NULL );
-
- if (self->m_disposed == false)
- {
- Byte rdataBytes[];
-
- if (rdlen)
- {
- rdataBytes = new Byte[rdlen];
- Byte __pin * p = &rdataBytes[0];
- memcpy(p, rdata, rdlen);
- }
-
- self->m_outer->QueryRecordDispatch((ServiceFlags) flags, (int) interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), rrtype, rrclass, rdataBytes, ttl);
- }
-}
-
-
-/*
- * EnumerateDomains()
- *
- * This maps to DNSServiceEnumerateDomains(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::EnumerateDomains
- (
- int flags,
- int interfaceIndex,
- EnumerateDomainsReply * callback
- )
-{
- ServiceRef * sdRef = new ServiceRef(callback);
- int err;
-
- err = DNSServiceEnumerateDomains(&sdRef->m_impl->m_ref, flags, interfaceIndex, ServiceRef::ServiceRefImpl::EnumerateDomainsCallback, sdRef->m_impl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- sdRef->StartThread();
-
- return sdRef;
-}
-
-
-/*
- * Register()
- *
- * This maps to DNSServiceRegister(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::Register
- (
- int flags,
- int interfaceIndex,
- String * name,
- String * regtype,
- String * domain,
- String * host,
- int port,
- Byte txtRecord[],
- RegisterReply * callback
- )
-{
- ServiceRef * sdRef = new ServiceRef(callback);
- PString * pName = new PString(name);
- PString * pType = new PString(regtype);
- PString * pDomain = new PString(domain);
- PString * pHost = new PString(host);
- int len = 0;
- Byte __pin * p = NULL;
- void * v = NULL;
-
- if ((txtRecord != NULL) && (txtRecord->Length > 0))
- {
- len = txtRecord->Length;
- p = &txtRecord[0];
- v = (void*) p;
- }
-
- int err = DNSServiceRegister(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(), pHost->c_str(), htons(port), len, v, ServiceRef::ServiceRefImpl::RegisterCallback, sdRef->m_impl );
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- sdRef->StartThread();
-
- return sdRef;
-}
-
-
-/*
- * AddRecord()
- *
- * This maps to DNSServiceAddRecord(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-RecordRef*
-DNSService::AddRecord
- (
- ServiceRef * sdRef,
- int flags,
- int rrtype,
- Byte rdata[],
- int ttl
- )
-{
- int len = 0;
- Byte __pin * p = NULL;
- void * v = NULL;
-
- if ((rdata != NULL) && (rdata->Length > 0))
- {
- len = rdata->Length;
- p = &rdata[0];
- v = (void*) p;
- }
-
- RecordRef * record = new RecordRef;
-
- int err = DNSServiceAddRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, rrtype, len, v, ttl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- return record;
-}
-
-
-/*
- * UpdateRecord()
- *
- * This maps to DNSServiceUpdateRecord(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-void
-DNSService::UpdateRecord
- (
- ServiceRef * sdRef,
- RecordRef * record,
- int flags,
- Byte rdata[],
- int ttl
- )
-{
- int len = 0;
- Byte __pin * p = NULL;
- void * v = NULL;
-
- if ((rdata != NULL) && (rdata->Length > 0))
- {
- len = rdata->Length;
- p = &rdata[0];
- v = (void*) p;
- }
-
- int err = DNSServiceUpdateRecord(sdRef->m_impl->m_ref, record ? record->m_impl->m_ref : NULL, flags, len, v, ttl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-}
-
-
-/*
- * RemoveRecord()
- *
- * This maps to DNSServiceRemoveRecord(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-void
-DNSService::RemoveRecord
- (
- ServiceRef * sdRef,
- RecordRef * record,
- int flags
- )
-{
- int err = DNSServiceRemoveRecord(sdRef->m_impl->m_ref, record->m_impl->m_ref, flags);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-}
-
-
-/*
- * Browse()
- *
- * This maps to DNSServiceBrowse(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::Browse
- (
- int flags,
- int interfaceIndex,
- String * regtype,
- String * domain,
- BrowseReply * callback
- )
-{
- ServiceRef * sdRef = new ServiceRef(callback);
- PString * pType = new PString(regtype);
- PString * pDomain = new PString(domain);
-
- int err = DNSServiceBrowse(&sdRef->m_impl->m_ref, flags, interfaceIndex, pType->c_str(), pDomain->c_str(),(DNSServiceBrowseReply) ServiceRef::ServiceRefImpl::BrowseCallback, sdRef->m_impl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- sdRef->StartThread();
-
- return sdRef;
-}
-
-
-/*
- * Resolve()
- *
- * This maps to DNSServiceResolve(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::Resolve
- (
- int flags,
- int interfaceIndex,
- String * name,
- String * regtype,
- String * domain,
- ResolveReply * callback
- )
-{
- ServiceRef * sdRef = new ServiceRef(callback);
- PString * pName = new PString(name);
- PString * pType = new PString(regtype);
- PString * pDomain = new PString(domain);
-
- int err = DNSServiceResolve(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(),(DNSServiceResolveReply) ServiceRef::ServiceRefImpl::ResolveCallback, sdRef->m_impl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- sdRef->StartThread();
-
- return sdRef;
-}
-
-
-/*
- * CreateConnection()
- *
- * This maps to DNSServiceCreateConnection(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::CreateConnection
- (
- RegisterRecordReply * callback
- )
-{
- ServiceRef * sdRef = new ServiceRef(callback);
-
- int err = DNSServiceCreateConnection(&sdRef->m_impl->m_ref);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- sdRef->StartThread();
-
- return sdRef;
-}
-
-
-/*
- * RegisterRecord()
- *
- * This maps to DNSServiceRegisterRecord(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-
-RecordRef*
-DNSService::RegisterRecord
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- int interfaceIndex,
- String * fullname,
- int rrtype,
- int rrclass,
- Byte rdata[],
- int ttl
- )
-{
- RecordRef * record = new RecordRef;
- int len = 0;
- Byte __pin * p = NULL;
- void * v = NULL;
-
- PString * pFullname = new PString(fullname);
-
- if ((rdata != NULL) && (rdata->Length > 0))
- {
- len = rdata->Length;
- p = &rdata[0];
- v = (void*) p;
- }
-
- int err = DNSServiceRegisterRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v, ttl, (DNSServiceRegisterRecordReply) ServiceRef::ServiceRefImpl::RegisterRecordCallback, sdRef->m_impl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- return record;
-}
-
-/*
- * QueryRecord()
- *
- * This maps to DNSServiceQueryRecord(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::QueryRecord
- (
- ServiceFlags flags,
- int interfaceIndex,
- String * fullname,
- int rrtype,
- int rrclass,
- QueryRecordReply * callback
- )
-{
- ServiceRef * sdRef = new ServiceRef(callback);
- PString * pFullname = new PString(fullname);
-
- int err = DNSServiceQueryRecord(&sdRef->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, (DNSServiceQueryRecordReply) ServiceRef::ServiceRefImpl::QueryRecordCallback, sdRef->m_impl);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- sdRef->StartThread();
-
- return sdRef;
-}
-
-
-/*
- * ReconfirmRecord()
- *
- * This maps to DNSServiceReconfirmRecord(). Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-void
-DNSService::ReconfirmRecord
- (
- ServiceFlags flags,
- int interfaceIndex,
- String * fullname,
- int rrtype,
- int rrclass,
- Byte rdata[]
- )
-{
- int len = 0;
- Byte __pin * p = NULL;
- void * v = NULL;
-
- PString * pFullname = new PString(fullname);
-
- if ((rdata != NULL) && (rdata->Length > 0))
- {
- len = rdata->Length;
- p = &rdata[0];
- v = (void*) p;
- }
-
- DNSServiceReconfirmRecord(flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v);
-}
-
-
-void
-TextRecord::SetValue
- (
- String * key,
- Byte value[] /* may be NULL */
- )
-{
- PString * pKey = new PString(key);
- int len = 0;
- Byte __pin * p = NULL;
- void * v = NULL;
- DNSServiceErrorType err;
-
- if (value && (value->Length > 0))
- {
- len = value->Length;
- p = &value[0];
- v = (void*) p;
- }
-
- err = TXTRecordSetValue(&m_impl->m_ref, pKey->c_str(), len, v);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-}
-
-
-void
-TextRecord::RemoveValue
- (
- String * key
- )
-{
- PString * pKey = new PString(key);
- DNSServiceErrorType err;
-
- err = TXTRecordRemoveValue(&m_impl->m_ref, pKey->c_str());
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-}
-
-
-int
-TextRecord::GetLength
- (
- )
-{
- return TXTRecordGetLength(&m_impl->m_ref);
-}
-
-
-Byte
-TextRecord::GetBytes
- (
- ) __gc[]
-{
- const void * noGCBytes = NULL;
- Byte gcBytes[] = NULL;
-
- noGCBytes = TXTRecordGetBytesPtr(&m_impl->m_ref);
- int len = GetLength();
-
- if (noGCBytes && len)
- {
- gcBytes = new Byte[len];
- Byte __pin * p = &gcBytes[0];
- memcpy(p, noGCBytes, len);
- }
-
- return gcBytes;
-}
-
-
-bool
-TextRecord::ContainsKey
- (
- Byte txtRecord[],
- String * key
- )
-{
- PString * pKey = new PString(key);
- Byte __pin * p = &txtRecord[0];
-
- return (TXTRecordContainsKey(txtRecord->Length, p, pKey->c_str()) > 0) ? true : false;
-}
-
-
-Byte
-TextRecord::GetValueBytes
- (
- Byte txtRecord[],
- String * key
- ) __gc[]
-{
- uint8_t valueLen;
- Byte ret[] = NULL;
- PString * pKey = new PString(key);
- Byte __pin * p1 = &txtRecord[0];
- const void * v;
-
- v = TXTRecordGetValuePtr(txtRecord->Length, p1, pKey->c_str(), &valueLen);
-
- if (v != NULL)
- {
- ret = new Byte[valueLen];
- Byte __pin * p2 = &ret[0];
-
- memcpy(p2, v, valueLen);
- }
-
- return ret;
-}
-
-
-int
-TextRecord::GetCount
- (
- Byte txtRecord[]
- )
-{
- Byte __pin * p = &txtRecord[0];
-
- return TXTRecordGetCount(txtRecord->Length, p);
-}
-
-
-Byte
-TextRecord::GetItemAtIndex
- (
- Byte txtRecord[],
- int index,
- [Out] String ** key
- ) __gc[]
-{
- char keyBuf[255];
- uint8_t keyBufLen = 255;
- uint8_t valueLen;
- void * value;
- Byte ret[] = NULL;
- DNSServiceErrorType err;
- Byte __pin * p1 = &txtRecord[0];
-
-
- err = TXTRecordGetItemAtIndex(txtRecord->Length, p1, index, keyBufLen, keyBuf, &valueLen, (const void**) &value);
-
- if (err != 0)
- {
- throw new DNSServiceException(err);
- }
-
- *key = ConvertToString(keyBuf);
-
- if (valueLen)
- {
- ret = new Byte[valueLen];
- Byte __pin * p2 = &ret[0];
-
- memcpy(p2, value, valueLen);
- }
-
- return ret;
-}
-
-
-//
-// DNSServiceException::DNSServiceException()
-//
-// Constructs an exception with an error code
-//
-DNSServiceException::DNSServiceException
- (
- int _err
- )
-:
- err(_err)
-{
-}
-
-
-//
-// This version of the constructor is useful for instances in which
-// an inner exception is thrown, caught, and then a new exception
-// is thrown in it's place
-//
-DNSServiceException::DNSServiceException
- (
- String * message,
- System::Exception * innerException
- )
-{
-}
+++ /dev/null
-/* -*- 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.
-
- *
- * NOTE:
- *
- * These .Net APIs are a work in progress, currently being discussed and refined.
- * If you plan to build an application based on these APIs, you may wish to
- * statically link this code into your application, or otherwise distribute
- * the DLL so that it installs into the same folder as your application
- * (not into any common system area where it might interfere with other
- * applications using a future completed version of these APIs).
- * If you plan to do this, please be sure to inform us by sending email
- * to bonjour@apple.com to let us know.
- * You may want to discuss what you're doing on the Bonjour mailing
- * list to see if others in similar positions have any suggestions for you:
- *
- * <http://lists.apple.com/bonjour-dev/>
- *
- */
-
-#pragma once
-
-#include <dns_sd.h>
-#include <vcclr.h>
-#include <memory>
-#include <winsock2.h>
-
-using namespace System;
-using namespace System::Net;
-using namespace System::Runtime::InteropServices;
-using namespace System::Threading;
-using namespace System::Collections;
-
-
-namespace Apple
-{
- namespace DNSSD
- {
- public __gc class ServiceRef;
-
- public __value enum ServiceFlags : int
- {
- MoreComing = 1,
- /* MoreComing indicates to a callback that at least one more result is
- * queued and will be delivered following immediately after this one.
- * Applications should not update their UI to display browse
- * results when the MoreComing flag is set, because this would
- * result in a great deal of ugly flickering on the screen.
- * Applications should instead wait until until MoreComing is not set,
- * and then update their UI.
- * When MoreComing is not set, that doesn't mean there will be no more
- * answers EVER, just that there are no more answers immediately
- * available right now at this instant. If more answers become available
- * in the future they will be delivered as usual.
- */
-
- Add = 2,
- Default = 4,
- /* Flags for domain enumeration and browse/query reply callbacks.
- * "Default" applies only to enumeration and is only valid in
- * conjuction with "Add". An enumeration callback with the "Add"
- * flag NOT set indicates a "Remove", i.e. the domain is no longer
- * valid.
- */
-
- NoAutoRename = 8,
- /* Flag for specifying renaming behavior on name conflict when registering
- * non-shared records. By default, name conflicts are automatically handled
- * by renaming the service. NoAutoRename overrides this behavior - with this
- * flag set, name conflicts will result in a callback. The NoAutorename flag
- * is only valid if a name is explicitly specified when registering a service
- * (i.e. the default name is not used.)
- */
-
- Shared = 16,
- Unique = 32,
- /* Flag for registering individual records on a connected
- * DNSServiceRef. Shared indicates that there may be multiple records
- * with this name on the network (e.g. PTR records). Unique indicates that
- the
- * record's name is to be unique on the network (e.g. SRV records).
- */
-
- BrowseDomains = 64,
- RegistrationDomains = 128,
- /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomain
- s.
- * BrowseDomains enumerates domains recommended for browsing, RegistrationDo
- mains
- * enumerates domains recommended for registration.
- */
- };
-
-
- public __value enum ErrorCode : int
- {
- NoError = 0,
- Unknown = -65537,
- NoSuchName = -65538,
- NoMemory = -65539,
- BadParam = -65540,
- BadReference = -65541,
- BadState = -65542,
- BadFlags = -65543,
- Unsupported = -65544,
- AlreadyRegistered = -65547,
- NameConflict = -65548,
- Invalid = -65549,
- Incompatible = -65551,
- BadinterfaceIndex = -65552
-
- /*
- * mDNS Error codes are in the range
- * FFFE FF00 (-65792) to FFFE FFFF (-65537)
- */
- };
-
- public __gc class DNSServiceException
- :
- public Exception
- {
- public:
-
- DNSServiceException
- (
- int err
- );
-
- DNSServiceException
- (
- String * message,
- System::Exception * innerException
- );
-
- int err;
- };
-
-
- /*
- * class RecordRef
- *
- * This is a thin MC++ class facade on top of a DNSRecordRef
- */
- public __gc class RecordRef
- {
- public:
-
- RecordRef()
- {
- m_impl = new RecordRefImpl;
- m_impl->m_ref = NULL;
- }
-
- ~RecordRef()
- {
- delete m_impl;
- }
-
- __nogc class RecordRefImpl
- {
- public:
-
- DNSRecordRef m_ref;
- };
-
- RecordRefImpl * m_impl;
- };
-
-
- /*
- * class ServiceRef
- *
- * This is a thin MC++ class facade on top of a DNSServiceRef
- */
- public __gc class ServiceRef : public IDisposable
- {
- public:
-
- ServiceRef(Object * callback);
-
- ~ServiceRef();
-
- /*
- * This does an underlying DNSServiceRefDeallocate(). After
- * calling Dispose, the ServiceRef is no longer usable.
- */
- void
- Dispose();
-
- /*
- * Internal - Dispatch an EnumerateDomains callback
- */
- void
- EnumerateDomainsDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * replyDomain
- );
-
- /*
- * Internal - Dispatch a Register callback
- */
- void
- RegisterDispatch
- (
- ServiceFlags flags,
- ErrorCode errorCode,
- String * name,
- String * regtype,
- String * domain
- );
-
- /*
- * Internal - Dispatch a Browse callback
- */
- void
- BrowseDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * serviceName,
- String * regtype,
- String * replyDomain
- );
-
- /*
- * Internal - Dispatch a Resolve callback
- */
- void
- ResolveDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * fullname,
- String * hosttarget,
- int port,
- Byte txtRecord[]
- );
-
- /*
- * Internal - Dispatch a RegisterRecord callback
- */
- void
- RegisterRecordDispatch
- (
- ServiceFlags flags,
- ErrorCode errorCode,
- RecordRef * record
- );
-
- /*
- * Internal - Dispatch a QueryRecord callback
- */
- void
- QueryRecordDispatch
- (
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * fullname,
- int rrtype,
- int rrclass,
- Byte rdata[],
- int ttl
- );
-
- /*
- * Internal - A non managed class to wrap a DNSServiceRef
- */
- __nogc class ServiceRefImpl
- {
- public:
-
- ServiceRefImpl
- (
- ServiceRef * outer
- );
-
- ~ServiceRefImpl();
-
- /*
- * Sets up events for threaded operation
- */
- void
- SetupEvents();
-
- /*
- * Main processing thread
- */
- void
- ProcessingThread();
-
- /*
- * Calls DNSServiceRefDeallocate()
- */
- void
- Dispose();
-
- /*
- * Called from dnssd.dll
- */
- static void DNSSD_API
- EnumerateDomainsCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * replyDomain,
- void * context
- );
-
- static void DNSSD_API
- RegisterCallback
- (
- DNSServiceRef ref,
- DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- const char * name,
- const char * regtype,
- const char * domain,
- void * context
- );
-
- static void DNSSD_API
- BrowseCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * serviceName,
- const char * regtype,
- const char * replyDomain,
- void * context
- );
-
- static void DNSSD_API
- ResolveCallback
- (
- DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * fullname,
- const char * hosttarget,
- uint16_t notAnIntPort,
- uint16_t txtLen,
- const char * txtRecord,
- void * context
- );
-
- static void DNSSD_API
- RegisterRecordCallback
- (
- DNSServiceRef sdRef,
- DNSRecordRef RecordRef,
- DNSServiceFlags flags,
- DNSServiceErrorType errorCode,
- void * context
- );
-
- static void DNSSD_API
- QueryRecordCallback
- (
- DNSServiceRef DNSServiceRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char * fullname,
- uint16_t rrtype,
- uint16_t rrclass,
- uint16_t rdlen,
- const void * rdata,
- uint32_t ttl,
- void * context
- );
-
- SOCKET m_socket;
- HANDLE m_socketEvent;
- HANDLE m_stopEvent;
- DWORD m_threadId;
- bool m_disposed;
- DNSServiceRef m_ref;
- gcroot<ServiceRef*> m_outer;
- };
-
- void
- StartThread();
-
- void
- ProcessingThread();
-
- bool m_bDisposed;
- Object * m_callback;
- Thread * m_thread;
- ServiceRefImpl * m_impl;
- };
-
- /*********************************************************************************************
- *
- * TXT Record Construction Functions
- *
- *********************************************************************************************/
-
- /*
- * A typical calling sequence for TXT record construction is something like:
- *
- * DNSService.TextRecord tr = new DNSService.TextRecord(1024);
- * tr.SetValue();
- * tr.SetValue();
- * tr.SetValue();
- * ...
- * DNSServiceRegister( ... tr.GetLength(), tr.GetBytes() ... );
- */
-
-
- /* TextRecord
- *
- * Opaque internal data type.
- * Note: Represents a DNS-SD TXT record.
- */
-
-
- /* TextRecord::TextRecord()
- *
- * Creates a new empty TextRecord .
- *
- */
-
- public __gc class TextRecord
- {
- public:
-
- TextRecord()
- {
- m_impl = new TextRecordImpl();
- TXTRecordCreate(&m_impl->m_ref, 0, NULL);
- }
-
- ~TextRecord()
- {
- TXTRecordDeallocate(&m_impl->m_ref);
- delete m_impl;
- }
-
- __nogc class TextRecordImpl
- {
- public:
-
- TXTRecordRef m_ref;
- };
-
- TextRecordImpl * m_impl;
-
-
- /* SetValue()
- *
- * Adds a key (optionally with value) to a TextRecord. If the "key" already
- * exists in the TextRecord, then the current value will be replaced with
- * the new value.
- * Keys may exist in four states with respect to a given TXT record:
- * - Absent (key does not appear at all)
- * - Present with no value ("key" appears alone)
- * - Present with empty value ("key=" appears in TXT record)
- * - Present with non-empty value ("key=value" appears in TXT record)
- * For more details refer to "Data Syntax for DNS-SD TXT Records" in
- * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
- *
- * key: A null-terminated string which only contains printable ASCII
- * values (0x20-0x7E), excluding '=' (0x3D). Keys should be
- * 14 characters or less (not counting the terminating null).
- *
- * value: Any binary value. For values that represent
- * textual data, UTF-8 is STRONGLY recommended.
- * For values that represent textual data, valueSize
- * should NOT include the terminating null (if any)
- * at the end of the string.
- * If NULL, then "key" will be added with no value.
- * If non-NULL but valueSize is zero, then "key=" will be
- * added with empty value.
- *
- * exceptions: Throws kDNSServiceErr_Invalid if the "key" string contains
- * illegal characters.
- * Throws kDNSServiceErr_NoMemory if adding this key would
- * exceed the available storage.
- */
-
- void
- SetValue
- (
- String * key,
- Byte value[] /* may be NULL */
- );
-
-
- /* RemoveValue()
- *
- * Removes a key from a TextRecord. The "key" must be an
- * ASCII string which exists in the TextRecord.
- *
- * key: A key name which exists in the TextRecord.
- *
- * exceptions: Throws kDNSServiceErr_NoSuchKey if the "key" does not
- * exist in the TextRecord.
- *
- */
-
- void
- RemoveValue
- (
- String * key
- );
-
-
- /* GetLength()
- *
- * Allows you to determine the length of the raw bytes within a TextRecord.
- *
- * return value : Returns the size of the raw bytes inside a TextRecord
- * which you can pass directly to DNSServiceRegister() or
- * to DNSServiceUpdateRecord().
- * Returns 0 if the TextRecord is empty.
- *
- */
-
- int
- GetLength
- (
- );
-
-
- /* GetBytes()
- *
- * Allows you to retrieve a pointer to the raw bytes within a TextRecord.
- *
- * return value: Returns a pointer to the bytes inside the TextRecord
- * which you can pass directly to DNSServiceRegister() or
- * to DNSServiceUpdateRecord().
- *
- */
-
- Byte
- GetBytes
- (
- ) __gc[];
-
-
- /*********************************************************************************************
- *
- * TXT Record Parsing Functions
- *
- *********************************************************************************************/
-
- /*
- * A typical calling sequence for TXT record parsing is something like:
- *
- * Receive TXT record data in DNSServiceResolve() callback
- * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
- * val1ptr = DNSService.TextService.GetValue(txtRecord, "key1", &len1);
- * val2ptr = DNSService.TextService.GetValue(txtRecord, "key2", &len2);
- * ...
- * return;
- *
- */
-
- /* ContainsKey()
- *
- * Allows you to determine if a given TXT Record contains a specified key.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * key: A null-terminated ASCII string containing the key name.
- *
- * return value: Returns 1 if the TXT Record contains the specified key.
- * Otherwise, it returns 0.
- *
- */
-
- static public bool
- ContainsKey
- (
- Byte txtRecord[],
- String * key
- );
-
-
- /* GetValueBytes()
- *
- * Allows you to retrieve the value for a given key from a TXT Record.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * key: A null-terminated ASCII string containing the key name.
- *
- * return value: Returns NULL if the key does not exist in this TXT record,
- * or exists with no value (to differentiate between
- * these two cases use ContainsKey()).
- * Returns byte array
- * if the key exists with empty or non-empty value.
- * For empty value, length of byte array will be zero.
- * For non-empty value, it will be the length of value data.
- */
-
- static public Byte
- GetValueBytes
- (
- Byte txtRecord[],
- String * key
- ) __gc[];
-
-
- /* GetCount()
- *
- * Returns the number of keys stored in the TXT Record. The count
- * can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * return value: Returns the total number of keys in the TXT Record.
- *
- */
-
- static public int
- GetCount
- (
- Byte txtRecord[]
- );
-
-
- /* GetItemAtIndex()
- *
- * Allows you to retrieve a key name and value pointer, given an index into
- * a TXT Record. Legal index values range from zero to TXTRecordGetCount()-1.
- * It's also possible to iterate through keys in a TXT record by simply
- * calling TXTRecordGetItemAtIndex() repeatedly, beginning with index zero
- * and increasing until TXTRecordGetItemAtIndex() returns kDNSServiceErr_Invalid.
- *
- * On return:
- * For keys with no value, *value is set to NULL and *valueLen is zero.
- * For keys with empty value, *value is non-NULL and *valueLen is zero.
- * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
- *
- * txtRecord: Pointer to the received TXT Record bytes.
- *
- * index: An index into the TXT Record.
- *
- * key: A string buffer used to store the key name.
- * On return, the buffer contains a string
- * giving the key name. DNS-SD TXT keys are usually
- * 14 characters or less.
- *
- * return value: Record bytes that holds the value data.
- *
- * exceptions: Throws kDNSServiceErr_Invalid if index is greater than
- * GetCount()-1.
- */
-
- static public Byte
- GetItemAtIndex
- (
- Byte txtRecord[],
- int index,
- [Out] String ** key
- ) __gc[];
- };
-
-
- public __abstract __gc class DNSService
- {
- public:
-
- /*********************************************************************************************
- *
- * Domain Enumeration
- *
- *********************************************************************************************/
-
- /* DNSServiceEnumerateDomains()
- *
- * Asynchronously enumerate domains available for browsing and registration.
- * Currently, the only domain returned is "local.", but other domains will be returned in future.
- *
- * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
- * are to be found.
- *
- *
- * EnumerateDomainsReply Delegate
- *
- * This Delegate is invoked upon a reply from an EnumerateDomains call.
- *
- * sdRef: The DNSServiceRef initialized by DNSServiceEnumerateDomains().
- *
- * flags: Possible values are:
- * MoreComing
- * Add
- * Default
- *
- * interfaceIndex: Specifies the interface on which the domain exists. (The index for a given
- * interface is determined via the if_nametoindex() family of calls.)
- *
- * errorCode: Will be NoError (0) on success, otherwise indicates
- * the failure that occurred (other parameters are undefined if errorCode is nonzero).
- *
- * replyDomain: The name of the domain.
- *
- */
-
- __delegate void
- EnumerateDomainsReply
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * replyDomain
- );
-
- /* DNSServiceEnumerateDomains() Parameters:
- *
- *
- * flags: Possible values are:
- * BrowseDomains to enumerate domains recommended for browsing.
- * RegistrationDomains to enumerate domains recommended
- * for registration.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to look for domains.
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to enumerate domains on
- * all interfaces.
- *
- * callback: The delegate to be called when a domain is found or the call asynchronously
- * fails.
- *
- *
- * return value: Returns initialize ServiceRef on succeses (any subsequent, asynchronous
- * errors are delivered to the delegate), otherwise throws an exception indicating
- * the error that occurred (the callback is not invoked and the ServiceRef
- * is not initialized.)
- */
-
- static public ServiceRef*
- EnumerateDomains
- (
- int flags,
- int interfaceIndex,
- EnumerateDomainsReply * callback
- );
-
- /*********************************************************************************************
- *
- * Service Registration
- *
- *********************************************************************************************/
-
- /* Register a service that is discovered via Browse() and Resolve() calls.
- *
- * RegisterReply() Callback Parameters:
- *
- * sdRef: The ServiceRef initialized by Register().
- *
- * flags: Currently unused, reserved for future use.
- *
- * errorCode: Will be NoError on success, otherwise will
- * indicate the failure that occurred (including name conflicts, if the
- * NoAutoRename flag was passed to the
- * callout.) Other parameters are undefined if errorCode is nonzero.
- *
- * name: The service name registered (if the application did not specify a name in
- * DNSServiceRegister(), this indicates what name was automatically chosen).
- *
- * regtype: The type of service registered, as it was passed to the callout.
- *
- * domain: The domain on which the service was registered (if the application did not
- * specify a domain in Register(), this indicates the default domain
- * on which the service was registered).
- *
- */
-
- __delegate void
- RegisterReply
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- ErrorCode errorCode,
- String * name,
- String * regtype,
- String * domain
- );
-
- /* Register() Parameters:
- *
- * flags: Indicates the renaming behavior on name conflict (most applications
- * will pass 0). See flag definitions above for details.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to register the service
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to register on all
- * available interfaces. Pass -1 to register a service only on the local
- * machine (service will not be visible to remote hosts.)
- *
- * name: If non-NULL, specifies the service name to be registered.
- * Most applications will not specify a name, in which case the
- * computer name is used (this name is communicated to the client via
- * the callback).
- *
- * regtype: The service type followed by the protocol, separated by a dot
- * (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
- * New service types should be registered at htp://www.dns-sd.org/ServiceTypes.html.
- *
- * domain: If non-NULL, specifies the domain on which to advertise the service.
- * Most applications will not specify a domain, instead automatically
- * registering in the default domain(s).
- *
- * host: If non-NULL, specifies the SRV target host name. Most applications
- * will not specify a host, instead automatically using the machine's
- * default host name(s). Note that specifying a non-NULL host does NOT
- * create an address record for that host - the application is responsible
- * for ensuring that the appropriate address record exists, or creating it
- * via DNSServiceRegisterRecord().
- *
- * port: The port, in host byte order, on which the service accepts connections.
- * Pass 0 for a "placeholder" service (i.e. a service that will not be discovered
- * by browsing, but will cause a name conflict if another client tries to
- * register that same name). Most clients will not use placeholder services.
- *
- * txtRecord: The txt record rdata. May be NULL. Note that a non-NULL txtRecord
- * MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
- * <length byte> <data> ...
- *
- * callback: The delegate to be called when the registration completes or asynchronously
- * fails. The client MAY pass NULL for the callback - The client will NOT be notified
- * of the default values picked on its behalf, and the client will NOT be notified of any
- * asynchronous errors (e.g. out of memory errors, etc.) that may prevent the registration
- * of the service. The client may NOT pass the NoAutoRename flag if the callback is NULL.
- * The client may still deregister the service at any time via DNSServiceRefDeallocate().
- *
- * return value: Returns initialize ServiceRef (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise throws an exception indicating
- * the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized.)
- *
- */
- static public ServiceRef*
- Register
- (
- int flags,
- int interfaceIndex,
- String * name,
- String * regtype,
- String * domain,
- String * host,
- int port,
- Byte txtRecord[],
- RegisterReply * callback
- );
-
- /* AddRecord()
- *
- * Add a record to a registered service. The name of the record will be the same as the
- * registered service's name.
- * The record can later be updated or deregistered by passing the RecordRef initialized
- * by this function to UpdateRecord() or RemoveRecord().
- *
- *
- * Parameters;
- *
- * sdRef: A ServiceRef initialized by Register().
- *
- * RecordRef: A pointer to an uninitialized RecordRef. Upon succesfull completion of this
- * call, this ref may be passed to UpdateRecord() or RemoveRecord().
- * If the above ServiceRef is disposed, RecordRef is also
- * invalidated and may not be used further.
- *
- * flags: Currently ignored, reserved for future use.
- *
- * rrtype: The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
- *
- * rdata: The raw rdata to be contained in the added resource record.
- *
- * ttl: The time to live of the resource record, in seconds.
- *
- * return value: Returns initialized RecordRef, otherwise throws
- * an exception indicating the error that occurred (the RecordRef is not initialized).
- */
-
- static public RecordRef*
- AddRecord
- (
- ServiceRef * sref,
- int flags,
- int rrtype,
- Byte rdata[],
- int ttl
- );
-
- /* UpdateRecord
- *
- * Update a registered resource record. The record must either be:
- * - The primary txt record of a service registered via Register()
- * - A record added to a registered service via AddRecord()
- * - An individual record registered by RegisterRecord()
- *
- *
- * Parameters:
- *
- * sdRef: A ServiceRef that was initialized by Register()
- * or CreateConnection().
- *
- * RecordRef: A RecordRef initialized by AddRecord, or NULL to update the
- * service's primary txt record.
- *
- * flags: Currently ignored, reserved for future use.
- *
- * rdata: The new rdata to be contained in the updated resource record.
- *
- * ttl: The time to live of the updated resource record, in seconds.
- *
- * return value: No return value on success, otherwise throws an exception
- * indicating the error that occurred.
- */
- static public void
- UpdateRecord
- (
- ServiceRef * sref,
- RecordRef * record,
- int flags,
- Byte rdata[],
- int ttl
- );
-
- /* RemoveRecord
- *
- * Remove a record previously added to a service record set via AddRecord(), or deregister
- * an record registered individually via RegisterRecord().
- *
- * Parameters:
- *
- * sdRef: A ServiceRef initialized by Register() (if the
- * record being removed was registered via AddRecord()) or by
- * CreateConnection() (if the record being removed was registered via
- * RegisterRecord()).
- *
- * recordRef: A RecordRef initialized by a successful call to AddRecord()
- * or RegisterRecord().
- *
- * flags: Currently ignored, reserved for future use.
- *
- * return value: Nothing on success, otherwise throws an
- * exception indicating the error that occurred.
- */
-
- static public void
- RemoveRecord
- (
- ServiceRef * sref,
- RecordRef * record,
- int flags
- );
-
- /*********************************************************************************************
- *
- * Service Discovery
- *
- *********************************************************************************************/
-
- /* Browse for instances of a service.
- *
- *
- * BrowseReply() Parameters:
- *
- * sdRef: The DNSServiceRef initialized by Browse().
- *
- * flags: Possible values are MoreComing and Add.
- * See flag definitions for details.
- *
- * interfaceIndex: The interface on which the service is advertised. This index should
- * be passed to Resolve() when resolving the service.
- *
- * errorCode: Will be NoError (0) on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * the errorCode is nonzero.
- *
- * serviceName: The service name discovered.
- *
- * regtype: The service type, as passed in to Browse().
- *
- * domain: The domain on which the service was discovered (if the application did not
- * specify a domain in Browse(), this indicates the domain on which the
- * service was discovered.)
- *
- */
-
- __delegate void
- BrowseReply
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * name,
- String * type,
- String * domain
- );
-
- /* DNSServiceBrowse() Parameters:
- *
- * sdRef: A pointer to an uninitialized ServiceRef. Call ServiceRef.Dispose()
- * to terminate the browse.
- *
- * flags: Currently ignored, reserved for future use.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to browse for services
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Most applications will pass 0 to browse on all available
- * interfaces. Pass -1 to only browse for services provided on the local host.
- *
- * regtype: The service type being browsed for followed by the protocol, separated by a
- * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
- *
- * domain: If non-NULL, specifies the domain on which to browse for services.
- * Most applications will not specify a domain, instead browsing on the
- * default domain(s).
- *
- * callback: The delegate to be called when an instance of the service being browsed for
- * is found, or if the call asynchronously fails.
- *
- * return value: Returns initialized ServiceRef on succeses (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise throws an exception indicating
- * the error that occurred (the callback is not invoked and the ServiceRef
- * is not initialized.)
- */
-
- static public ServiceRef*
- Browse
- (
- int flags,
- int interfaceIndex,
- String * regtype,
- String * domain,
- BrowseReply * callback
- );
-
- /* ResolveReply() Parameters:
- *
- * Resolve a service name discovered via Browse() to a target host name, port number, and
- * txt record.
- *
- * Note: Applications should NOT use Resolve() solely for txt record monitoring - use
- * QueryRecord() instead, as it is more efficient for this task.
- *
- * Note: When the desired results have been returned, the client MUST terminate the resolve by calling
- * ServiceRef.Dispose().
- *
- * Note: Resolve() behaves correctly for typical services that have a single SRV record and
- * a single TXT record (the TXT record may be empty.) To resolve non-standard services with multiple
- * SRV or TXT records, QueryRecord() should be used.
- *
- * ResolveReply Callback Parameters:
- *
- * sdRef: The DNSServiceRef initialized by Resolve().
- *
- * flags: Currently unused, reserved for future use.
- *
- * interfaceIndex: The interface on which the service was resolved.
- *
- * errorCode: Will be NoError (0) on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * the errorCode is nonzero.
- *
- * fullname: The full service domain name, in the form <servicename>.<protocol>.<domain>.
- * (Any literal dots (".") are escaped with a backslash ("\."), and literal
- * backslashes are escaped with a second backslash ("\\"), e.g. a web server
- * named "Dr. Pepper" would have the fullname "Dr\.\032Pepper._http._tcp.local.").
- * This is the appropriate format to pass to standard system DNS APIs such as
- * res_query(), or to the special-purpose functions included in this API that
- * take fullname parameters.
- *
- * hosttarget: The target hostname of the machine providing the service. This name can
- * be passed to functions like gethostbyname() to identify the host's IP address.
- *
- * port: The port, in host byte order, on which connections are accepted for this service.
- *
- * txtRecord: The service's primary txt record, in standard txt record format.
- *
- */
-
- __delegate void
- ResolveReply
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * fullName,
- String * hostName,
- int port,
- Byte txtRecord[]
- );
-
- /* Resolve() Parameters
- *
- * flags: Currently ignored, reserved for future use.
- *
- * interfaceIndex: The interface on which to resolve the service. The client should
- * pass the interface on which the servicename was discovered, i.e.
- * the interfaceIndex passed to the DNSServiceBrowseReply callback,
- * or 0 to resolve the named service on all available interfaces.
- *
- * name: The servicename to be resolved.
- *
- * regtype: The service type being resolved followed by the protocol, separated by a
- * dot (e.g. "_ftp._tcp"). The transport protocol must be "_tcp" or "_udp".
- *
- * domain: The domain on which the service is registered, i.e. the domain passed
- * to the DNSServiceBrowseReply callback.
- *
- * callback: The delegate to be called when a result is found, or if the call
- * asynchronously fails.
- *
- *
- * return value: Returns initialized ServiceRef on succeses (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise throws an exception indicating
- * the error that occurred (the callback is never invoked and the DNSServiceRef
- * is not initialized.)
- */
-
- static public ServiceRef*
- Resolve
- (
- int flags,
- int interfaceIndex,
- String * name,
- String * regtype,
- String * domain,
- ResolveReply * callback
- );
-
- /*********************************************************************************************
- *
- * Special Purpose Calls (most applications will not use these)
- *
- *********************************************************************************************/
-
- /* CreateConnection/RegisterRecord
- *
- * Register an individual resource record on a connected ServiceRef.
- *
- * Note that name conflicts occurring for records registered via this call must be handled
- * by the client in the callback.
- *
- *
- * RecordReply() parameters:
- *
- * sdRef: The connected ServiceRef initialized by
- * CreateConnection().
- *
- * RecordRef: The RecordRef initialized by RegisterRecord(). If the above
- * ServiceRef.Dispose is called, this RecordRef is
- * invalidated, and may not be used further.
- *
- * flags: Currently unused, reserved for future use.
- *
- * errorCode: Will be NoError on success, otherwise will
- * indicate the failure that occurred (including name conflicts.)
- * Other parameters are undefined if errorCode is nonzero.
- *
- */
-
- __delegate void
- RegisterRecordReply
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- ErrorCode errorCode,
- RecordRef * record
- );
-
- /* CreateConnection()
- *
- * Create a connection to the daemon allowing efficient registration of
- * multiple individual records.
- *
- *
- * Parameters:
- *
- * callback: The delegate to be called when a result is found, or if the call
- * asynchronously fails (e.g. because of a name conflict.)
- *
- * return value: Returns initialize ServiceRef on success, otherwise throws
- * an exception indicating the specific failure that occurred (in which
- * case the ServiceRef is not initialized).
- */
-
- static public ServiceRef*
- CreateConnection
- (
- RegisterRecordReply * callback
- );
-
-
- /* RegisterRecord() Parameters:
- *
- * sdRef: A ServiceRef initialized by CreateConnection().
- *
- * RecordRef: A pointer to an uninitialized RecordRef. Upon succesfull completion of this
- * call, this ref may be passed to UpdateRecord() or RemoveRecord().
- * (To deregister ALL records registered on a single connected ServiceRef
- * and deallocate each of their corresponding RecordRefs, call
- * ServiceRef.Dispose()).
- *
- * flags: Possible values are Shared or Unique
- * (see flag type definitions for details).
- *
- * interfaceIndex: If non-zero, specifies the interface on which to register the record
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Passing 0 causes the record to be registered on all interfaces.
- * Passing -1 causes the record to only be visible on the local host.
- *
- * fullname: The full domain name of the resource record.
- *
- * rrtype: The numerical type of the resource record (e.g. PTR, SRV, etc), as defined
- * in nameser.h.
- *
- * rrclass: The class of the resource record, as defined in nameser.h (usually 1 for the
- * Internet class).
- *
- * 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.
- *
- *
- * return value: Returns initialize RecordRef on succeses (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise throws an exception indicating
- * the error that occurred (the callback is never invoked and the RecordRef is
- * not initialized.)
- */
- static public RecordRef*
- RegisterRecord
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- int interfaceIndex,
- String * fullname,
- int rrtype,
- int rrclass,
- Byte rdata[],
- int ttl
- );
-
-
- /* DNSServiceQueryRecord
- *
- * Query for an arbitrary DNS record.
- *
- *
- * QueryRecordReply() Delegate Parameters:
- *
- * sdRef: The ServiceRef initialized by QueryRecord().
- *
- * flags: Possible values are MoreComing and
- * Add. The Add flag is NOT set for PTR records
- * with a ttl of 0, i.e. "Remove" events.
- *
- * interfaceIndex: The interface on which the query was resolved (the index for a given
- * interface is determined via the if_nametoindex() family of calls).
- *
- * errorCode: Will be kDNSServiceErr_NoError on success, otherwise will
- * indicate the failure that occurred. Other parameters are undefined if
- * errorCode is nonzero.
- *
- * fullname: The resource record's full domain name.
- *
- * rrtype: The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
- *
- * rrclass: The class of the resource record, as defined in nameser.h (usually 1).
- *
- * rdata: The raw rdata of the resource record.
- *
- * ttl: The resource record's time to live, in seconds.
- *
- */
-
- __delegate void
- QueryRecordReply
- (
- ServiceRef * sdRef,
- ServiceFlags flags,
- int interfaceIndex,
- ErrorCode errorCode,
- String * fullName,
- int rrtype,
- int rrclass,
- Byte rdata[],
- int ttl
- );
-
- /* QueryRecord() Parameters:
- *
- * flags: Pass LongLivedQuery to create a "long-lived" unicast
- * query in a non-local domain. Without setting this flag, unicast queries
- * will be one-shot - that is, only answers available at the time of the call
- * will be returned. By setting this flag, answers (including Add and Remove
- * events) that become available after the initial call is made will generate
- * callbacks. This flag has no effect on link-local multicast queries.
- *
- * interfaceIndex: If non-zero, specifies the interface on which to issue the query
- * (the index for a given interface is determined via the if_nametoindex()
- * family of calls.) Passing 0 causes the name to be queried for on all
- * interfaces. Passing -1 causes the name to be queried for only on the
- * local host.
- *
- * fullname: The full domain name of the resource record to be queried for.
- *
- * rrtype: The numerical type of the resource record to be queried for (e.g. PTR, SRV, etc)
- * as defined in nameser.h.
- *
- * rrclass: The class of the resource record, as defined in nameser.h
- * (usually 1 for the Internet class).
- *
- * callback: The delegate to be called when a result is found, or if the call
- * asynchronously fails.
- *
- *
- * return value: Returns initialized ServiceRef on succeses (any subsequent, asynchronous
- * errors are delivered to the callback), otherwise throws an exception indicating
- * the error that occurred (the callback is never invoked and the ServiceRef
- * is not initialized.)
- */
-
- static public ServiceRef*
- QueryRecord
- (
- ServiceFlags flags,
- int interfaceIndex,
- String * fullname,
- int rrtype,
- int rrclass,
- QueryRecordReply * callback
- );
-
- /* ReconfirmRecord
- *
- * Instruct the daemon to verify the validity of a resource record that appears to
- * be out of date (e.g. because tcp connection to a service's target failed.)
- * Causes the record to be flushed from the daemon's cache (as well as all other
- * daemons' caches on the network) if the record is determined to be invalid.
- *
- * Parameters:
- *
- * flags: Currently unused, reserved for future use.
- *
- * fullname: The resource record's full domain name.
- *
- * rrtype: The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
- *
- * rrclass: The class of the resource record, as defined in nameser.h (usually 1).
- *
- * rdata: The raw rdata of the resource record.
- *
- */
- static public void
- ReconfirmRecord
- (
- ServiceFlags flags,
- int interfaceIndex,
- String * fullname,
- int rrtype,
- int rrclass,
- Byte rdata[]
- );
- };
- }
-}
+++ /dev/null
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.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
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-1 ICON "dnssd_NET.ico"
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "resource.h\0"
- "\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", MASTER_COMPANY_NAME
- VALUE "FileDescription", "Bonjour.NET Client Library"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "dnssd.NET.dll"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "dnssd.NET.dll"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="DLL.NET"\r
- ProjectGUID="{2A2FFA97-AF60-494F-9384-BBAA283AA3F2}"\r
- RootNamespace="DLL2NET"\r
- Keyword="ManagedCProj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- CharacterSet="1"\r
- ManagedExtensions="4"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- Description="Generating keypair..."\r
- CommandLine="sn -k dnssd_NET.snk"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="../;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"\r
- RuntimeLibrary="3"\r
- UsePrecompiledHeader="2"\r
- WarningLevel="3"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)\dnssd.NET.dll"\r
- LinkIncremental="2"\r
- GenerateDebugInformation="true"\r
- AssemblyDebug="1"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- EmbedManifest="false"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- CharacterSet="1"\r
- ManagedExtensions="4"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- Description="Generating keypair..."\r
- CommandLine="sn -k dnssd_NET.snk"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="../;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"\r
- RuntimeLibrary="3"\r
- UsePrecompiledHeader="2"\r
- WarningLevel="3"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)\dnssd.NET.dll"\r
- LinkIncremental="2"\r
- GenerateDebugInformation="true"\r
- AssemblyDebug="1"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- EmbedManifest="false"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- CharacterSet="1"\r
- ManagedExtensions="4"\r
- WholeProgramOptimization="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- Description="Generating keypair..."\r
- CommandLine="sn -k dnssd_NET.snk"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="../;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"\r
- RuntimeLibrary="2"\r
- UsePrecompiledHeader="0"\r
- WarningLevel="3"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)\dnssd.NET.dll"\r
- LinkIncremental="1"\r
- GenerateDebugInformation="true"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- EmbedManifest="false"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- CharacterSet="1"\r
- ManagedExtensions="4"\r
- WholeProgramOptimization="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- Description="Generating keypair..."\r
- CommandLine="sn -k dnssd_NET.snk"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="../;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"\r
- RuntimeLibrary="2"\r
- UsePrecompiledHeader="0"\r
- WarningLevel="3"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
- OutputFile="$(OutDir)\dnssd.NET.dll"\r
- LinkIncremental="1"\r
- GenerateDebugInformation="true"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- EmbedManifest="false"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- <AssemblyReference\r
- RelativePath="System.dll"\r
- AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"\r
- />\r
- <AssemblyReference\r
- RelativePath="System.Data.dll"\r
- AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"\r
- />\r
- <AssemblyReference\r
- RelativePath="System.XML.dll"\r
- AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"\r
- />\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath=".\AssemblyInfo.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\dnssd_NET.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\Stdafx.cpp"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="1"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="1"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="1"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="1"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath=".\dnssd_NET.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\resource.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\Stdafx.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- <File\r
- RelativePath=".\dnssd_NET.ico"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\dnssd_NET.rc"\r
- >\r
- </File>\r
- </Filter>\r
- <File\r
- RelativePath=".\ReadMe.txt"\r
- >\r
- </File>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by dnssd_NET.rc
+++ /dev/null
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.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 ""afxres.h""\r\n"
- "#include ""WinVersRes.h""\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", MASTER_COMPANY_NAME
- VALUE "FileDescription", "Bonjour Client Library"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "dnssd.dll"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "dnssd.dll"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <windows.h>
-#include <DebugServices.h>
-#include <stdlib.h>
-
-BOOL APIENTRY DllMain( HANDLE inModule, DWORD inReason, LPVOID inReserved )
-{
- (void) inModule;
- (void) inReserved;
-
- switch( inReason )
- {
- case DLL_PROCESS_ATTACH:
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return( TRUE );
-}
-
-
-BOOL
-IsSystemServiceDisabled()
-{
- ENUM_SERVICE_STATUS * lpService = NULL;
- SC_HANDLE sc;
- BOOL ret = FALSE;
- BOOL ok;
- DWORD bytesNeeded = 0;
- DWORD srvCount;
- DWORD resumeHandle = 0;
- DWORD srvType;
- DWORD srvState;
- DWORD dwBytes = 0;
- DWORD i;
- OSStatus err;
-
- sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
- err = translate_errno( sc, GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- srvType = SERVICE_WIN32;
- srvState = SERVICE_STATE_ALL;
-
- for ( ;; )
- {
- // Call EnumServicesStatus using the handle returned by OpenSCManager
-
- ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
-
- if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
- {
- break;
- }
-
- if ( lpService )
- {
- free( lpService );
- }
-
- dwBytes = bytesNeeded;
-
- lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
- require_action( lpService, exit, ret = FALSE );
- }
-
- err = translate_errno( ok, GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- for ( i = 0; i < srvCount; i++ )
- {
- if ( strcmp( lpService[i].lpServiceName, "Bonjour Service" ) == 0 )
- {
- if ( ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_PAUSED ) || ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED ) )
- {
- ret = TRUE;
- }
-
- break;
- }
- }
-
-exit:
-
- if ( lpService )
- {
- free( lpService );
- }
-
- if ( sc )
- {
- CloseServiceHandle ( sc );
- }
-
- return ret;
-}
+++ /dev/null
-; -*- 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.
-;
-
-LIBRARY dnssd
-
-EXPORTS
- DNSServiceRefSockFD
- DNSServiceProcessResult
- DNSServiceRefDeallocate
- DNSServiceEnumerateDomains
- DNSServiceRegister
- DNSServiceAddRecord
- DNSServiceUpdateRecord
- DNSServiceRemoveRecord
- DNSServiceBrowse
- DNSServiceResolve
- DNSServiceConstructFullName
- DNSServiceCreateConnection
- DNSServiceRegisterRecord
- DNSServiceQueryRecord
- DNSServiceReconfirmRecord
- DNSServiceNATPortMappingCreate
- DNSServiceGetAddrInfo
- DNSServiceGetProperty
- TXTRecordCreate
- TXTRecordDeallocate
- TXTRecordSetValue
- TXTRecordRemoveValue
- TXTRecordContainsKey
- TXTRecordGetCount
- TXTRecordGetLength
- TXTRecordGetBytesPtr
- TXTRecordGetValuePtr
- TXTRecordGetItemAtIndex
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="DLL"\r
- ProjectGUID="{AB581101-18F0-46F6-B56A-83A6B1EA657E}"\r
- RootNamespace="DLL"\r
- Keyword="Win32Proj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;NOT_HAVE_SA_LEN;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- DisableSpecificWarnings="4127;4204"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/dnssd.dll"\r
- LinkIncremental="2"\r
- ModuleDefinitionFile="dnssd.def"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
- SubSystem="2"\r
- BaseAddress="0x16000000"\r
- ImportLibrary="$(OutDir)\dnssd.lib"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- DisableSpecificWarnings="4127;4204"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/dnssd.dll"\r
- LinkIncremental="2"\r
- ModuleDefinitionFile="dnssd.def"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
- SubSystem="2"\r
- BaseAddress="0x16000000"\r
- ImportLibrary="$(OutDir)\dnssd.lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- DisableSpecificWarnings="4127;4204"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/dnssd.dll"\r
- LinkIncremental="1"\r
- ModuleDefinitionFile="dnssd.def"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
- SubSystem="2"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- BaseAddress="0x16000000"\r
- ImportLibrary="$(OutDir)\dnssd.lib"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- 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" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib"
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"
if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"
if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"
if not exist "$(DSTROOT)\AppleInternal\bin\$(PlatformName)" mkdir "$(DSTROOT)\AppleInternal\bin\$(PlatformName)"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(PlatformName)"
xcopy /I/Y "$(OutDir)\dnssd.dll.pdb" "$(DSTROOT)\AppleInternal\bin\$(PlatformName)"
xcopy /I/Y "$(ProjectDir)..\..\mDNSShared\dns_sd.h" "$(DSTROOT)\Program Files\Bonjour SDK\include"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- CompileAs="0"\r
- DisableSpecificWarnings="4127;4204"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/dnssd.dll"\r
- LinkIncremental="1"\r
- ModuleDefinitionFile="dnssd.def"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
- SubSystem="2"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- BaseAddress="0x16000000"\r
- ImportLibrary="$(OutDir)\dnssd.lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- 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" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib"
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"
if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"
if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"
if not exist "$(DSTROOT)\AppleInternal\bin\$(PlatformName)" mkdir "$(DSTROOT)\AppleInternal\bin\$(PlatformName)"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(PlatformName)"
xcopy /I/Y "$(OutDir)\dnssd.dll.pdb" "$(DSTROOT)\AppleInternal\bin\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\dllmain.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\dnssd.def"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dnssd_clientlib.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dnssd_clientstub.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dnssd_ipc.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\GenLinkedList.c"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dns_sd.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dnssd_ipc.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\GenLinkedList.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\resource.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- <File\r
- RelativePath=".\dll.rc"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectName>DLL</ProjectName>\r
- <ProjectGuid>{AB581101-18F0-46F6-B56A-83A6B1EA657E}</ProjectGuid>\r
- <RootNamespace>DLL</RootNamespace>\r
- <Keyword>Win32Proj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dnssd</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dnssd</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dnssd</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dnssd</TargetName>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;NOT_HAVE_SA_LEN;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
- <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <BaseAddress>0x16000000</BaseAddress>\r
- <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
- <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <BaseAddress>0x16000000</BaseAddress>\r
- <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
- <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <BaseAddress>0x16000000</BaseAddress>\r
- <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)" mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\include" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\include"\r
-if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"\r
-if not exist "$(DSTROOT)\AppleInternal\bin\$(Platform)" mkdir "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(OutDir)dnssd.dll.pdb" "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-xcopy /I/Y "$(ProjectDir)..\..\mDNSShared\dns_sd.h" "$(DSTROOT)\Program Files\Bonjour SDK\include"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <CompileAs>Default</CompileAs>\r
- <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
- <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <BaseAddress>0x16000000</BaseAddress>\r
- <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)" mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\include" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\include"\r
-if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"\r
-if not exist "$(DSTROOT)\AppleInternal\bin\$(Platform)" mkdir "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(OutDir)dnssd.dll.pdb" "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
- <ClCompile Include="dllmain.c" />\r
- <ClCompile Include="..\..\mDNSShared\dnssd_clientlib.c" />\r
- <ClCompile Include="..\..\mDNSShared\dnssd_clientstub.c" />\r
- <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c" />\r
- <ClCompile Include="..\..\mDNSShared\GenLinkedList.c" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="dnssd.def" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\dns_sd.h" />\r
- <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h" />\r
- <ClInclude Include="..\..\mDNSShared\GenLinkedList.h" />\r
- <ClInclude Include="resource.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="dll.rc" />\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
- <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="dllmain.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\dnssd_clientlib.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\dnssd_clientstub.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\GenLinkedList.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="dnssd.def">\r
- <Filter>Source Files</Filter>\r
- </None>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\dns_sd.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\GenLinkedList.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="resource.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="dll.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by dll.rc
-//
-#define IDS_PROJNAME 100
-#define IDR_WMDMLOGGER 101
-#define IDS_LOG_SEV_INFO 201
-#define IDS_LOG_SEV_WARN 202
-#define IDS_LOG_SEV_ERROR 203
-#define IDS_LOG_DATETIME 204
-#define IDS_LOG_SRCNAME 205
-#define IDS_DEF_LOGFILE 301
-#define IDS_DEF_MAXSIZE 302
-#define IDS_DEF_SHRINKTOSIZE 303
-#define IDS_DEF_LOGENABLED 304
-#define IDS_MUTEX_TIMEOUT 401
-
-// 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 101
-#endif
-#endif
+++ /dev/null
-/* -*- 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_ServiceNotRunning;
-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 );
-}
-
-
-dnssd_sock_t DNSSD_API
-DNSServiceRefSockFD(DNSServiceRef sdRef)
-{
- typedef int (DNSSD_API * Func)(DNSServiceRef sdRef);
- static Func func = NULL;
- int ret = INVALID_SOCKET;
-
- 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;
-}
+++ /dev/null
-/* -*- 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 <windows.h>
-#include <dns_sd.h>
-
-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
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="DLLStub"\r
- ProjectGUID="{3A2B6325-3053-4236-84BD-AA9BE2E323E5}"\r
- RootNamespace="DLLStub"\r
- Keyword="Win32Proj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="4"\r
- UseOfATL="0"\r
- CharacterSet="1"\r
- WholeProgramOptimization="0"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- MinimalRebuild="false"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.pdb"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLibrarianTool"\r
- OutputFile="$(OutDir)\dnssdStatic.lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="4"\r
- UseOfATL="0"\r
- CharacterSet="1"\r
- WholeProgramOptimization="0"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- MinimalRebuild="false"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.pdb"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLibrarianTool"\r
- OutputFile="$(OutDir)\dnssdStatic.lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="4"\r
- UseOfATL="0"\r
- CharacterSet="1"\r
- WholeProgramOptimization="0"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.lib.pdb"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLibrarianTool"\r
- OutputFile="$(OutDir)\dnssdStatic.lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)"
echo F | xcopy /Y "$(OutDir)\dnssdStatic.lib" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)\dnssd.lib"
xcopy /Y "$(OutDir)\dnssd.lib.pdb" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="4"\r
- UseOfATL="0"\r
- CharacterSet="1"\r
- WholeProgramOptimization="0"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- ProgramDataBaseFileName="$(IntDir)\dnssd.lib.pdb"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLibrarianTool"\r
- OutputFile="$(OutDir)\dnssdStatic.lib"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)"
echo F | xcopy /I/Y "$(OutDir)\dnssdStatic.lib" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)\dnssd.lib"
xcopy /Y "$(OutDir)\dnssd.lib.pdb" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath=".\DLLStub.cpp"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath=".\DLLStub.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- </Filter>\r
- <File\r
- RelativePath=".\ReadMe.txt"\r
- >\r
- </File>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{3A2B6325-3053-4236-84BD-AA9BE2E323E5}</ProjectGuid>\r
- <RootNamespace>DLLStub</RootNamespace>\r
- <Keyword>Win32Proj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>StaticLibrary</ConfigurationType>\r
- <UseOfAtl>false</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- <WholeProgramOptimization>false</WholeProgramOptimization>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>StaticLibrary</ConfigurationType>\r
- <UseOfAtl>false</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- <WholeProgramOptimization>false</WholeProgramOptimization>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>StaticLibrary</ConfigurationType>\r
- <UseOfAtl>false</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- <WholeProgramOptimization>false</WholeProgramOptimization>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>StaticLibrary</ConfigurationType>\r
- <UseOfAtl>false</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- <WholeProgramOptimization>false</WholeProgramOptimization>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dnssdStatic</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dnssdStatic</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dnssdStatic</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dnssdStatic</TargetName>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MinimalRebuild>false</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <Lib>\r
- <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
- </Lib>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MinimalRebuild>false</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <Lib>\r
- <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
- </Lib>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.lib.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <Lib>\r
- <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
- </Lib>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-echo F | xcopy /Y "$(OutDir)dnssdStatic.lib" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)\dnssd.lib"\r
-xcopy /Y "$(OutDir)dnssd.lib.pdb" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <ProgramDataBaseFileName>$(IntDir)dnssd.lib.pdb</ProgramDataBaseFileName>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <Lib>\r
- <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
- </Lib>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-echo F | xcopy /I/Y "$(OutDir)dnssdStatic.lib" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)\dnssd.lib"\r
-xcopy /Y "$(OutDir)dnssd.lib.pdb" "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="DLLStub.cpp" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="DLLStub.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="ReadMe.txt" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
- <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
- </ProjectReference>\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
- <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="DLLStub.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="DLLStub.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="ReadMe.txt" />\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-
-
-#include "stdafx.h"
-
-#include "resource.h"
-
-#include "DLLX.h"
-
-#include "dlldatax.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-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;
-
-}
-
-
-
+++ /dev/null
-; -*- 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.
-;
-
-
-
-
-
-LIBRARY "dnssdX.DLL"
-
-
-
-EXPORTS
-
- DllCanUnloadNow PRIVATE
-
- DllGetClassObject PRIVATE
-
- DllRegisterServer PRIVATE
-
- DllUnregisterServer PRIVATE
-
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-// 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 PCP, NAT-PMP or UPnP */
- kDNSSDError_NATPortMappingDisabled = -65565, /* NAT supports PCP, 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;
-
-};
-
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "winres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""winres.h""\r\n"\r
- "#include ""WinVersRes.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "1 TYPELIB ""BonjourLib.tlb""\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904e4"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "Bonjour COM Component Library"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "InternalName", "dnssdX.dll"\r
- VALUE "OriginalFilename", "dnssdX.dll"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1252\r
- END\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// REGISTRY\r
-//\r
-\r
-IDR_DLLX REGISTRY "DLLX.rgs"\r
-IDR_DNSSDSERVICE REGISTRY "DNSSDService.rgs"\r
-IDR_TXTRECORD REGISTRY "TXTRecord.rgs"\r
-IDR_DNSSDRECORD REGISTRY "DNSSDRecord.rgs"\r
-IDR_DNSSDEVENTMANAGER REGISTRY "DNSSDEventManager.rgs"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// String Table\r
-//\r
-\r
-STRINGTABLE \r
-BEGIN\r
- IDS_PROJNAME "BonjourLib"\r
-END\r
-\r
-#endif // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-1 TYPELIB "dnssdX.tlb"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
-\r
+++ /dev/null
-HKCR\r
-{\r
- NoRemove AppID\r
- {\r
- '%APPID%' = s 'Bonjour'\r
- 'Bonjour.DLL'\r
- {\r
- val AppID = s '%APPID%'\r
- }\r
- }\r
-}\r
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="DLLX"\r
- ProjectGUID="{78FBFCC5-2873-4AE2-9114-A08082F71124}"\r
- RootNamespace="DLLX"\r
- Keyword="AtlProj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- UseOfMFC="0"\r
- UseOfATL="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="1"\r
- GenerateStublessProxies="true"\r
- TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
- HeaderFileName="DLLX.h"\r
- DLLDataFileName=""\r
- InterfaceIdentifierFileName="DLLX_i.c"\r
- ProxyFileName="DLLX_p.c"\r
- ValidateParameters="false"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="..;"$(IntDir)""\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- RegisterOutput="true"\r
- IgnoreImportLibrary="true"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
- OutputFile="$(OutDir)\dnssdX.dll"\r
- LinkIncremental="2"\r
- ModuleDefinitionFile=".\DLLX.def"\r
- GenerateDebugInformation="true"\r
- SubSystem="2"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- UseOfMFC="0"\r
- UseOfATL="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="3"\r
- GenerateStublessProxies="true"\r
- TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
- HeaderFileName="DLLX.h"\r
- DLLDataFileName=""\r
- InterfaceIdentifierFileName="DLLX_i.c"\r
- ProxyFileName="DLLX_p.c"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- MinimalRebuild="true"\r
- BasicRuntimeChecks="3"\r
- RuntimeLibrary="1"\r
- UsePrecompiledHeader="0"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="_DEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="..;"$(IntDir)""\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- RegisterOutput="true"\r
- IgnoreImportLibrary="true"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
- OutputFile="$(OutDir)\dnssdX.dll"\r
- LinkIncremental="2"\r
- ModuleDefinitionFile=".\DLLX.def"\r
- GenerateDebugInformation="true"\r
- SubSystem="2"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- UseOfATL="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="1"\r
- GenerateStublessProxies="true"\r
- TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
- HeaderFileName="DLLX.h"\r
- DLLDataFileName=""\r
- InterfaceIdentifierFileName="DLLX_i.c"\r
- ProxyFileName="DLLX_p.c"\r
- ValidateParameters="false"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="..;"$(IntDir)""\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- RegisterOutput="false"\r
- IgnoreImportLibrary="true"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
- OutputFile="$(OutDir)\dnssdX.dll"\r
- LinkIncremental="1"\r
- ModuleDefinitionFile=".\DLLX.def"\r
- GenerateDebugInformation="true"\r
- SubSystem="2"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\WINDOWS\system32\$(PlatformName)" mkdir "$(DSTROOT)\WINDOWS\system32\$(PlatformName)"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- UseOfATL="1"\r
- ATLMinimizesCRunTimeLibraryUsage="false"\r
- CharacterSet="1"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- MkTypLibCompatible="false"\r
- TargetEnvironment="3"\r
- GenerateStublessProxies="true"\r
- TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
- HeaderFileName="DLLX.h"\r
- DLLDataFileName=""\r
- InterfaceIdentifierFileName="DLLX_i.c"\r
- ProxyFileName="DLLX_p.c"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="2"\r
- AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
- PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- WarningLevel="3"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- PreprocessorDefinitions="NDEBUG"\r
- Culture="1033"\r
- AdditionalIncludeDirectories="..;"$(IntDir)""\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- RegisterOutput="false"\r
- IgnoreImportLibrary="true"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
- OutputFile="$(OutDir)\dnssdX.dll"\r
- LinkIncremental="1"\r
- ModuleDefinitionFile=".\DLLX.def"\r
- GenerateDebugInformation="true"\r
- SubSystem="2"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\WINDOWS\system32\$(PlatformName)" mkdir "$(DSTROOT)\WINDOWS\system32\$(PlatformName)"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(PlatformName)"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath=".\dlldatax.c"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath=".\DLLX.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DLLX.def"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DLLX.idl"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDEventManager.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDRecord.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDService.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\TXTRecord.cpp"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath=".\_IDNSSDEvents_CP.H"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\dlldatax.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDEventManager.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDRecord.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDService.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\Resource.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\stdafx.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\TXTRecord.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- <File\r
- RelativePath=".\DLLX.rc"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DLLX.rgs"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDEventManager.rgs"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDRecord.rgs"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DNSSDService.rgs"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\TXTRecord.rgs"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Generated Files"\r
- SourceControlFiles="false"\r
- >\r
- <File\r
- RelativePath=".\DLLX.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\DLLX_i.c"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- UsePrecompiledHeader="0"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Support Files"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\StringServices.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\StringServices.h"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{78FBFCC5-2873-4AE2-9114-A08082F71124}</ProjectGuid>\r
- <RootNamespace>DLLX</RootNamespace>\r
- <Keyword>AtlProj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfAtl>Static</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>false</UseOfMfc>\r
- <UseOfAtl>Static</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfAtl>Static</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <UseOfMfc>false</UseOfMfc>\r
- <UseOfAtl>Static</UseOfAtl>\r
- <CharacterSet>Unicode</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dnssdX</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dnssdX</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dnssdX</TargetName>\r
- <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dnssdX</TargetName>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <GenerateStublessProxies>true</GenerateStublessProxies>\r
- <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
- <HeaderFileName>DLLX.h</HeaderFileName>\r
- <DllDataFileName>\r
- </DllDataFileName>\r
- <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
- <ProxyFileName>DLLX_p.c</ProxyFileName>\r
- <ValidateAllParameters>false</ValidateAllParameters>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <RegisterOutput>true</RegisterOutput>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
- <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <SubSystem>Windows</SubSystem>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- <GenerateStublessProxies>true</GenerateStublessProxies>\r
- <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
- <HeaderFileName>DLLX.h</HeaderFileName>\r
- <DllDataFileName>\r
- </DllDataFileName>\r
- <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
- <ProxyFileName>DLLX_p.c</ProxyFileName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <RegisterOutput>false</RegisterOutput>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
- <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <SubSystem>Windows</SubSystem>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- <TargetEnvironment>Win32</TargetEnvironment>\r
- <GenerateStublessProxies>true</GenerateStublessProxies>\r
- <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
- <HeaderFileName>DLLX.h</HeaderFileName>\r
- <DllDataFileName>\r
- </DllDataFileName>\r
- <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
- <ProxyFileName>DLLX_p.c</ProxyFileName>\r
- <ValidateAllParameters>false</ValidateAllParameters>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <RegisterOutput>false</RegisterOutput>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
- <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)" mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <MkTypLibCompatible>false</MkTypLibCompatible>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- <GenerateStublessProxies>true</GenerateStublessProxies>\r
- <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
- <HeaderFileName>DLLX.h</HeaderFileName>\r
- <DllDataFileName>\r
- </DllDataFileName>\r
- <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
- <ProxyFileName>DLLX_p.c</ProxyFileName>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>MaxSpeed</Optimization>\r
- <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <WarningLevel>Level3</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <Culture>0x0409</Culture>\r
- <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <RegisterOutput>false</RegisterOutput>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
- <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)" mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="dlldatax.c">\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- </PrecompiledHeader>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- </PrecompiledHeader>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- </PrecompiledHeader>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- </PrecompiledHeader>\r
- </ClCompile>\r
- <ClCompile Include="DLLX.cpp" />\r
- <ClCompile Include="DNSSDEventManager.cpp" />\r
- <ClCompile Include="DNSSDRecord.cpp" />\r
- <ClCompile Include="DNSSDService.cpp" />\r
- <ClCompile Include="TXTRecord.cpp" />\r
- <ClCompile Include="DLLX_i.c">\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- </PrecompiledHeader>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- </PrecompiledHeader>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- </PrecompiledHeader>\r
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- </PrecompiledHeader>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
- <ClCompile Include="StringServices.cpp" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="DLLX.def" />\r
- <None Include="DLLX.rgs" />\r
- <None Include="DNSSDEventManager.rgs" />\r
- <None Include="DNSSDRecord.rgs" />\r
- <None Include="DNSSDService.rgs" />\r
- <None Include="TXTRecord.rgs" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <Midl Include="DLLX.idl" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="_IDNSSDEvents_CP.H" />\r
- <ClInclude Include="dlldatax.h" />\r
- <ClInclude Include="DNSSDEventManager.h" />\r
- <ClInclude Include="DNSSDRecord.h" />\r
- <ClInclude Include="DNSSDService.h" />\r
- <ClInclude Include="Resource.h" />\r
- <ClInclude Include="stdafx.h" />\r
- <ClInclude Include="TXTRecord.h" />\r
- <ClInclude Include="DLLX.h" />\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
- <ClInclude Include="StringServices.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="DLLX.rc" />\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
- <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\r
- </Filter>\r
- <Filter Include="Generated Files">\r
- <UniqueIdentifier>{f6bd0810-64ce-4840-9a29-d80d06414fcf}</UniqueIdentifier>\r
- <SourceControlFiles>False</SourceControlFiles>\r
- </Filter>\r
- <Filter Include="Support Files">\r
- <UniqueIdentifier>{0756c4a0-cd93-4f7e-a376-dc55c520a2d0}</UniqueIdentifier>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="dlldatax.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="DLLX.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="DNSSDEventManager.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="DNSSDRecord.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="DNSSDService.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="TXTRecord.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="DLLX_i.c">\r
- <Filter>Generated Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
- <Filter>Support Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="StringServices.cpp">\r
- <Filter>Support Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="DLLX.def">\r
- <Filter>Source Files</Filter>\r
- </None>\r
- <None Include="DLLX.rgs">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="DNSSDEventManager.rgs">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="DNSSDRecord.rgs">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="DNSSDService.rgs">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- <None Include="TXTRecord.rgs">\r
- <Filter>Resource Files</Filter>\r
- </None>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <Midl Include="DLLX.idl">\r
- <Filter>Source Files</Filter>\r
- </Midl>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="_IDNSSDEvents_CP.H">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="dlldatax.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="DNSSDEventManager.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="DNSSDRecord.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="DNSSDService.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="Resource.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="stdafx.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="TXTRecord.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="DLLX.h">\r
- <Filter>Generated Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
- <Filter>Support Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
- <Filter>Support Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="StringServices.h">\r
- <Filter>Support Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="DLLX.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-// DNSSD.cpp : Implementation of CDNSSD
-
-#include "stdafx.h"
-#include "DNSSD.h"
-#include "DNSSDService.h"
-#include "TXTRecord.h"
-#include <dns_sd.h>
-#include <CommonServices.h>
-#include <DebugServices.h>
-#include "StringServices.h"
-
-
-// CDNSSD
-
-STDMETHODIMP CDNSSD::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IBrowseListener* listener, IDNSSDService** browser )
-{
- CComObject<CDNSSDService> * 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<CDNSSDService>();
- }
- 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<CDNSSDService> * 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<CDNSSDService>();
- }
- 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<CDNSSDService> * object = NULL;
- DNSServiceRef sref = NULL;
- DNSServiceErrorType err = 0;
- HRESULT hr = 0;
-
- // Initialize
- *service = NULL;
-
- try
- {
- object = new CComObject<CDNSSDService>();
- }
- 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<CDNSSDService> * 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<CDNSSDService>();
- }
- 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<CDNSSDService> * 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<CDNSSDService>();
- }
- 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<CDNSSDService> * 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<CDNSSDService>();
- }
- 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<CDNSSDService> * object = NULL;
- DNSServiceRef sref = NULL;
- DNSServiceErrorType err = 0;
- HRESULT hr = 0;
-
- // Initialize
- *service = NULL;
-
- try
- {
- object = new CComObject<CDNSSDService>();
- }
- 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<CDNSSDService> * object = NULL;
- DNSServiceRef sref = NULL;
- DNSServiceProtocol prot = 0;
- DNSServiceErrorType err = 0;
- HRESULT hr = 0;
-
- // Initialize
- *service = NULL;
-
- try
- {
- object = new CComObject<CDNSSDService>();
- }
- 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDService> * 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<CTXTRecord>();
- }
- catch ( ... )
- {
- record = NULL;
- }
-
- require_action( record, exit, err = kDNSServiceErr_NoMemory );
- record->AddRef();
-
- char buf[ 64 ];
- snprintf( buf, sizeof( 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDService> * 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;
-}
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#include "stdafx.h"
-
-#include "DNSSDEventManager.h"
-
-
-
-
-
-// CDNSSDEventManager
-
-
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#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<CComSingleThreadModel>,
-
- public CComCoClass<CDNSSDEventManager, &CLSID_DNSSDEventManager>,
-
- public IConnectionPointContainerImpl<CDNSSDEventManager>,
-
- public CProxy_IDNSSDEvents<CDNSSDEventManager>,
-
- public IDispatchImpl<IDNSSDEventManager, &IID_IDNSSDEventManager, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-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)
-
+++ /dev/null
-HKCR\r
-{\r
- Bonjour.DNSSDEventManager.1 = s 'DNSSDEventManager Class'\r
- {\r
- CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}'\r
- }\r
- Bonjour.DNSSDEventManager = s 'DNSSDEventManager Class'\r
- {\r
- CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}'\r
- CurVer = s 'Bonjour.DNSSDEventManager.1'\r
- }\r
- NoRemove CLSID\r
- {\r
- ForceRemove {BEEB932A-8D4A-4619-AEFE-A836F988B221} = s 'DNSSDEventManager Class'\r
- {\r
- ProgID = s 'Bonjour.DNSSDEventManager.1'\r
- VersionIndependentProgID = s 'Bonjour.DNSSDEventManager'\r
- ForceRemove 'Programmable'\r
- InprocServer32 = s '%MODULE%'\r
- {\r
- val ThreadingModel = s 'Apartment'\r
- }\r
- val AppID = s '%APPID%'\r
- 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
- }\r
- }\r
-}\r
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#include "stdafx.h"
-
-#include "DNSSDRecord.h"
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-// 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;
-
-}
-
-
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#pragma once
-
-#include "resource.h" // main symbols
-
-
-
-#include "DLLX.h"
-
-#include "DNSSDService.h"
-
-#include <dns_sd.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
-
-
-
-
-
-
-
-// CDNSSDRecord
-
-
-
-class ATL_NO_VTABLE CDNSSDRecord :
-
- public CComObjectRootEx<CComSingleThreadModel>,
-
- public CComCoClass<CDNSSDRecord, &CLSID_DNSSDRecord>,
-
- public IDispatchImpl<IDNSSDRecord, &IID_IDNSSDRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-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)
-
+++ /dev/null
-HKCR\r
-{\r
- Bonjour.DNSSDRecord.1 = s 'DNSSDRecord Class'\r
- {\r
- CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}'\r
- }\r
- Bonjour.DNSSDRecord = s 'DNSSDRecord Class'\r
- {\r
- CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}'\r
- CurVer = s 'Bonjour.DNSSDRecord.1'\r
- }\r
- NoRemove CLSID\r
- {\r
- ForceRemove {5E93C5A9-7516-4259-A67B-41A656F6E01C} = s 'DNSSDRecord Class'\r
- {\r
- ProgID = s 'Bonjour.DNSSDRecord.1'\r
- VersionIndependentProgID = s 'Bonjour.DNSSDRecord'\r
- ForceRemove 'Programmable'\r
- InprocServer32 = s '%MODULE%'\r
- {\r
- val ThreadingModel = s 'Apartment'\r
- }\r
- val AppID = s '%APPID%'\r
- 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
- }\r
- }\r
-}\r
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#pragma warning(disable:4995)
-
-
-
-#include "stdafx.h"
-
-#include <strsafe.h>
-
-#include "DNSSDService.h"
-
-#include "DNSSDEventManager.h"
-
-#include "DNSSDRecord.h"
-
-#include "TXTRecord.h"
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-#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<CDNSSDService> * object = NULL;
-
- DNSServiceRef subord = NULL;
-
- DNSServiceErrorType err = 0;
-
- HRESULT hr = 0;
-
-
-
- check( m_primary );
-
-
-
- // Initialize
-
- *service = NULL;
-
-
-
- try
-
- {
-
- object = new CComObject<CDNSSDService>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService>();
-
- }
-
- 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<CDNSSDRecord> * 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<CDNSSDRecord>();
-
- }
-
- 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<CDNSSDRecord> * 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<CDNSSDRecord>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService>();
-
- }
-
- 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<CDNSSDService> * object = NULL;
-
- DNSServiceRef subord = NULL;
-
- DNSServiceProtocol prot = 0;
-
- DNSServiceErrorType err = 0;
-
- HRESULT hr = 0;
-
-
-
- check( m_primary );
-
-
-
- // Initialize
-
- *service = NULL;
-
-
-
- try
-
- {
-
- object = new CComObject<CDNSSDService>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDService> * 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<CTXTRecord>();
-
- }
-
- 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDService> * 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<CDNSSDRecord> * 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);;
-
-}
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#pragma once
-
-#include "resource.h" // main symbols
-
-
-
-#include "DLLX.h"
-
-#include "DNSSDEventManager.h"
-
-#include <CommonServices.h>
-
-#include <DebugServices.h>
-
-#include <dns_sd.h>
-
-#include <map>
-
-
-
-
-
-#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<CComSingleThreadModel>,
-
- public CComCoClass<CDNSSDService, &CLSID_DNSSDService>,
-
- public IDispatchImpl<IDNSSDService, &IID_IDNSSDService, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-public:
-
-
-
- typedef CComObjectRootEx<CComSingleThreadModel> 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)
-
+++ /dev/null
-HKCR\r
-{\r
- Bonjour.DNSSDService.1 = s 'DNSSDService Class'\r
- {\r
- CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}'\r
- }\r
- Bonjour.DNSSDService = s 'DNSSDService Class'\r
- {\r
- CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}'\r
- CurVer = s 'Bonjour.DNSSDService.1'\r
- }\r
- NoRemove CLSID\r
- {\r
- ForceRemove {24CD4DE9-FF84-4701-9DC1-9B69E0D1090A} = s 'DNSSDService Class'\r
- {\r
- ProgID = s 'Bonjour.DNSSDService.1'\r
- VersionIndependentProgID = s 'Bonjour.DNSSDService'\r
- ForceRemove 'Programmable'\r
- InprocServer32 = s '%MODULE%'\r
- {\r
- val ThreadingModel = s 'Apartment'\r
- }\r
- val AppID = s '%APPID%'\r
- 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
- }\r
- }\r
-}\r
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-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
- )
-{
- BOOL ok = TRUE;
-
- if ( V_VT( inVariant ) == VT_BSTR )
- {
- BSTR bstr = V_BSTR( inVariant );
- std::string utf8;
-
- BSTRToUTF8( bstr, utf8 );
-
- outArray.reserve( utf8.size() );
- outArray.assign( utf8.begin(), utf8.end() );
- }
- else if ( V_VT( inVariant ) == VT_ARRAY )
- {
- SAFEARRAY * psa = NULL;
- BYTE * pData = NULL;
- ULONG cElements = 0;
- HRESULT hr;
-
- 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 );
- }
- else
- {
- ok = FALSE;
- }
-
-exit:
-
- return ok;
-
-}
\ No newline at end of file
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#ifndef _StringServices_h
-
-#define _StringServices_h
-
-
-
-#include <atlbase.h>
-
-#include <vector>
-
-#include <string>
-
-
-
-
-
-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
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#include "stdafx.h"
-
-#include "TXTRecord.h"
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-// 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_allocated )
- {
- *count = TXTRecordGetCount( TXTRecordGetLength( &m_tref ), TXTRecordGetBytesPtr( &m_tref ) );
- }
- else 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 );
-
-}
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#pragma once
-
-#include "resource.h" // main symbols
-
-#include "DLLX.h"
-
-#include <vector>
-
-#include <dns_sd.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
-
-
-
-
-
-
-
-// CTXTRecord
-
-
-
-class ATL_NO_VTABLE CTXTRecord :
-
- public CComObjectRootEx<CComSingleThreadModel>,
-
- public CComCoClass<CTXTRecord, &CLSID_TXTRecord>,
-
- public IDispatchImpl<ITXTRecord, &IID_ITXTRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-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)
-
+++ /dev/null
-HKCR\r
-{\r
- Bonjour.TXTRecord.1 = s 'TXTRecord Class'\r
- {\r
- CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}'\r
- }\r
- Bonjour.TXTRecord = s 'TXTRecord Class'\r
- {\r
- CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}'\r
- CurVer = s 'Bonjour.TXTRecord.1'\r
- }\r
- NoRemove CLSID\r
- {\r
- ForceRemove {AFEE063C-05BA-4248-A26E-168477F49734} = s 'TXTRecord Class'\r
- {\r
- ProgID = s 'Bonjour.TXTRecord.1'\r
- VersionIndependentProgID = s 'Bonjour.TXTRecord'\r
- ForceRemove 'Programmable'\r
- InprocServer32 = s '%MODULE%'\r
- {\r
- val ThreadingModel = s 'Apartment'\r
- }\r
- val AppID = s '%APPID%'\r
- 'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
- }\r
- }\r
-}\r
+++ /dev/null
-
-// Wizard-generated connection point proxy class
-// WARNING: This file may be regenerated by the wizard
-
-
-#pragma once
-
-template<class T>
-class CProxy_IDNSSDEvents :
- public IConnectionPointImpl<T, &__uuidof(_IDNSSDEvents)>
-{
-public:
- HRESULT Fire_DomainFound( IDNSSDService * service, DNSSDFlags flags, ULONG ifIndex, BSTR domain)
- {
- HRESULT hr = S_OK;
- T * pThis = static_cast<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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<T *>(this);
- int cConnections = m_vec.GetSize();
-
- for (int iConnection = 0; iConnection < cConnections; iConnection++)
- {
- pThis->Lock();
- CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
- pThis->Unlock();
-
- IDispatch * pConnection = static_cast<IDispatch *>(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;
- }
-};
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#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
-
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#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
-
+++ /dev/null
-//{{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
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#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 <atlbase.h>
-
-#include <atlcom.h>
-
-
-
-using namespace ATL;
\ No newline at end of file
+++ /dev/null
-Microsoft Visual Studio Solution File, Format Version 7.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "ApplicationVS2002.vcproj", "{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
-EndProject
-Global
- GlobalSection(SolutionConfiguration) = preSolution
- ConfigName.0 = Debug
- ConfigName.1 = Release
- EndGlobalSection
- GlobalSection(ProjectDependencies) = postSolution
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.ActiveCfg = Debug|Win32
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.Build.0 = Debug|Win32
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.ActiveCfg = Release|Win32
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+++ /dev/null
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.00"
- Name="Application"
- ProjectGUID="{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
- Keyword="MFCProj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="1"
- UseOfMFC="1"
- CharacterSet="1">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1"
- StringPooling="TRUE"
- MinimalRebuild="FALSE"
- BasicRuntimeChecks="3"
- SmallerTypeCheck="FALSE"
- RuntimeLibrary="1"
- BufferSecurityCheck="TRUE"
- EnableFunctionLevelLinking="FALSE"
- ForceConformanceInForLoopScope="TRUE"
- RuntimeTypeInfo="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="StdAfx.h"
- PrecompiledHeaderFile=".\Debug/Application.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- BrowseInformation="1"
- WarningLevel="4"
- WarnAsError="TRUE"
- SuppressStartupBanner="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"
- CompileAs="2"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="DNSServiceBrowser Debug.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- IgnoreDefaultLibraryNames="wsock32.lib"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Debug/Application.pdb"
- SubSystem="2"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="FALSE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/Application.tlb"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_AFXDLL;_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="1"
- UseOfMFC="1"
- CharacterSet="1"
- WholeProgramOptimization="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- GlobalOptimizations="TRUE"
- InlineFunctionExpansion="0"
- FavorSizeOrSpeed="2"
- OmitFramePointers="TRUE"
- OptimizeForWindowsApplication="FALSE"
- AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
- StringPooling="TRUE"
- MinimalRebuild="FALSE"
- RuntimeLibrary="0"
- BufferSecurityCheck="FALSE"
- EnableFunctionLevelLinking="FALSE"
- ForceConformanceInForLoopScope="TRUE"
- RuntimeTypeInfo="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="stdafx.h"
- PrecompiledHeaderFile=".\Release/Application.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- BrowseInformation="1"
- WarningLevel="4"
- WarnAsError="TRUE"
- SuppressStartupBanner="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- CompileAs="2"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="DNSServiceBrowser.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- IgnoreDefaultLibraryNames="wsock32.lib"
- ProgramDatabaseFile=".\Release/Application.pdb"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="TRUE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/Application.tlb"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_AFXDLL;NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- </Configuration>
- </Configurations>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="Sources\AboutDialog.cpp">
- </File>
- <File
- RelativePath="Sources\AboutDialog.h">
- </File>
- <File
- RelativePath="Sources\Application.cpp">
- </File>
- <File
- RelativePath="Sources\Application.h">
- </File>
- <File
- RelativePath="Sources\ChooserDialog.cpp">
- </File>
- <File
- RelativePath="Sources\ChooserDialog.h">
- </File>
- <File
- RelativePath="Sources\LoginDialog.cpp">
- </File>
- <File
- RelativePath="Sources\LoginDialog.h">
- </File>
- <File
- RelativePath="Sources\StdAfx.cpp">
- </File>
- <File
- RelativePath="Sources\StdAfx.h">
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;rc">
- <File
- RelativePath="Resources\Application.ico">
- </File>
- <File
- RelativePath="Resources\Application.rc">
- </File>
- <File
- RelativePath="Resources\Application.rc2">
- </File>
- <File
- RelativePath=".\Resources\Resource.h">
- </File>
- </Filter>
- <Filter
- Name="Support"
- Filter="">
- <File
- RelativePath="..\..\..\CommonServices.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\DNSCommon.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\DNSCommon.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\DNSDigest.c">
- </File>
- <File
- RelativePath="..\..\..\DNSServices\DNSServices.c">
- </File>
- <File
- RelativePath="..\..\..\DebugServices.c">
- </File>
- <File
- RelativePath="..\..\..\DebugServices.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\mDNS.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\mDNSClientAPI.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\mDNSDebug.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSWin32.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\uDNS.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\uDNS.h">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+++ /dev/null
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "ApplicationVS2003.vcproj", "{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfiguration) = preSolution
- Debug = Debug
- Release = Release
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.ActiveCfg = Debug|Win32
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.Build.0 = Debug|Win32
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.ActiveCfg = Release|Win32
- {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="Application"
- ProjectGUID="{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
- Keyword="MFCProj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="1"
- UseOfMFC="1"
- CharacterSet="1">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1"
- StringPooling="TRUE"
- MinimalRebuild="FALSE"
- BasicRuntimeChecks="3"
- SmallerTypeCheck="FALSE"
- RuntimeLibrary="1"
- BufferSecurityCheck="TRUE"
- EnableFunctionLevelLinking="FALSE"
- ForceConformanceInForLoopScope="TRUE"
- RuntimeTypeInfo="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="StdAfx.h"
- PrecompiledHeaderFile=".\Debug/Application.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- BrowseInformation="1"
- WarningLevel="4"
- WarnAsError="TRUE"
- SuppressStartupBanner="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"
- CompileAs="0"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="DNSServiceBrowser Debug.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- IgnoreDefaultLibraryNames="wsock32.lib"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Debug/Application.pdb"
- SubSystem="2"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="_DEBUG"
- MkTypLibCompatible="FALSE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Debug/Application.tlb"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_AFXDLL;_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="1"
- UseOfMFC="1"
- CharacterSet="1"
- WholeProgramOptimization="FALSE">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- GlobalOptimizations="TRUE"
- InlineFunctionExpansion="0"
- FavorSizeOrSpeed="2"
- OmitFramePointers="TRUE"
- OptimizeForWindowsApplication="FALSE"
- AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
- StringPooling="TRUE"
- MinimalRebuild="FALSE"
- RuntimeLibrary="0"
- BufferSecurityCheck="FALSE"
- EnableFunctionLevelLinking="FALSE"
- ForceConformanceInForLoopScope="TRUE"
- RuntimeTypeInfo="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderThrough="stdafx.h"
- PrecompiledHeaderFile=".\Release/Application.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- BrowseInformation="1"
- WarningLevel="4"
- WarnAsError="TRUE"
- SuppressStartupBanner="TRUE"
- Detect64BitPortabilityProblems="TRUE"
- CompileAs="0"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
- AdditionalDependencies="ws2_32.lib"
- OutputFile="DNSServiceBrowser.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- IgnoreDefaultLibraryNames="wsock32.lib"
- ProgramDatabaseFile=".\Release/Application.pdb"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"/>
- <Tool
- Name="VCMIDLTool"
- PreprocessorDefinitions="NDEBUG"
- MkTypLibCompatible="TRUE"
- SuppressStartupBanner="TRUE"
- TargetEnvironment="1"
- TypeLibraryName=".\Release/Application.tlb"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_AFXDLL;NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Source Files"
- Filter="">
- <File
- RelativePath="Sources\AboutDialog.cpp">
- </File>
- <File
- RelativePath="Sources\AboutDialog.h">
- </File>
- <File
- RelativePath="Sources\Application.cpp">
- </File>
- <File
- RelativePath="Sources\Application.h">
- </File>
- <File
- RelativePath="Sources\ChooserDialog.cpp">
- </File>
- <File
- RelativePath="Sources\ChooserDialog.h">
- </File>
- <File
- RelativePath="Sources\LoginDialog.cpp">
- </File>
- <File
- RelativePath="Sources\LoginDialog.h">
- </File>
- <File
- RelativePath="Sources\StdAfx.cpp">
- </File>
- <File
- RelativePath="Sources\StdAfx.h">
- </File>
- </Filter>
- <Filter
- Name="Resource Files"
- Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;rc">
- <File
- RelativePath="Resources\Application.ico">
- </File>
- <File
- RelativePath="Resources\Application.rc">
- </File>
- <File
- RelativePath="Resources\Application.rc2">
- </File>
- <File
- RelativePath=".\Resources\Resource.h">
- </File>
- </Filter>
- <Filter
- Name="Support"
- Filter="">
- <File
- RelativePath="..\..\..\CommonServices.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\DNSCommon.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\DNSCommon.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\DNSDigest.c">
- </File>
- <File
- RelativePath="..\..\..\DNSServices\DNSServices.c">
- </File>
- <File
- RelativePath="..\..\..\DebugServices.c">
- </File>
- <File
- RelativePath="..\..\..\DebugServices.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\mDNS.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\mDNSClientAPI.h">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\mDNSDebug.h">
- </File>
- <File
- RelativePath="..\..\..\mDNSWin32.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\uDNS.c">
- </File>
- <File
- RelativePath="..\..\..\..\mDNSCore\uDNS.h">
- </File>
- </Filter>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+++ /dev/null
-// Microsoft Visual C++ generated resource script.
-//
-#include "Resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.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 ""afxres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
- "#define _AFX_NO_OLE_RESOURCES\r\n"
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
- "\r\n"
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
- "#ifdef _WIN32\r\n"
- "LANGUAGE 9, 1\r\n"
- "#pragma code_page(1252)\r\n"
- "#endif //_WIN32\r\n"
- "#include ""Resources\\Application.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
- "#include ""afxres.rc"" // Standard components\r\n"
- "#endif\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDR_MAIN_ICON ICON "Application.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_CHOOSER_DIALOG DIALOGEX 0, 0, 512, 316
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP |
- WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_APPWINDOW
-CAPTION "DNSServiceBrowser"
-MENU IDR_CHOOSER_DIALOG_MENU
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- CONTROL "",IDC_SERVICE_LIST,"SysListView32",LVS_REPORT |
- LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT |
- LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,8,8,268,256
- CONTROL "",IDC_CHOOSER_LIST,"SysListView32",LVS_REPORT |
- LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT |
- LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,282,8,224,170
- CONTROL "",IDC_DOMAIN_LIST,"SysListView32",LVS_REPORT |
- LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT |
- LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,8,272,268,38
- GROUPBOX "Information",IDC_STATIC,282,182,224,128
- RTEXT "Name:",IDC_STATIC,288,195,38,8
- EDITTEXT IDC_INFO_NAME_TEXT,330,195,168,10,ES_AUTOHSCROLL |
- ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
- RTEXT "IP address:",IDC_STATIC,288,208,38,8
- EDITTEXT IDC_INFO_IP_TEXT,330,208,168,10,ES_AUTOHSCROLL |
- ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
- RTEXT "Interface:",IDC_STATIC,288,221,38,8
- EDITTEXT IDC_INFO_INTERFACE_TEXT,330,221,168,10,ES_AUTOHSCROLL |
- ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
- RTEXT "Host Name:",IDC_STATIC,287,234,38,8
- EDITTEXT IDC_INFO_HOST_NAME_TEXT,330,234,168,10,ES_AUTOHSCROLL |
- ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
- RTEXT "Text:",IDC_STATIC,288,247,38,8
- EDITTEXT IDC_INFO_TEXT_TEXT,330,247,168,57,ES_MULTILINE |
- ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT
- WS_BORDER,WS_EX_STATICEDGE
-END
-
-IDD_ABOUT_DIALOG DIALOGEX 0, 0, 244, 73
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
-CAPTION "About DNSServiceBrowser"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- ICON IDR_MAIN_ICON,IDC_ABOUT_APP_ICON,12,12,20,20
- LTEXT "DNSServiceBrowser",IDC_ABOUT_APP_NAME_TEXT,44,11,192,
- 12
- LTEXT "Version 1.2d1",IDC_ABOUT_APP_VERSION_TEXT,44,25,192,8
- LTEXT "Copyright (C) 2002-2004 Apple Computer, Inc.",
- IDC_ABOUT_COPYRIGHT_TEXT,4,60,156,8
- DEFPUSHBUTTON "OK",IDOK,192,52,44,14
-END
-
-IDD_LOGIN DIALOGEX 0, 0, 180, 89
-STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION
-CAPTION "Login"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
- LTEXT "Enter a username and password. Leave blank to use the default username and/or password.",
- IDC_STATIC,8,8,156,16,NOT WS_GROUP
- RTEXT "Username:",IDC_STATIC,10,34,36,8,NOT WS_GROUP
- EDITTEXT IDC_LOGIN_USERNAME_TEXT,50,32,118,12,ES_AUTOHSCROLL
- RTEXT "Password:",IDC_STATIC,10,50,36,8,NOT WS_GROUP
- EDITTEXT IDC_LOGIN_PASSWORD_TEXT,50,48,118,12,ES_PASSWORD |
- ES_AUTOHSCROLL
- DEFPUSHBUTTON "OK",IDOK,129,70,44,14
- PUSHBUTTON "Cancel",IDCANCEL,77,70,44,14
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", "Apple Computer, Inc."
- VALUE "FileDescription", "DNSServiceBrowser for Windows"
- VALUE "FileVersion", "1, 0, 0, 1"
- VALUE "InternalName", "DNSServiceBrowser for Windows"
- VALUE "LegalCopyright", "Copyright (C) 2002-2004 Apple Computer, Inc."
- VALUE "OriginalFilename", "DNSServiceBrowser.exe"
- VALUE "ProductName", "DNSServiceBrowser for Windows"
- VALUE "ProductVersion", "1, 0, 0, 1"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDR_CHOOSER_DIALOG_MENU MENU
-BEGIN
- POPUP "File"
- BEGIN
- MENUITEM "Close &Window\tCtrl+W", ID_FILE_CLOSE
- MENUITEM SEPARATOR
- MENUITEM "Exit", ID_FILE_EXIT
- END
- POPUP "Help"
- BEGIN
- MENUITEM "About DNSServiceBrowser...", ID_HELP_ABOUT
- END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Accelerator
-//
-
-IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ACCELERATORS
-BEGIN
- "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT
- "W", ID_FILE_CLOSE, VIRTKEY, CONTROL, NOINVERT
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// RT_MANIFEST
-//
-
-1 RT_MANIFEST
-BEGIN
- 0x3f3c, 0x6d78, 0x206c, 0x6576, 0x7372, 0x6f69, 0x3d6e, 0x3122, 0x302e,
- 0x2022, 0x6e65, 0x6f63, 0x6964, 0x676e, 0x223d, 0x5455, 0x2d46, 0x2238,
- 0x7320, 0x6174, 0x646e, 0x6c61, 0x6e6f, 0x3d65, 0x7922, 0x7365, 0x3f22,
- 0x203e, 0x0a0d, 0x613c, 0x7373, 0x6d65, 0x6c62, 0x2079, 0x0a0d, 0x2020,
- 0x7820, 0x6c6d, 0x736e, 0x223d, 0x7275, 0x3a6e, 0x6373, 0x6568, 0x616d,
- 0x2d73, 0x696d, 0x7263, 0x736f, 0x666f, 0x2d74, 0x6f63, 0x3a6d, 0x7361,
- 0x2e6d, 0x3176, 0x2022, 0x0a0d, 0x2020, 0x6d20, 0x6e61, 0x6669, 0x7365,
- 0x5674, 0x7265, 0x6973, 0x6e6f, 0x223d, 0x2e31, 0x2230, 0x0d3e, 0x3c0a,
- 0x7361, 0x6573, 0x626d, 0x796c, 0x6449, 0x6e65, 0x6974, 0x7974, 0x0d20,
- 0x200a, 0x2020, 0x7020, 0x6f72, 0x6563, 0x7373, 0x726f, 0x7241, 0x6863,
- 0x7469, 0x6365, 0x7574, 0x6572, 0x223d, 0x3878, 0x2236, 0x0d20, 0x200a,
- 0x2020, 0x7620, 0x7265, 0x6973, 0x6e6f, 0x223d, 0x2e35, 0x2e31, 0x2e30,
- 0x2230, 0x0a0d, 0x2020, 0x2020, 0x7974, 0x6570, 0x223d, 0x6977, 0x336e,
- 0x2232, 0x0a0d, 0x2020, 0x2020, 0x616e, 0x656d, 0x223d, 0x7041, 0x2e70,
- 0x7865, 0x2265, 0x3e2f, 0x0a0d, 0x2020, 0x2020, 0x643c, 0x7365, 0x7263,
- 0x7069, 0x6974, 0x6e6f, 0x413e, 0x7269, 0x6f50, 0x7472, 0x4120, 0x6d64,
- 0x6e69, 0x5520, 0x6974, 0x696c, 0x7974, 0x2f3c, 0x6564, 0x6373, 0x6972,
- 0x7470, 0x6f69, 0x3e6e, 0x0a0d, 0x2020, 0x2020, 0x643c, 0x7065, 0x6e65,
- 0x6564, 0x636e, 0x3e79, 0x0a0d, 0x2020, 0x2020, 0x643c, 0x7065, 0x6e65,
- 0x6564, 0x746e, 0x7341, 0x6573, 0x626d, 0x796c, 0x0d3e, 0x200a, 0x2020,
- 0x3c20, 0x7361, 0x6573, 0x626d, 0x796c, 0x6449, 0x6e65, 0x6974, 0x7974,
- 0x0a0d, 0x2020, 0x2020, 0x2020, 0x2020, 0x7420, 0x7079, 0x3d65, 0x7722,
- 0x6e69, 0x3233, 0x0d22, 0x200a, 0x2020, 0x2020, 0x2020, 0x2020, 0x616e,
- 0x656d, 0x223d, 0x694d, 0x7263, 0x736f, 0x666f, 0x2e74, 0x6957, 0x646e,
- 0x776f, 0x2e73, 0x6f43, 0x6d6d, 0x6e6f, 0x432d, 0x6e6f, 0x7274, 0x6c6f,
- 0x2273, 0x0a0d, 0x2020, 0x2020, 0x2020, 0x2020, 0x7620, 0x7265, 0x6973,
- 0x6e6f, 0x223d, 0x2e36, 0x2e30, 0x2e30, 0x2230, 0x0a0d, 0x2020, 0x2020,
- 0x2020, 0x2020, 0x7020, 0x6275, 0x696c, 0x4b63, 0x7965, 0x6f54, 0x656b,
- 0x3d6e, 0x3622, 0x3935, 0x6235, 0x3436, 0x3431, 0x6334, 0x6663, 0x6431,
- 0x2266, 0x0a0d, 0x2020, 0x2020, 0x2020, 0x2020, 0x6c20, 0x6e61, 0x7567,
- 0x6761, 0x3d65, 0x2a22, 0x0d22, 0x200a, 0x2020, 0x2020, 0x2020, 0x2020,
- 0x7270, 0x636f, 0x7365, 0x6f73, 0x4172, 0x6372, 0x6968, 0x6574, 0x7463,
- 0x7275, 0x3d65, 0x7822, 0x3638, 0x2f22, 0x0d3e, 0x200a, 0x2020, 0x3c20,
- 0x642f, 0x7065, 0x6e65, 0x6564, 0x746e, 0x7341, 0x6573, 0x626d, 0x796c,
- 0x0d3e, 0x200a, 0x2020, 0x3c20, 0x642f, 0x7065, 0x6e65, 0x6564, 0x636e,
- 0x3e79, 0x0a0d, 0x2f3c, 0x7361, 0x6573, 0x626d, 0x796c, 0x0d3e, "\012"
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
-BEGIN
- IDD_CHOOSER_DIALOG, DIALOG
- BEGIN
- RIGHTMARGIN, 468
- END
-
- IDD_LOGIN, DIALOG
- BEGIN
- BOTTOMMARGIN, 62
- END
-END
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE
-BEGIN
- IDS_ABOUTBOX "&About DNSServiceBrowser"
- IDS_CHOOSER_DOMAIN_COLUMN_NAME "Domains"
- IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed."
- IDS_CHOOSER_SERVICE_COLUMN_TYPE "Services"
- IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME "Name"
- IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME "IP Address"
- IDS_CHOOSER_SERVICE_COLUMN_DESC "Description"
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-#define _AFX_NO_SPLITTER_RESOURCES
-#define _AFX_NO_OLE_RESOURCES
-#define _AFX_NO_TRACKER_RESOURCES
-#define _AFX_NO_PROPERTY_RESOURCES
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#endif //_WIN32
-#include "Resources\Application.rc2" // non-Microsoft Visual C++ edited resources
-#include "afxres.rc" // Standard components
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-/* -*- 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.
- */
-
-#ifdef APSTUDIO_INVOKED
- #error this file is not editable by Microsoft Visual C++
-#endif //APSTUDIO_INVOKED
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Application.rc
-//
-#define IDS_ABOUTBOX 101
-#define IDS_CHOOSER_DOMAIN_COLUMN_NAME 102
-#define IDP_SOCKETS_INIT_FAILED 103
-#define IDS_CHOOSER_SERVICE_COLUMN_NAME 104
-#define IDS_CHOOSER_SERVICE_COLUMN_TYPE 104
-#define IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME 105
-#define IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME 106
-#define IDS_CHOOSER_SERVICE_COLUMN_DESC 107
-#define IDC_NAME_TEXT2 124
-#define IDC_INFO_NAME_TEXT 124
-#define IDC_DESCRIPTION_TEXT2 125
-#define IDC_INFO_TEXT_TEXT 125
-#define IDC_IP_TEXT2 126
-#define IDC_INFO_IP_TEXT 126
-#define IDC_IP_TEXT3 127
-#define IDC_INFO_INTERFACE_TEXT 127
-#define IDR_MAIN_ICON 128
-#define IDC_INFO_INTERFACE_TEXT2 128
-#define IDC_INFO_HOST_NAME_TEXT 128
-#define IDR_CHOOSER_DIALOG_MENU 136
-#define IDD_CHOOSER_DIALOG 143
-#define IDD_ABOUT_DIALOG 144
-#define IDD_LOGIN 145
-#define IDR_CHOOSER_DIALOG_MENU_ACCELERATORS 146
-#define IDC_CHOOSER_LIST 1000
-#define IDC_SERVICE_LIST2 1001
-#define IDC_SERVICE_LIST 1001
-#define IDC_SERVICE_LIST3 1002
-#define IDC_DOMAIN_LIST 1002
-#define IDC_ABOUT_APP_NAME_TEXT 1105
-#define IDC_ABOUT_APP_VERSION_TEXT 1106
-#define IDC_ABOUT_COPYRIGHT_TEXT 1107
-#define IDC_ABOUT_APP_ICON 1108
-#define IDC_LOGIN_USERNAME_TEXT 1182
-#define IDC_EDIT2 1183
-#define IDC_LOGIN_PASSWORD_TEXT 1183
-#define ID_FILE_EXIT 32771
-#define ID_HELP_ABOUT 32806
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 164
-#define _APS_NEXT_COMMAND_VALUE 32809
-#define _APS_NEXT_CONTROL_VALUE 1185
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-
-#include "stdafx.h"
-
-#include "AboutDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-// Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(AboutDialog, CDialog)
- //{{AFX_MSG_MAP(AboutDialog)
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-// AboutDialog
-//===========================================================================================================================
-
-AboutDialog::AboutDialog(CWnd* pParent /*=NULL*/)
- : CDialog(AboutDialog::IDD, pParent)
-{
- //{{AFX_DATA_INIT(AboutDialog)
- // Note: the ClassWizard will add member initialization here
- //}}AFX_DATA_INIT
-}
-
-//===========================================================================================================================
-// OnInitDialog
-//===========================================================================================================================
-
-BOOL AboutDialog::OnInitDialog()
-{
- CDialog::OnInitDialog();
- return( true );
-}
-
-//===========================================================================================================================
-// DoDataExchange
-//===========================================================================================================================
-
-void AboutDialog::DoDataExchange(CDataExchange* pDX)
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(AboutDialog)
- // Note: the ClassWizard will add DDX and DDV calls here
- //}}AFX_DATA_MAP
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_)
-#define AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include "Resource.h"
-
-//===========================================================================================================================
-// AboutDialog
-//===========================================================================================================================
-
-class AboutDialog : public CDialog
-{
- public:
-
- // Creation/Deletion
-
- AboutDialog(CWnd* pParent = NULL); // standard constructor
-
- //{{AFX_DATA(AboutDialog)
- enum { IDD = IDD_ABOUT_DIALOG };
- // Note: the ClassWizard will add data members here
- //}}AFX_DATA
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(AboutDialog)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- protected:
-
- // Generated message map functions
- //{{AFX_MSG(AboutDialog)
- virtual BOOL OnInitDialog();
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_)
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-
-#include "StdAfx.h"
-
-#include "DNSServices.h"
-
-#include "Application.h"
-
-#include "ChooserDialog.h"
-
-#include "stdafx.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-// Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(Application, CWinApp)
- //{{AFX_MSG_MAP(Application)
- // NOTE - the ClassWizard will add and remove mapping macros here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG
- ON_COMMAND(ID_HELP, CWinApp::OnHelp)
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-Application gApp;
-
-//===========================================================================================================================
-// Application
-//===========================================================================================================================
-
-Application::Application( void )
-{
- //
-}
-
-//===========================================================================================================================
-// InitInstance
-//===========================================================================================================================
-
-BOOL Application::InitInstance()
-{
- DNSStatus err;
-
- // Standard MFC initialization.
-
-#if( !defined( AFX_DEPRECATED ) )
- #ifdef _AFXDLL
- Enable3dControls(); // Call this when using MFC in a shared DLL
- #else
- Enable3dControlsStatic(); // Call this when linking to MFC statically
- #endif
-#endif
-
- InitCommonControls();
-
- // Set up DNS Services.
-
- err = DNSServicesInitialize( 0, 512 );
- assert( err == kDNSNoErr );
-
- // Create the chooser dialog.
-
- ChooserDialog * dialog;
-
- m_pMainWnd = NULL;
- dialog = new ChooserDialog;
- dialog->Create( IDD_CHOOSER_DIALOG );
- m_pMainWnd = dialog;
- dialog->ShowWindow( SW_SHOW );
-
- return( true );
-}
-
-//===========================================================================================================================
-// ExitInstance
-//===========================================================================================================================
-
-int Application::ExitInstance( void )
-{
- // Clean up DNS Services.
-
- DNSServicesFinalize();
- return( 0 );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_)
-#define AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include "stdafx.h"
-
-#ifndef __AFXWIN_H__
- #error include 'stdafx.h' before including this file for PCH
-#endif
-
-#include "Resource.h"
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-extern class Application gApp;
-
-//===========================================================================================================================
-// Application
-//===========================================================================================================================
-
-class Application : public CWinApp
-{
- public:
-
- // Creation/Deletion
-
- Application();
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(Application)
- public:
- virtual BOOL InitInstance();
- virtual int ExitInstance( void );
- //}}AFX_VIRTUAL
-
- //{{AFX_MSG(Application)
- // NOTE - the ClassWizard will add and remove member functions here.
- // DO NOT EDIT what you see in these blocks of generated code !
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_)
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <algorithm>
-#include <memory>
-
-#include "stdafx.h"
-
-#include "DNSServices.h"
-
-#include "Application.h"
-#include "AboutDialog.h"
-#include "LoginDialog.h"
-#include "Resource.h"
-
-#include "ChooserDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-// Menus
-
-enum
-{
- kChooserMenuIndexFile = 0,
- kChooserMenuIndexHelp = 1
-};
-
-// Domain List
-
-#define kDomainListDefaultDomainColumnWidth 164
-
-// Service List
-
-#define kServiceListDefaultServiceColumnTypeWidth 146
-#define kServiceListDefaultServiceColumnDescWidth 230
-
-// Chooser List
-
-#define kChooserListDefaultNameColumnWidth 190
-#define kChooserListDefaultIPColumnWidth 120
-
-// Windows User Messages
-
-#define WM_USER_DOMAIN_ADD ( WM_USER + 0x100 )
-#define WM_USER_DOMAIN_REMOVE ( WM_USER + 0x101 )
-#define WM_USER_SERVICE_ADD ( WM_USER + 0x102 )
-#define WM_USER_SERVICE_REMOVE ( WM_USER + 0x103 )
-#define WM_USER_RESOLVE ( WM_USER + 0x104 )
-
-#if 0
-#pragma mark == Constants - Service Table ==
-#endif
-
-//===========================================================================================================================
-// Constants - Service Table
-//===========================================================================================================================
-
-struct KnownServiceEntry
-{
- const char * serviceType;
- const char * description;
- const char * urlScheme;
- bool useText;
-};
-
-static const KnownServiceEntry kKnownServiceTable[] =
-{
- { "_accountedge._tcp.", "MYOB AccountEdge", "", false },
- { "_aecoretech._tcp.", "Apple Application Engineering Services", "", false },
- { "_afpovertcp._tcp.", "Apple File Sharing (AFP)", "afp://", false },
- { "_airport._tcp.", "AirPort Base Station", "", false },
- { "_apple-sasl._tcp.", "Apple Password Server", "", false },
- { "_aquamon._tcp.", "AquaMon", "", false },
- { "_async._tcp", "address-o-sync", "", false },
- { "_auth._tcp.", "Authentication Service", "", false },
- { "_bootps._tcp.", "Bootstrap Protocol Server", "", false },
- { "_bousg._tcp.", "Bag Of Unusual Strategy Games", "", false },
- { "_browse._udp.", "DNS Service Discovery", "", false },
- { "_cheat._tcp.", "The Cheat", "", false },
- { "_chess._tcp", "Project Gridlock", "", false },
- { "_chfts._tcp", "Fluid Theme Server", "", false },
- { "_clipboard._tcp", "Clipboard Sharing", "", false },
- { "_contactserver._tcp.", "Now Up-to-Date & Contact", "", false },
- { "_cvspserver._tcp", "CVS PServer", "", false },
- { "_cytv._tcp.", "CyTV Network streaming for Elgato EyeTV", "", false },
- { "_daap._tcp.", "Digital Audio Access Protocol (iTunes)", "daap://", false },
- { "_distcc._tcp", "Distributed Compiler", "", false },
- { "_dns-sd._udp", "DNS Service Discovery", "", false },
- { "_dpap._tcp.", "Digital Picture Access Protocol (iPhoto)", "", false },
- { "_earphoria._tcp.", "Earphoria", "", false },
- { "_ecbyesfsgksc._tcp.", "Net Monitor Anti-Piracy Service", "", false },
- { "_eheap._tcp.", "Interactive Room Software", "", false },
- { "_embrace._tcp.", "DataEnvoy", "", false },
- { "_eppc._tcp.", "Remote AppleEvents", "eppc://", false },
- { "_exec._tcp.", "Remote Process Execution", "", false },
- { "_facespan._tcp.", "FaceSpan", "", false },
- { "_fjork._tcp.", "Fjork", "", false },
- { "_ftp._tcp.", "File Transfer (FTP)", "ftp://", false },
- { "_ftpcroco._tcp.", "Crocodile FTP Server", "", false },
- { "_gbs-smp._tcp.", "SnapMail", "", false },
- { "_gbs-stp._tcp.", "SnapTalk", "", false },
- { "_grillezvous._tcp.", "Roxio ToastAnywhere(tm) Recorder Sharing", "", false },
- { "_h323._tcp.", "H.323", "", false },
- { "_hotwayd._tcp", "Hotwayd", "", false },
- { "_http._tcp.", "Web Server (HTTP)", "http://", true },
- { "_hydra._tcp", "SubEthaEdit", "", false },
- { "_ica-networking._tcp.", "Image Capture Networking", "", false },
- { "_ichalkboard._tcp.", "iChalk", "", false },
- { "_ichat._tcp.", "iChat", "ichat://", false },
- { "_iconquer._tcp.", "iConquer", "", false },
- { "_imap._tcp.", "Internet Message Access Protocol", "", false },
- { "_imidi._tcp.", "iMidi", "", false },
- { "_ipp._tcp.", "Printer (IPP)", "ipp://", false },
- { "_ishare._tcp.", "iShare", "", false },
- { "_isparx._tcp.", "iSparx", "", false },
- { "_istorm._tcp", "iStorm", "", false },
- { "_iwork._tcp.", "iWork Server", "", false },
- { "_liaison._tcp.", "Liaison", "", false },
- { "_login._tcp.", "Remote Login a la Telnet", "", false },
- { "_lontalk._tcp.", "LonTalk over IP (ANSI 852)", "", false },
- { "_lonworks._tcp.", "Echelon LNS Remote Client", "", false },
- { "_macfoh-remote._tcp.", "MacFOH Remote", "", false },
- { "_moneyworks._tcp.", "MoneyWorks", "", false },
- { "_mp3sushi._tcp", "MP3 Sushi", "", false },
- { "_mttp._tcp.", "MenuTunes Sharing", "", false },
- { "_ncbroadcast._tcp.", "Network Clipboard Broadcasts", "", false },
- { "_ncdirect._tcp.", "Network Clipboard Direct Transfers", "", false },
- { "_ncsyncserver._tcp.", "Network Clipboard Sync Server", "", false },
- { "_newton-dock._tcp.", "Escale", "", false },
- { "_nfs._tcp", "NFS", "", false },
- { "_nssocketport._tcp.", "DO over NSSocketPort", "", false },
- { "_omni-bookmark._tcp.", "OmniWeb", "", false },
- { "_openbase._tcp.", "OpenBase SQL", "", false },
- { "_p2pchat._tcp.", "Peer-to-Peer Chat", "", false },
- { "_pdl-datastream._tcp.", "Printer (PDL)", "pdl://", false },
- { "_poch._tcp.", "Parallel OperatiOn and Control Heuristic", "", false },
- { "_pop_2_ambrosia._tcp.", "Pop-Pop", "", false },
- { "_pop3._tcp", "POP3 Server", "", false },
- { "_postgresql._tcp", "PostgreSQL Server", "", false },
- { "_presence._tcp", "iChat AV", "", false },
- { "_printer._tcp.", "Printer (LPR)", "lpr://", false },
- { "_ptp._tcp.", "Picture Transfer (PTP)", "ptp://", false },
- { "_register._tcp", "DNS Service Discovery", "", false },
- { "_rfb._tcp.", "Remote Frame Buffer", "", false },
- { "_riousbprint._tcp.", "Remote I/O USB Printer Protocol", "", false },
- { "_rtsp._tcp.", "Real Time Stream Control Protocol", "", false },
- { "_safarimenu._tcp", "Safari Menu", "", false },
- { "_scone._tcp", "Scone", "", false },
- { "_sdsharing._tcp.", "Speed Download", "", false },
- { "_seeCard._tcp.", "seeCard", "", false },
- { "_services._udp.", "DNS Service Discovery", "", false },
- { "_shell._tcp.", "like exec, but automatic authentication", "", false },
- { "_shout._tcp.", "Shout", "", false },
- { "_shoutcast._tcp", "Nicecast", "", false },
- { "_smb._tcp.", "Windows File Sharing (SMB)", "smb://", false },
- { "_soap._tcp.", "Simple Object Access Protocol", "", false },
- { "_spincrisis._tcp.", "Spin Crisis", "", false },
- { "_spl-itunes._tcp.", "launchTunes", "", false },
- { "_spr-itunes._tcp.", "netTunes", "", false },
- { "_ssh._tcp.", "Secure Shell (SSH)", "ssh://", false },
- { "_ssscreenshare._tcp", "Screen Sharing", "", false },
- { "_sge-exec._tcp", "Sun Grid Engine (Execution Host)", "", false },
- { "_sge-qmaster._tcp", "Sun Grid Engine (Master)", "", false },
- { "_stickynotes._tcp", "Sticky Notes", "", false },
- { "_strateges._tcp", "Strateges", "", false },
- { "_sxqdea._tcp", "Synchronize! Pro X", "", false },
- { "_sybase-tds._tcp", "Sybase Server", "", false },
- { "_tce._tcp", "Power Card", "", false },
- { "_teamlist._tcp", "ARTIS Team Task", "", false },
- { "_teleport._tcp", "teleport", "", false },
- { "_telnet._tcp.", "Telnet", "telnet://", false },
- { "_tftp._tcp.", "Trivial File Transfer (TFTP)", "tftp://", false },
- { "_tinavigator._tcp.", "TI Navigator", "", false },
- { "_tivo_servemedia._tcp", "TiVo", "", false },
- { "_upnp._tcp.", "Universal Plug and Play", "", false },
- { "_utest._tcp.", "uTest", "", false },
- { "_vue4rendercow._tcp", "VueProRenderCow", "", false },
- { "_webdav._tcp.", "WebDAV", "webdav://", false },
- { "_whamb._tcp.", "Whamb", "", false },
- { "_workstation._tcp", "Macintosh Manager", "", false },
- { "_ws._tcp", "Web Services", "", false },
- { "_xserveraid._tcp.", "Xserve RAID", "xsr://", false },
- { "_xsync._tcp.", "Xserve RAID Synchronization", "", false },
-
- { "", "", "", false },
-
- // Unofficial and invalid service types that will be phased out:
-
- { "_clipboardsharing._tcp.", "ClipboardSharing", "", false },
- { "_MacOSXDupSuppress._tcp.", "Mac OS X Duplicate Suppression", "", false },
- { "_netmonitorserver._tcp.", "Net Monitor Server", "", false },
- { "_networkclipboard._tcp.", "Network Clipboard", "", false },
- { "_slimdevices_slimp3_cli._tcp.", "SliMP3 Server Command-Line Interface", "", false },
- { "_slimdevices_slimp3_http._tcp.", "SliMP3 Server Web Interface", "", false },
- { "_tieducationalhandhelddevice._tcp.", "TI Connect Manager", "", false },
- { "_tivo_servemedia._tcp.", "TiVo", "", false },
-
- { NULL, NULL, NULL, false },
-};
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-// Structures
-//===========================================================================================================================
-
-struct DomainEventInfo
-{
- DNSBrowserEventType eventType;
- CString domain;
- DNSNetworkAddress ifIP;
-};
-
-struct ServiceEventInfo
-{
- DNSBrowserEventType eventType;
- std::string name;
- std::string type;
- std::string domain;
- DNSNetworkAddress ifIP;
-};
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-static void
- BrowserCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent );
-
-static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, size_t inLen, char *outString );
-
-static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject );
-static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 );
-
-#if 0
-#pragma mark == Message Map ==
-#endif
-
-//===========================================================================================================================
-// Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(ChooserDialog, CDialog)
- //{{AFX_MSG_MAP(ChooserDialog)
- ON_WM_SYSCOMMAND()
- ON_NOTIFY(LVN_ITEMCHANGED, IDC_DOMAIN_LIST, OnDomainListChanged)
- ON_NOTIFY(LVN_ITEMCHANGED, IDC_SERVICE_LIST, OnServiceListChanged)
- ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHOOSER_LIST, OnChooserListChanged)
- ON_NOTIFY(NM_DBLCLK, IDC_CHOOSER_LIST, OnChooserListDoubleClick)
- ON_COMMAND(ID_HELP_ABOUT, OnAbout)
- ON_WM_INITMENUPOPUP()
- ON_WM_ACTIVATE()
- ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
- ON_COMMAND(ID_FILE_EXIT, OnExit)
- ON_WM_CLOSE()
- ON_WM_NCDESTROY()
- //}}AFX_MSG_MAP
- ON_MESSAGE( WM_USER_DOMAIN_ADD, OnDomainAdd )
- ON_MESSAGE( WM_USER_DOMAIN_REMOVE, OnDomainRemove )
- ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
- ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
- ON_MESSAGE( WM_USER_RESOLVE, OnResolve )
-END_MESSAGE_MAP()
-
-#if 0
-#pragma mark == Routines ==
-#endif
-
-//===========================================================================================================================
-// ChooserDialog
-//===========================================================================================================================
-
-ChooserDialog::ChooserDialog( CWnd *inParent )
- : CDialog( ChooserDialog::IDD, inParent)
-{
- //{{AFX_DATA_INIT(ChooserDialog)
- // Note: the ClassWizard will add member initialization here
- //}}AFX_DATA_INIT
-
- // Load menu accelerator table.
-
- mMenuAcceleratorTable = ::LoadAccelerators( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ) );
- assert( mMenuAcceleratorTable );
-
- mBrowser = NULL;
- mIsServiceBrowsing = false;
-}
-
-//===========================================================================================================================
-// ~ChooserDialog
-//===========================================================================================================================
-
-ChooserDialog::~ChooserDialog( void )
-{
- if( mBrowser )
- {
- DNSStatus err;
-
- err = DNSBrowserRelease( mBrowser, 0 );
- assert( err == kDNSNoErr );
- }
-}
-
-//===========================================================================================================================
-// DoDataExchange
-//===========================================================================================================================
-
-void ChooserDialog::DoDataExchange( CDataExchange *pDX )
-{
- CDialog::DoDataExchange(pDX);
-
- //{{AFX_DATA_MAP(ChooserDialog)
- DDX_Control(pDX, IDC_SERVICE_LIST, mServiceList);
- DDX_Control(pDX, IDC_DOMAIN_LIST, mDomainList);
- DDX_Control(pDX, IDC_CHOOSER_LIST, mChooserList);
- //}}AFX_DATA_MAP
-}
-
-//===========================================================================================================================
-// OnInitDialog
-//===========================================================================================================================
-
-BOOL ChooserDialog::OnInitDialog( void )
-{
- HICON icon;
- BOOL result;
- CString tempString;
- DNSStatus err;
-
- // Initialize our parent.
-
- CDialog::OnInitDialog();
-
- // Set up the window icon.
-
- icon = AfxGetApp()->LoadIcon( IDR_MAIN_ICON );
- assert( icon );
- if( icon )
- {
- SetIcon( icon, TRUE ); // Set big icon
- SetIcon( icon, FALSE ); // Set small icon
- }
-
- // Set up the Domain List.
-
- result = tempString.LoadString( IDS_CHOOSER_DOMAIN_COLUMN_NAME );
- assert( result );
- mDomainList.InsertColumn( 0, tempString, LVCFMT_LEFT, kDomainListDefaultDomainColumnWidth );
-
- // Set up the Service List.
-
- result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE );
- assert( result );
- mServiceList.InsertColumn( 0, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnTypeWidth );
-
- result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_DESC );
- assert( result );
- mServiceList.InsertColumn( 1, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnDescWidth );
-
- PopulateServicesList();
-
- // Set up the Chooser List.
-
- result = tempString.LoadString( IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME );
- assert( result );
- mChooserList.InsertColumn( 0, tempString, LVCFMT_LEFT, kChooserListDefaultNameColumnWidth );
-
- result = tempString.LoadString( IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME );
- assert( result );
- mChooserList.InsertColumn( 1, tempString, LVCFMT_LEFT, kChooserListDefaultIPColumnWidth );
-
- // Set up the other controls.
-
- UpdateInfoDisplay();
-
- // Start browsing for domains.
-
- err = DNSBrowserCreate( 0, BrowserCallBack, this, &mBrowser );
- assert( err == kDNSNoErr );
-
- err = DNSBrowserStartDomainSearch( mBrowser, 0 );
- assert( err == kDNSNoErr );
-
- return( true );
-}
-
-//===========================================================================================================================
-// OnFileClose
-//===========================================================================================================================
-
-void ChooserDialog::OnFileClose()
-{
- OnClose();
-}
-
-//===========================================================================================================================
-// OnActivate
-//===========================================================================================================================
-
-void ChooserDialog::OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized )
-{
- // Always make the active window the "main" window so modal dialogs work better and the app quits after closing
- // the last window.
-
- gApp.m_pMainWnd = this;
-
- CDialog::OnActivate(nState, pWndOther, bMinimized);
-}
-
-//===========================================================================================================================
-// PostNcDestroy
-//===========================================================================================================================
-
-void ChooserDialog::PostNcDestroy()
-{
- // Call the base class to do the normal cleanup.
-
- delete this;
-}
-
-//===========================================================================================================================
-// PreTranslateMessage
-//===========================================================================================================================
-
-BOOL ChooserDialog::PreTranslateMessage(MSG* pMsg)
-{
- BOOL result;
-
- result = false;
- assert( mMenuAcceleratorTable );
- if( mMenuAcceleratorTable )
- {
- result = ::TranslateAccelerator( m_hWnd, mMenuAcceleratorTable, pMsg );
- }
- if( !result )
- {
- result = CDialog::PreTranslateMessage( pMsg );
- }
- return( result );
-}
-
-//===========================================================================================================================
-// OnInitMenuPopup
-//===========================================================================================================================
-
-void ChooserDialog::OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMenu )
-{
- CDialog::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );
-
- switch( nIndex )
- {
- case kChooserMenuIndexFile:
- break;
-
- case kChooserMenuIndexHelp:
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// OnExit
-//===========================================================================================================================
-
-void ChooserDialog::OnExit()
-{
- OnClose();
-}
-
-//===========================================================================================================================
-// OnAbout
-//===========================================================================================================================
-
-void ChooserDialog::OnAbout()
-{
- AboutDialog dialog;
-
- dialog.DoModal();
-}
-
-//===========================================================================================================================
-// OnSysCommand
-//===========================================================================================================================
-
-void ChooserDialog::OnSysCommand( UINT inID, LPARAM inParam )
-{
- CDialog::OnSysCommand( inID, inParam );
-}
-
-//===========================================================================================================================
-// OnClose
-//===========================================================================================================================
-
-void ChooserDialog::OnClose()
-{
- StopBrowsing();
-
- gApp.m_pMainWnd = this;
- DestroyWindow();
-}
-
-//===========================================================================================================================
-// OnNcDestroy
-//===========================================================================================================================
-
-void ChooserDialog::OnNcDestroy()
-{
- gApp.m_pMainWnd = this;
-
- CDialog::OnNcDestroy();
-}
-
-//===========================================================================================================================
-// OnDomainListChanged
-//===========================================================================================================================
-
-void ChooserDialog::OnDomainListChanged( NMHDR *pNMHDR, LRESULT *pResult )
-{
- UNUSED_ALWAYS( pNMHDR );
-
- // Domain list changes have similar effects to service list changes so reuse that code path by calling it here.
-
- OnServiceListChanged( NULL, NULL );
-
- *pResult = 0;
-}
-
-//===========================================================================================================================
-// OnServiceListChanged
-//===========================================================================================================================
-
-void ChooserDialog::OnServiceListChanged( NMHDR *pNMHDR, LRESULT *pResult )
-{
- int selectedType;
- int selectedDomain;
-
- UNUSED_ALWAYS( pNMHDR );
-
- // Stop any existing service search.
-
- StopBrowsing();
-
- // If a domain and service type are selected, start searching for the service type on the domain.
-
- selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
- selectedDomain = mDomainList.GetNextItem( -1, LVNI_SELECTED );
-
- if( ( selectedType >= 0 ) && ( selectedDomain >= 0 ) )
- {
- CString s;
- std::string utf8;
- const char * type;
-
- s = mDomainList.GetItemText( selectedDomain, 0 );
- StringObjectToUTF8String( s, utf8 );
- type = mServiceTypes[ selectedType ].serviceType.c_str();
- if( *type != '\0' )
- {
- StartBrowsing( type, utf8.c_str() );
- }
- }
-
- if( pResult )
- {
- *pResult = 0;
- }
-}
-
-//===========================================================================================================================
-// OnChooserListChanged
-//===========================================================================================================================
-
-void ChooserDialog::OnChooserListChanged( NMHDR *pNMHDR, LRESULT *pResult )
-{
- UNUSED_ALWAYS( pNMHDR );
-
- UpdateInfoDisplay();
- *pResult = 0;
-}
-
-//===========================================================================================================================
-// OnChooserListDoubleClick
-//===========================================================================================================================
-
-void ChooserDialog::OnChooserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
-{
- int selectedItem;
-
- UNUSED_ALWAYS( pNMHDR );
-
- // Display the service instance if it is selected. Otherwise, clear all the info.
-
- selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
- if( selectedItem >= 0 )
- {
- ServiceInstanceInfo * p;
- CString url;
- const KnownServiceEntry * service;
-
- assert( selectedItem < (int) mServiceInstances.size() );
- p = &mServiceInstances[ selectedItem ];
-
- // Search for a known service type entry that matches.
-
- for( service = kKnownServiceTable; service->serviceType; ++service )
- {
- if( p->type == service->serviceType )
- {
- break;
- }
- }
- if( service->serviceType )
- {
- const char * text;
-
- // Create a URL representing the service instance.
-
- if( strcmp( service->serviceType, "_smb._tcp." ) == 0 )
- {
- // Special case for SMB (no port number).
-
- url.Format( TEXT( "%s%s/" ), service->urlScheme, (const char *) p->ip.c_str() );
- }
- else if( strcmp( service->serviceType, "_ftp._tcp." ) == 0 )
- {
- // Special case for FTP to get login info.
-
- LoginDialog dialog;
- CString username;
- CString password;
-
- if( !dialog.GetLogin( username, password ) )
- {
- goto exit;
- }
-
- // Build URL in the following format:
- //
- // ftp://[username[:password]@]<ip>
-
- url += service->urlScheme;
- if( username.GetLength() > 0 )
- {
- url += username;
- if( password.GetLength() > 0 )
- {
- url += ':';
- url += password;
- }
- url += '@';
- }
- url += p->ip.c_str();
- }
- else if( strcmp( service->serviceType, "_http._tcp." ) == 0 )
- {
- // Special case for HTTP to exclude "path=" if present.
-
- text = service->useText ? p->text.c_str() : "";
- if( strncmp( text, "path=", 5 ) == 0 )
- {
- text += 5;
- }
- if( *text != '/' )
- {
- url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
- }
- else
- {
- url.Format( TEXT( "%s%s%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
- }
- }
- else
- {
- text = service->useText ? p->text.c_str() : "";
- url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
- }
-
- // Let the system open the URL in the correct app.
-
- {
- CWaitCursor waitCursor;
-
- ShellExecute( NULL, TEXT( "open" ), url, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL );
- }
- }
- }
-
-exit:
- *pResult = 0;
-}
-
-//===========================================================================================================================
-// OnCancel
-//===========================================================================================================================
-
-void ChooserDialog::OnCancel()
-{
- // Do nothing.
-}
-
-//===========================================================================================================================
-// PopulateServicesList
-//===========================================================================================================================
-
-void ChooserDialog::PopulateServicesList( void )
-{
- ServiceTypeVector::iterator i;
- CString type;
- CString desc;
- std::string tmp;
-
- // Add a fixed list of known services.
-
- if( mServiceTypes.empty() )
- {
- const KnownServiceEntry * service;
-
- for( service = kKnownServiceTable; service->serviceType; ++service )
- {
- ServiceTypeInfo info;
-
- info.serviceType = service->serviceType;
- info.description = service->description;
- info.urlScheme = service->urlScheme;
- mServiceTypes.push_back( info );
- }
- }
-
- // Add each service to the list.
-
- for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i )
- {
- const char * p;
- const char * q;
-
- p = ( *i ).serviceType.c_str();
- if( *p == '_' ) ++p; // Skip leading '_'.
- q = strchr( p, '.' ); // Find first '.'.
- if( q ) tmp.assign( p, (size_t)( q - p ) ); // Use only up to the first '.'.
- else tmp.assign( p ); // No '.' so use the entire string.
- UTF8StringToStringObject( tmp.c_str(), type );
- UTF8StringToStringObject( ( *i ).description.c_str(), desc );
-
- int n;
-
- n = mServiceList.GetItemCount();
- mServiceList.InsertItem( n, type );
- mServiceList.SetItemText( n, 1, desc );
- }
-
- // Select the first service type by default.
-
- if( !mServiceTypes.empty() )
- {
- mServiceList.SetItemState( 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
- }
-}
-
-//===========================================================================================================================
-// UpdateInfoDisplay
-//===========================================================================================================================
-
-void ChooserDialog::UpdateInfoDisplay( void )
-{
- int selectedItem;
- std::string name;
- CString s;
- std::string ip;
- std::string ifIP;
- std::string text;
- std::string textNewLines;
- std::string hostName;
- CWnd * item;
- std::string::iterator i;
-
- // Display the service instance if it is selected. Otherwise, clear all the info.
-
- selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
- if( selectedItem >= 0 )
- {
- ServiceInstanceInfo * p;
-
- assert( selectedItem < (int) mServiceInstances.size() );
- p = &mServiceInstances[ selectedItem ];
-
- name = p->name;
- ip = p->ip;
- ifIP = p->ifIP;
- text = p->text;
- hostName = p->hostName;
-
- // Sync up the list items with the actual data (IP address may change).
-
- UTF8StringToStringObject( ip.c_str(), s );
- mChooserList.SetItemText( selectedItem, 1, s );
- }
-
- // Name
-
- item = (CWnd *) this->GetDlgItem( IDC_INFO_NAME_TEXT );
- assert( item );
- UTF8StringToStringObject( name.c_str(), s );
- item->SetWindowText( s );
-
- // IP
-
- item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT );
- assert( item );
- UTF8StringToStringObject( ip.c_str(), s );
- item->SetWindowText( s );
-
- // Interface
-
- item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT );
- assert( item );
- UTF8StringToStringObject( ifIP.c_str(), s );
- item->SetWindowText( s );
-
-
- item = (CWnd *) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT );
- assert( item );
- UTF8StringToStringObject( hostName.c_str(), s );
- item->SetWindowText( s );
-
- // Text
-
- item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT );
- assert( item );
- for( i = text.begin(); i != text.end(); ++i )
- {
- if( *i == '\1' )
- {
- textNewLines += "\r\n";
- }
- else
- {
- textNewLines += *i;
- }
- }
- UTF8StringToStringObject( textNewLines.c_str(), s );
- item->SetWindowText( s );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// OnDomainAdd
-//===========================================================================================================================
-
-LONG ChooserDialog::OnDomainAdd( WPARAM inWParam, LPARAM inLParam )
-{
- DomainEventInfo * p;
- std::auto_ptr < DomainEventInfo > pAutoPtr;
- int n;
- int i;
- CString domain;
- CString s;
- bool found;
-
- UNUSED_ALWAYS( inWParam );
-
- assert( inLParam );
- p = reinterpret_cast <DomainEventInfo *> ( inLParam );
- pAutoPtr.reset( p );
-
- // Search to see if we already know about this domain. If not, add it to the list.
-
- found = false;
- domain = p->domain;
- n = mDomainList.GetItemCount();
- for( i = 0; i < n; ++i )
- {
- s = mDomainList.GetItemText( i, 0 );
- if( s == domain )
- {
- found = true;
- break;
- }
- }
- if( !found )
- {
- int selectedItem;
-
- mDomainList.InsertItem( n, domain );
-
- // If no domains are selected and the domain being added is a default domain, select it.
-
- selectedItem = mDomainList.GetNextItem( -1, LVNI_SELECTED );
- if( ( selectedItem < 0 ) && ( p->eventType == kDNSBrowserEventTypeAddDefaultDomain ) )
- {
- mDomainList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
- }
- }
- return( 0 );
-}
-
-//===========================================================================================================================
-// OnDomainRemove
-//===========================================================================================================================
-
-LONG ChooserDialog::OnDomainRemove( WPARAM inWParam, LPARAM inLParam )
-{
- DomainEventInfo * p;
- std::auto_ptr < DomainEventInfo > pAutoPtr;
- int n;
- int i;
- CString domain;
- CString s;
- bool found;
-
- UNUSED_ALWAYS( inWParam );
-
- assert( inLParam );
- p = reinterpret_cast <DomainEventInfo *> ( inLParam );
- pAutoPtr.reset( p );
-
- // Search to see if we know about this domain. If so, remove it from the list.
-
- found = false;
- domain = p->domain;
- n = mDomainList.GetItemCount();
- for( i = 0; i < n; ++i )
- {
- s = mDomainList.GetItemText( i, 0 );
- if( s == domain )
- {
- found = true;
- break;
- }
- }
- if( found )
- {
- mDomainList.DeleteItem( i );
- }
- return( 0 );
-}
-
-//===========================================================================================================================
-// OnServiceAdd
-//===========================================================================================================================
-
-LONG ChooserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
-{
- ServiceEventInfo * p;
- std::auto_ptr < ServiceEventInfo > pAutoPtr;
-
- UNUSED_ALWAYS( inWParam );
-
- assert( inLParam );
- p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
- pAutoPtr.reset( p );
-
- return( 0 );
-}
-
-//===========================================================================================================================
-// OnServiceRemove
-//===========================================================================================================================
-
-LONG ChooserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
-{
- ServiceEventInfo * p;
- std::auto_ptr < ServiceEventInfo > pAutoPtr;
- bool found;
- int n;
- int i;
-
- UNUSED_ALWAYS( inWParam );
-
- assert( inLParam );
- p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
- pAutoPtr.reset( p );
-
- // Search to see if we know about this service instance. If so, remove it from the list.
-
- found = false;
- n = (int) mServiceInstances.size();
- for( i = 0; i < n; ++i )
- {
- ServiceInstanceInfo * q;
-
- // If the name, type, domain, and interface match, treat it as the same service instance.
-
- q = &mServiceInstances[ i ];
- if( ( p->name == q->name ) &&
- ( p->type == q->type ) &&
- ( p->domain == q->domain ) )
- {
- found = true;
- break;
- }
- }
- if( found )
- {
- mChooserList.DeleteItem( i );
- assert( i < (int) mServiceInstances.size() );
- mServiceInstances.erase( mServiceInstances.begin() + i );
- }
- return( 0 );
-}
-
-//===========================================================================================================================
-// OnResolve
-//===========================================================================================================================
-
-LONG ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam )
-{
- ServiceInstanceInfo * p;
- std::auto_ptr < ServiceInstanceInfo > pAutoPtr;
- int selectedType;
- int n;
- int i;
- bool found;
-
- UNUSED_ALWAYS( inWParam );
-
- assert( inLParam );
- p = reinterpret_cast <ServiceInstanceInfo *> ( inLParam );
- pAutoPtr.reset( p );
-
- // Make sure it is for an item of the correct type. This handles any resolves that may have been queued up.
-
- selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
- assert( selectedType >= 0 );
- if( selectedType >= 0 )
- {
- assert( selectedType <= (int) mServiceTypes.size() );
- if( p->type != mServiceTypes[ selectedType ].serviceType )
- {
- goto exit;
- }
- }
-
- // Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list.
-
- found = false;
- n = (int) mServiceInstances.size();
- for( i = 0; i < n; ++i )
- {
- ServiceInstanceInfo * q;
-
- // If the name, type, domain, and interface matches, treat it as the same service instance.
-
- q = &mServiceInstances[ i ];
- if( ( p->name == q->name ) &&
- ( p->type == q->type ) &&
- ( p->domain == q->domain ) &&
- ( p->ifIP == q->ifIP ) )
- {
- found = true;
- break;
- }
- }
- if( found )
- {
- mServiceInstances[ i ] = *p;
- }
- else
- {
- CString s;
-
- mServiceInstances.push_back( *p );
- UTF8StringToStringObject( p->name.c_str(), s );
- mChooserList.InsertItem( n, s );
-
- UTF8StringToStringObject( p->ip.c_str(), s );
- mChooserList.SetItemText( n, 1, s );
-
- // If this is the only item, select it.
-
- if( n == 0 )
- {
- mChooserList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
- }
- }
- UpdateInfoDisplay();
-
-exit:
- return( 0 );
-}
-
-//===========================================================================================================================
-// StartBrowsing
-//===========================================================================================================================
-
-void ChooserDialog::StartBrowsing( const char *inType, const char *inDomain )
-{
- DNSStatus err;
-
- assert( mServiceInstances.empty() );
- assert( mChooserList.GetItemCount() == 0 );
- assert( !mIsServiceBrowsing );
-
- mChooserList.DeleteAllItems();
- mServiceInstances.clear();
-
- mIsServiceBrowsing = true;
- err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, inType, inDomain );
- assert( err == kDNSNoErr );
-}
-
-//===========================================================================================================================
-// StopBrowsing
-//===========================================================================================================================
-
-void ChooserDialog::StopBrowsing( void )
-{
- // If searching, stop.
-
- if( mIsServiceBrowsing )
- {
- DNSStatus err;
-
- mIsServiceBrowsing = false;
- err = DNSBrowserStopServiceSearch( mBrowser, 0 );
- assert( err == kDNSNoErr );
- }
-
- // Remove all service instances.
-
- mChooserList.DeleteAllItems();
- assert( mChooserList.GetItemCount() == 0 );
- mServiceInstances.clear();
- assert( mServiceInstances.empty() );
- UpdateInfoDisplay();
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// BrowserCallBack
-//===========================================================================================================================
-
-static void
- BrowserCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent )
-{
- ChooserDialog * dialog;
- UINT message;
- BOOL posted;
-
- UNUSED_ALWAYS( inStatusCode );
- UNUSED_ALWAYS( inRef );
-
- // Check parameters.
-
- assert( inContext );
- dialog = reinterpret_cast <ChooserDialog *> ( inContext );
-
- try
- {
- switch( inEvent->type )
- {
- case kDNSBrowserEventTypeRelease:
- break;
-
- // Domains
-
- case kDNSBrowserEventTypeAddDomain:
- case kDNSBrowserEventTypeAddDefaultDomain:
- case kDNSBrowserEventTypeRemoveDomain:
- {
- DomainEventInfo * domain;
- std::auto_ptr < DomainEventInfo > domainAutoPtr;
-
- domain = new DomainEventInfo;
- domainAutoPtr.reset( domain );
-
- domain->eventType = inEvent->type;
- domain->domain = inEvent->data.addDomain.domain;
- domain->ifIP = inEvent->data.addDomain.interfaceIP;
-
- message = ( inEvent->type == kDNSBrowserEventTypeRemoveDomain ) ? WM_USER_DOMAIN_REMOVE : WM_USER_DOMAIN_ADD;
- posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) domain );
- assert( posted );
- if( posted )
- {
- domainAutoPtr.release();
- }
- break;
- }
-
- // Services
-
- case kDNSBrowserEventTypeAddService:
- case kDNSBrowserEventTypeRemoveService:
- {
- ServiceEventInfo * service;
- std::auto_ptr < ServiceEventInfo > serviceAutoPtr;
-
- service = new ServiceEventInfo;
- serviceAutoPtr.reset( service );
-
- service->eventType = inEvent->type;
- service->name = inEvent->data.addService.name;
- service->type = inEvent->data.addService.type;
- service->domain = inEvent->data.addService.domain;
- service->ifIP = inEvent->data.addService.interfaceIP;
-
- message = ( inEvent->type == kDNSBrowserEventTypeAddService ) ? WM_USER_SERVICE_ADD : WM_USER_SERVICE_REMOVE;
- posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) service );
- assert( posted );
- if( posted )
- {
- serviceAutoPtr.release();
- }
- break;
- }
-
- // Resolves
-
- case kDNSBrowserEventTypeResolved:
- if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 )
- {
- ServiceInstanceInfo * serviceInstance;
- std::auto_ptr < ServiceInstanceInfo > serviceInstanceAutoPtr;
- char s[ 32 ];
-
- serviceInstance = new ServiceInstanceInfo;
- serviceInstanceAutoPtr.reset( serviceInstance );
-
- serviceInstance->name = inEvent->data.resolved->name;
- serviceInstance->type = inEvent->data.resolved->type;
- serviceInstance->domain = inEvent->data.resolved->domain;
- serviceInstance->ip = DNSNetworkAddressToString( &inEvent->data.resolved->address, sizeof( s ), s );
- serviceInstance->ifIP = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, sizeof( s ), s );
- serviceInstance->text = inEvent->data.resolved->textRecord;
- serviceInstance->hostName = inEvent->data.resolved->hostName;
-
- posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_RESOLVE, 0, (LPARAM) serviceInstance );
- assert( posted );
- if( posted )
- {
- serviceInstanceAutoPtr.release();
- }
- }
- break;
-
- default:
- break;
- }
- }
- catch( ... )
- {
- // Don't let exceptions escape.
- }
-}
-
-//===========================================================================================================================
-// DNSNetworkAddressToString
-//
-// Note: Currently only supports IPv4 network addresses.
-//===========================================================================================================================
-
-static char * DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, size_t inLen, char *outString )
-{
- const DNSUInt8 * p;
- DNSUInt16 port;
-
- p = inAddr->u.ipv4.addr.v8;
- port = ntohs( inAddr->u.ipv4.port.v16 );
- if( port != kDNSPortInvalid )
- {
- snprintf( outString, inLen, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port );
- }
- else
- {
- snprintf( outString, inLen, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] );
- }
- return( outString );
-}
-
-//===========================================================================================================================
-// UTF8StringToStringObject
-//===========================================================================================================================
-
-static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject )
-{
- DWORD err;
- int n;
- BSTR unicode;
-
- unicode = NULL;
-
- n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
- if( n > 0 )
- {
- unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
- if( !unicode )
- {
- err = ERROR_INSUFFICIENT_BUFFER;
- goto exit;
- }
-
- n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
- try
- {
- inObject = unicode;
- }
- catch( ... )
- {
- err = ERROR_NO_UNICODE_TRANSLATION;
- goto exit;
- }
- }
- else
- {
- inObject = "";
- }
- err = 0;
-
-exit:
- if( unicode )
- {
- free( unicode );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// StringObjectToUTF8String
-//===========================================================================================================================
-
-static DWORD StringObjectToUTF8String( CString &inObject, std::string &outUTF8 )
-{
- DWORD err;
- BSTR unicode;
- int nUnicode;
- int n;
- char * utf8;
-
- unicode = NULL;
- utf8 = NULL;
-
- nUnicode = inObject.GetLength();
- if( nUnicode > 0 )
- {
- unicode = inObject.AllocSysString();
- n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, NULL, 0, NULL, NULL );
- assert( n > 0 );
-
- utf8 = (char *) malloc( (size_t) n );
- assert( utf8 );
- if( !utf8 ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; }
-
- n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, utf8, n, NULL, NULL );
- assert( n > 0 );
-
- try
- {
- outUTF8.assign( utf8, n );
- }
- catch( ... )
- {
- err = ERROR_NO_UNICODE_TRANSLATION;
- goto exit;
- }
- }
- else
- {
- outUTF8.clear();
- }
- err = 0;
-
-exit:
- if( unicode )
- {
- SysFreeString( unicode );
- }
- if( utf8 )
- {
- free( utf8 );
- }
- return( err );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_)
-#define AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include <string>
-#include <vector>
-
-#include "afxcmn.h"
-
-#include "Resource.h"
-
-#include "DNSServices.h"
-
-//===========================================================================================================================
-// Structures
-//===========================================================================================================================
-
-struct ServiceInstanceInfo
-{
- std::string name;
- std::string type;
- std::string domain;
- std::string ip;
- std::string text;
- std::string ifIP;
- std::string hostName;
-};
-
-struct ServiceTypeInfo
-{
- std::string serviceType;
- std::string description;
- std::string urlScheme;
-};
-
-//===========================================================================================================================
-// ChooserDialog
-//===========================================================================================================================
-
-class ChooserDialog : public CDialog
-{
- public:
-
- ChooserDialog(CWnd* pParent = NULL);
- virtual ~ChooserDialog( void );
-
- //{{AFX_DATA(ChooserDialog)
- enum { IDD = IDD_CHOOSER_DIALOG };
- CListCtrl mServiceList;
- CListCtrl mDomainList;
- CListCtrl mChooserList;
- //}}AFX_DATA
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(ChooserDialog)
- public:
- virtual BOOL PreTranslateMessage(MSG* pMsg);
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- virtual void PostNcDestroy();
- //}}AFX_VIRTUAL
-
- protected:
-
- typedef std::vector < ServiceInstanceInfo > ServiceInstanceVector;
- typedef std::vector < ServiceTypeInfo > ServiceTypeVector;
-
- HACCEL mMenuAcceleratorTable;
- DNSBrowserRef mBrowser;
- BOOL mIsServiceBrowsing;
- ServiceInstanceVector mServiceInstances;
- ServiceTypeVector mServiceTypes;
-
- public:
-
- void PopulateServicesList( void );
- void UpdateInfoDisplay( void );
-
- void StartBrowsing( const char *inType, const char *inDomain );
- void StopBrowsing( void );
-
- protected:
-
- //{{AFX_MSG(ChooserDialog)
- virtual BOOL OnInitDialog();
- afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
- afx_msg void OnDomainListChanged(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg void OnServiceListChanged(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg void OnChooserListChanged(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg void OnChooserListDoubleClick(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg void OnAbout();
- afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu);
- afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
- afx_msg void OnFileClose();
- virtual void OnCancel();
- afx_msg void OnExit();
- afx_msg void OnClose();
- afx_msg void OnNcDestroy();
- //}}AFX_MSG
- afx_msg LONG OnDomainAdd( WPARAM inWParam, LPARAM inLParam );
- afx_msg LONG OnDomainRemove( WPARAM inWParam, LPARAM inLParam );
- afx_msg LONG OnServiceAdd( WPARAM inWParam, LPARAM inLParam );
- afx_msg LONG OnServiceRemove( WPARAM inWParam, LPARAM inLParam );
- afx_msg LONG OnResolve( WPARAM inWParam, LPARAM inLParam );
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_)
+++ /dev/null
-/* -*- 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.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-
-#include "stdafx.h"
-
-#include "LoginDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-// Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP( LoginDialog, CDialog )
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-// LoginDialog
-//===========================================================================================================================
-
-LoginDialog::LoginDialog( CWnd *inParent )
- : CDialog( LoginDialog::IDD, inParent )
-{
- //
-}
-
-//===========================================================================================================================
-// OnInitDialog
-//===========================================================================================================================
-
-BOOL LoginDialog::OnInitDialog( void )
-{
- CDialog::OnInitDialog();
- return( TRUE );
-}
-
-//===========================================================================================================================
-// DoDataExchange
-//===========================================================================================================================
-
-void LoginDialog::DoDataExchange( CDataExchange *inDX )
-{
- CDialog::DoDataExchange( inDX );
-}
-
-//===========================================================================================================================
-// OnOK
-//===========================================================================================================================
-
-void LoginDialog::OnOK( void )
-{
- const CWnd * control;
-
- // Username
-
- control = GetDlgItem( IDC_LOGIN_USERNAME_TEXT );
- assert( control );
- if( control )
- {
- control->GetWindowText( mUsername );
- }
-
- // Password
-
- control = GetDlgItem( IDC_LOGIN_PASSWORD_TEXT );
- assert( control );
- if( control )
- {
- control->GetWindowText( mPassword );
- }
-
- CDialog::OnOK();
-}
-
-//===========================================================================================================================
-// GetLogin
-//===========================================================================================================================
-
-BOOL LoginDialog::GetLogin( CString &outUsername, CString &outPassword )
-{
- if( DoModal() == IDOK )
- {
- outUsername = mUsername;
- outPassword = mPassword;
- return( TRUE );
- }
- return( FALSE );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef __LOGIN_DIALOG__
-#define __LOGIN_DIALOG__
-
-#pragma once
-
-#include "Resource.h"
-
-//===========================================================================================================================
-// LoginDialog
-//===========================================================================================================================
-
-class LoginDialog : public CDialog
-{
- protected:
-
- CString mUsername;
- CString mPassword;
-
- public:
-
- enum { IDD = IDD_LOGIN };
-
- LoginDialog( CWnd *inParent = NULL );
-
- virtual BOOL GetLogin( CString &outUsername, CString &outPassword );
-
- protected:
-
- virtual BOOL OnInitDialog( void );
- virtual void DoDataExchange( CDataExchange *inDX );
- virtual void OnOK( void );
-
- DECLARE_MESSAGE_MAP()
-};
-
-#endif // __LOGIN_DIALOG__
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stdafx.h"
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_)
-#define AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
-
-#ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later.
- #define WINVER 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
-#endif
-
-#include <afxwin.h> // MFC core and standard components
-#include <afxext.h> // MFC extensions
-#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
-#ifndef _AFX_NO_AFXCMN_SUPPORT
- #include <afxcmn.h> // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-
-#include <winsock2.h>
-
-#include <stdlib.h>
-
-#include "DNSServices.h"
-
-#include "Application.h"
-
-#include "ChooserDialog.h"
-
-#endif // !defined(AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_)
+++ /dev/null
-; CLW file contains information for the MFC ClassWizard
-
-[General Info]
-Version=1
-LastClass=BrowserDialog
-LastTemplate=CDialog
-NewFileInclude1=#include "stdafx.h"
-NewFileInclude2=#include "Application.h"
-
-ClassCount=3
-Class1=Application
-Class2=BrowserDialog
-
-ResourceCount=3
-Resource2=IDR_MAINFRAME
-Resource3=IDD_APPLICATION_DIALOG
-
-[CLS:Application]
-Type=0
-HeaderFile=Application.h
-ImplementationFile=Application.cpp
-Filter=N
-
-[CLS:BrowserDialog]
-Type=0
-HeaderFile=BrowserDialog.h
-ImplementationFile=BrowserDialog.cpp
-Filter=D
-
-
-[DLG:IDD_APPLICATION_DIALOG]
-Type=1
-ControlCount=3
-Control1=IDOK,button,1342242817
-Control2=IDCANCEL,button,1342242816
-Control3=IDC_STATIC,static,1342308352
-Class=BrowserDialog
+++ /dev/null
-# Microsoft eMbedded Visual Tools Project File - Name="Application" - Package Owner=<4>
-# Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (WCE ARMV4) Application" 0xa301
-# TARGTYPE "Win32 (WCE emulator) Application" 0xa601
-
-CFG=Application - Win32 (WCE emulator) Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "Application.vcn".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "Application.vcn" CFG="Application - Win32 (WCE emulator) Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "Application - Win32 (WCE emulator) Release" (based on "Win32 (WCE emulator) Application")
-!MESSAGE "Application - Win32 (WCE emulator) Debug" (based on "Win32 (WCE emulator) Application")
-!MESSAGE "Application - Win32 (WCE ARMV4) Release" (based on "Win32 (WCE ARMV4) Application")
-!MESSAGE "Application - Win32 (WCE ARMV4) Debug" (based on "Win32 (WCE ARMV4) Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-# PROP ATL_Project 2
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "emulatorRel"
-# PROP BASE Intermediate_Dir "emulatorRel"
-# PROP BASE CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "emulatorRel"
-# PROP Intermediate_Dir "emulatorRel"
-# PROP CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /D "_i386_" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_WIN32_WCE_CEPC" /D "_AFXDLL" /Yu"stdafx.h" /Gs8192 /GF /O2 /c
-# ADD CPP /nologo /W3 /WX /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "_i386_" /D "_X86_" /D "x86" /D "NDEBUG" /D "_WIN32_WCE_CEPC" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /Gs8192 /GF /O2 /c
-# SUBTRACT CPP /YX /Yc /Yu
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /MACHINE:IX86
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /MACHINE:IX86
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "emulatorDbg"
-# PROP BASE Intermediate_Dir "emulatorDbg"
-# PROP BASE CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "emulatorDbg"
-# PROP Intermediate_Dir "emulatorDbg"
-# PROP CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D "_i386_" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_WIN32_WCE_CEPC" /D "_AFXDLL" /Yu"stdafx.h" /Gs8192 /GF /c
-# ADD CPP /nologo /W3 /WX /Zi /Od /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "_i386_" /D "_X86_" /D "x86" /D "_WIN32_WCE_CEPC" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /FR /Gs8192 /GF /c
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /MACHINE:IX86
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /MACHINE:IX86
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "ARMV4Rel"
-# PROP BASE Intermediate_Dir "ARMV4Rel"
-# PROP BASE CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "ARMV4Rel"
-# PROP Intermediate_Dir "ARMV4Rel"
-# PROP CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "NDEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "NDEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-CPP=clarm.exe
-# ADD BASE CPP /nologo /W3 /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_AFXDLL" /Yu"stdafx.h" /O2 /M$(CECrtMT) /c
-# ADD CPP /nologo /W3 /WX /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "ARM" /D "_ARM_" /D "ARMV4" /D "NDEBUG" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /O2 /M$(CECrtMT) /c
-# SUBTRACT CPP /YX /Yc /Yu
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "ARMV4Dbg"
-# PROP BASE Intermediate_Dir "ARMV4Dbg"
-# PROP BASE CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "ARMV4Dbg"
-# PROP Intermediate_Dir "ARMV4Dbg"
-# PROP CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "DEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "DEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-CPP=clarm.exe
-# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /Yu"stdafx.h" /M$(CECrtMTDebug) /c
-# ADD CPP /nologo /W3 /WX /Zi /Od /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /FR /M$(CECrtMTDebug) /c
-# SUBTRACT CPP /YX /Yc /Yu
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-
-!ENDIF
-
-# Begin Target
-
-# Name "Application - Win32 (WCE emulator) Release"
-# Name "Application - Win32 (WCE emulator) Debug"
-# Name "Application - Win32 (WCE ARMV4) Release"
-# Name "Application - Win32 (WCE ARMV4) Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\Sources\Application.cpp
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_APPLI=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_APPLI=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_APPLI=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_APPLI=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\Application.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\BrowserDialog.cpp
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_BROWS=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_BROWS=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_BROWS=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_BROWS=\
- "..\..\..\DNSServices\DNSServices.h"\
- ".\Sources\Application.h"\
- ".\Sources\BrowserDialog.h"\
- ".\Sources\StdAfx.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\BrowserDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\StdAfx.cpp
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_STDAF=\
- ".\Sources\StdAfx.h"\
-
-# ADD CPP /Yc"stdafx.h"
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_STDAF=\
- ".\Sources\StdAfx.h"\
-
-# ADD CPP /Yc"stdafx.h"
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_STDAF=\
- ".\Sources\StdAfx.h"\
-
-# ADD CPP /Yc"stdafx.h"
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_STDAF=\
- ".\Sources\StdAfx.h"\
-
-# ADD CPP /Yc"stdafx.h"
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\Resources\Application.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\Application.rc
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\Application.rc2
-# PROP Exclude_From_Scan -1
-# PROP BASE Exclude_From_Build 1
-# PROP Exclude_From_Build 1
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\newres.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\Resource.h
-# End Source File
-# End Group
-# Begin Group "Support"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\CommonServices.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DebugServices.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DEBUG=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
-
-NODEP_CPP_DEBUG=\
- "..\..\..\intLib.h"\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DEBUG=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
-
-NODEP_CPP_DEBUG=\
- "..\..\..\intLib.h"\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DEBUG=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
-
-NODEP_CPP_DEBUG=\
- "..\..\..\intLib.h"\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DEBUG=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
-
-NODEP_CPP_DEBUG=\
- "..\..\..\intLib.h"\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DebugServices.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\DNSCommon.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSCO=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSCO=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSCO=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSCO=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\DNSCommon.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\DNSDigest.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSDI=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSDI=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSDI=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSDI=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSD.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSSD=\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
- "..\..\..\RMxClient.h"\
-
-NODEP_CPP_DNSSD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSSD=\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
- "..\..\..\RMxClient.h"\
-
-NODEP_CPP_DNSSD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSSD=\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
- "..\..\..\RMxClient.h"\
-
-NODEP_CPP_DNSSD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSSD=\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
- "..\..\..\RMxClient.h"\
-
-NODEP_CPP_DNSSD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSD.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSDDirect.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSSDD=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
-
-NODEP_CPP_DNSSDD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSSDD=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
-
-NODEP_CPP_DNSSDD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSSDD=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
-
-NODEP_CPP_DNSSDD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSSDD=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\DNSSD.h"\
- "..\..\..\DNSSDDirect.h"\
-
-NODEP_CPP_DNSSDD=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSDDirect.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSServices\DNSServices.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSSE=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\DNSServices\DNSServices.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSSE=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\DNSServices\DNSServices.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSSE=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\DNSServices\DNSServices.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSSE=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\DNSServices\DNSServices.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSServices\DNSServices.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\mDNS.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_MDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_MDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_MDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_MDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\mDNSClientAPI.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\mDNSDebug.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\mDNSWin32.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_MDNSW=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\mDNSWin32.h"\
- {$(INCLUDE)}"ipexport.h"\
- {$(INCLUDE)}"Iphlpapi.h"\
- {$(INCLUDE)}"iptypes.h"\
-
-NODEP_CPP_MDNSW=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_MDNSW=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\mDNSWin32.h"\
- {$(INCLUDE)}"ipexport.h"\
- {$(INCLUDE)}"Iphlpapi.h"\
- {$(INCLUDE)}"iptypes.h"\
-
-NODEP_CPP_MDNSW=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-# ADD CPP /W3
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_MDNSW=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\mDNSWin32.h"\
- {$(INCLUDE)}"ipexport.h"\
- {$(INCLUDE)}"Iphlpapi.h"\
- {$(INCLUDE)}"iptypes.h"\
-
-NODEP_CPP_MDNSW=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_MDNSW=\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\CommonServices.h"\
- "..\..\..\DebugServices.h"\
- "..\..\..\mDNSWin32.h"\
- {$(INCLUDE)}"ipexport.h"\
- {$(INCLUDE)}"Iphlpapi.h"\
- {$(INCLUDE)}"iptypes.h"\
-
-NODEP_CPP_MDNSW=\
- "..\..\..\logLib.h"\
- "..\..\..\vxWorks.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\mDNSWin32.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\uDNS.c
-
-!IF "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_UDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_UDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_UDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ELSEIF "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_UDNS_=\
- "..\..\..\..\mDNSCore\DNSCommon.h"\
- "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
- "..\..\..\..\mDNSCore\mDNSDebug.h"\
- "..\..\..\..\mDNSCore\uDNS.h"\
-
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\uDNS.h
-# End Source File
-# End Group
-# End Target
-# End Project
+++ /dev/null
-Microsoft eMbedded Visual Tools Workspace File, Format Version 4.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "Application"=.\Application.vcp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+++ /dev/null
-//Microsoft eMbedded Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "newres.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 DISCARDABLE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#include ""afxres.h""\r\n"
- "#include ""newres.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE
-BEGIN
- "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
- "#define _AFX_NO_OLE_RESOURCES\r\n"
- "#define _AFX_NO_TRACKER_RESOURCES\r\n"
- "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
- "\r\n"
- "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
- "#ifdef _WIN32\r\n"
- "LANGUAGE 9, 1\r\n"
- "#pragma code_page(1252)\r\n"
- "#endif //_WIN32\r\n"
- "#include ""Resources\\Application.rc2"" // non-Microsoft eMbedded Visual C++ edited resources\r\n"
- "#include ""afxres.rc"" // Standard components\r\n"
- "#include ""wceres.rc"" // WCE-specific components\r\n"
- "#endif\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDR_MAINFRAME ICON DISCARDABLE "Application.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_APPLICATION_DIALOG DIALOG DISCARDABLE 0, 0, 139, 153
-STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION
-EXSTYLE WS_EX_APPWINDOW | 0x80000000L
-CAPTION "DNSServiceBrowser"
-FONT 8, "System"
-BEGIN
- CONTROL "List1",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT |
- LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER |
- WS_BORDER | WS_TABSTOP,7,7,125,141
-END
-
-
-#ifndef _MAC
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "Comments", "\0"
- VALUE "CompanyName", "Apple Computer, Inc.\0"
- VALUE "FileDescription", "DNSServiceBrowser for Windows CE\0"
- VALUE "FileVersion", "1, 0, 0, 1\0"
- VALUE "InternalName", "Application\0"
- VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc.\0"
- VALUE "LegalTrademarks", "\0"
- VALUE "OriginalFilename", "Application.exe\0"
- VALUE "PrivateBuild", "\0"
- VALUE "ProductName", "DNSServiceBrowser for Windows CE\0"
- VALUE "ProductVersion", "1, 0, 0, 1\0"
- VALUE "SpecialBuild", "\0"
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // !_MAC
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO DISCARDABLE
-BEGIN
- IDD_APPLICATION_DIALOG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 132
- TOPMARGIN, 7
- BOTTOMMARGIN, 146
- END
-END
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE DISCARDABLE
-BEGIN
- IDP_SOCKETS_INIT_FAILED "Windows CE sockets initialization failed."
- IDS_BROWSER_LIST_COLUMN_NAME "Name"
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-#define _AFX_NO_SPLITTER_RESOURCES
-#define _AFX_NO_OLE_RESOURCES
-#define _AFX_NO_TRACKER_RESOURCES
-#define _AFX_NO_PROPERTY_RESOURCES
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#endif //_WIN32
-#include "Resources\Application.rc2" // non-Microsoft eMbedded Visual C++ edited resources
-#include "afxres.rc" // Standard components
-#include "wceres.rc" // WCE-specific components
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-//
-// APPLICATION.RC2 - resources Microsoft eMbedded Visual C++ does not edit directly
-//
-
-#ifdef APSTUDIO_INVOKED
- #error this file is not editable by Microsoft eMbedded Visual C++
-#endif //APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-// Add manually edited resources here...
-
-/////////////////////////////////////////////////////////////////////////////
+++ /dev/null
-#ifndef __NEWRES_H__
-#define __NEWRES_H__
-
-#define SHMENUBAR RCDATA
-#if !(defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 300))
- #undef HDS_HORZ
- #undef HDS_BUTTONS
- #undef HDS_HIDDEN
-
- #include <commctrl.h>
- // for MenuBar
- #define I_IMAGENONE (-2)
- #define NOMENU 0xFFFF
- #define IDS_SHNEW 1
- #define IDM_SHAREDNEW 10
- #define IDM_SHAREDNEWDEFAULT 11
-
- // for Tab Control
- #define TCS_SCROLLOPPOSITE 0x0001 // assumes multiline tab
- #define TCS_BOTTOM 0x0002
- #define TCS_RIGHT 0x0002
- #define TCS_VERTICAL 0x0080
- #define TCS_MULTISELECT 0x0004 // allow multi-select in button mode
- #define TCS_FLATBUTTONS 0x0008
-#endif //_WIN32_WCE_PSPC
-
-
-#endif //__NEWRES_H__
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft eMbedded Visual C++ generated include file.
-// Used by Application.rc
-//
-#define IDD_APPLICATION_DIALOG 102
-#define IDP_SOCKETS_INIT_FAILED 103
-#define IDS_BROWSER_LIST_COLUMN_NAME 104
-#define IDR_MAINFRAME 128
-#define IDC_BROWSE_LIST 1000
-#define IDC_IP_TEXT 1003
-#define IDC_TXT_TEXT 1004
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 129
-#define _APS_NEXT_COMMAND_VALUE 32771
-#define _APS_NEXT_CONTROL_VALUE 1005
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stdafx.h"
-
-#include "DNSServices.h"
-
-#include "BrowserDialog.h"
-
-#include "Application.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-// Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(Application, CWinApp)
- //{{AFX_MSG_MAP(Application)
- // NOTE - the ClassWizard will add and remove mapping macros here.
- // DO NOT EDIT what you see in these blocks of generated code!
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-Application gApp;
-
-//===========================================================================================================================
-// Application
-//===========================================================================================================================
-
-Application::Application()
- : CWinApp()
-{
- //
-}
-
-//===========================================================================================================================
-// InitInstance
-//===========================================================================================================================
-
-BOOL Application::InitInstance()
-{
- DNSStatus err;
- BrowserDialog dialog;
- BOOL dnsInitialized;
-
- dnsInitialized = FALSE;
-
- err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
- if( err )
- {
- AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
- goto exit;
- }
- dnsInitialized = TRUE;
-
- // Display the main browser dialog.
-
- m_pMainWnd = &dialog;
- dialog.DoModal();
-
- // Dialog has been closed. Return false to exit the app and not start the app's message pump.
-
-exit:
- if( dnsInitialized )
- {
- DNSServicesFinalize();
- }
- return( FALSE );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_)
-#define AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#ifndef __AFXWIN_H__
- #error include 'stdafx.h' before including this file for PCH
-#endif
-
-#include "Resource.h"
-
-//===========================================================================================================================
-// Application
-//===========================================================================================================================
-
-class Application : public CWinApp
-{
- public:
-
- Application();
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(Application)
- public:
- virtual BOOL InitInstance();
- //}}AFX_VIRTUAL
-
- //{{AFX_MSG(Application)
- // NOTE - the ClassWizard will add and remove member functions here.
- // DO NOT EDIT what you see in these blocks of generated code !
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_)
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stdafx.h"
-
-#include "Application.h"
-
-#include "DNSServices.h"
-
-#include "BrowserDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define WM_USER_SERVICE_ADD ( WM_USER + 0x100 )
-#define WM_USER_SERVICE_REMOVE ( WM_USER + 0x101 )
-
-//===========================================================================================================================
-// Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(BrowserDialog, CDialog)
- //{{AFX_MSG_MAP(BrowserDialog)
- ON_NOTIFY(NM_CLICK, IDC_BROWSE_LIST, OnBrowserListDoubleClick)
- ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
- ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
- //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject );
-
-//===========================================================================================================================
-// BrowserDialog
-//===========================================================================================================================
-
-BrowserDialog::BrowserDialog( CWnd *inParent )
- : CDialog( BrowserDialog::IDD, inParent )
-{
- //{{AFX_DATA_INIT(BrowserDialog)
- // Note: the ClassWizard will add member initialization here
- //}}AFX_DATA_INIT
-
- // Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
-
- mIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
- ASSERT( mIcon );
-}
-
-//===========================================================================================================================
-// DoDataExchange
-//===========================================================================================================================
-
-void BrowserDialog::DoDataExchange( CDataExchange *pDX )
-{
- CDialog::DoDataExchange(pDX);
- //{{AFX_DATA_MAP(BrowserDialog)
- DDX_Control(pDX, IDC_BROWSE_LIST, mBrowserList);
- //}}AFX_DATA_MAP
-}
-
-//===========================================================================================================================
-// OnInitDialog
-//===========================================================================================================================
-
-BOOL BrowserDialog::OnInitDialog()
-{
- CString s;
-
- CDialog::OnInitDialog();
-
- // Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog.
-
- SetIcon( mIcon, TRUE ); // Set big icon
- SetIcon( mIcon, FALSE ); // Set small icon
-
- CenterWindow( GetDesktopWindow() );
-
- // Set up the list.
-
- CRect rect;
-
- s.LoadString( IDS_BROWSER_LIST_COLUMN_NAME );
- mBrowserList.GetWindowRect( rect );
- mBrowserList.InsertColumn( 0, s, LVCFMT_LEFT, rect.Width() - 8 );
-
- // Start browsing for services.
-
- DNSStatus err;
-
- err = DNSBrowserCreate( 0, OnBrowserCallBack, this, &mBrowser );
- if( err )
- {
- AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
- goto exit;
- }
-
- err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, "_http._tcp", NULL );
- if( err )
- {
- AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
- goto exit;
- }
-
-exit:
- return( TRUE );
-}
-
-
-//===========================================================================================================================
-// OnBrowserListDoubleClick
-//===========================================================================================================================
-
-void BrowserDialog::OnBrowserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
-{
- int selectedItem;
-
- (void) pNMHDR; // Unused
-
- selectedItem = mBrowserList.GetNextItem( -1, LVNI_SELECTED );
- if( selectedItem >= 0 )
- {
- BrowserEntry * entry;
- CString temp;
- CString url;
-
- // Build the URL from the IP and optional TXT record.
-
- entry = &mBrowserEntries[ selectedItem ];
- url += "http://" + entry->ip;
- temp = entry->text;
- if( temp.Find( TEXT( "path=" ) ) == 0 )
- {
- temp.Delete( 0, 5 );
- }
- if( temp.Find( '/' ) != 0 )
- {
- url += '/';
- }
- url += temp;
-
- // Let the system open the URL in the correct app.
-
- SHELLEXECUTEINFO info;
-
- info.cbSize = sizeof( info );
- info.fMask = 0;
- info.hwnd = NULL;
- info.lpVerb = NULL;
- info.lpFile = url;
- info.lpParameters = NULL;
- info.lpDirectory = NULL;
- info.nShow = SW_SHOWNORMAL;
- info.hInstApp = NULL;
-
- ShellExecuteEx( &info );
- }
- *pResult = 0;
-}
-
-//===========================================================================================================================
-// OnBrowserCallBack [static]
-//===========================================================================================================================
-
-void
- BrowserDialog::OnBrowserCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent )
-{
- BrowserDialog * dialog;
- BrowserEntry * entry;
- BOOL posted;
-
- DNS_UNUSED( inStatusCode );
- dialog = reinterpret_cast < BrowserDialog * > ( inContext );
- ASSERT( dialog );
-
- switch( inEvent->type )
- {
- case kDNSBrowserEventTypeResolved:
- if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4 )
- {
- char ip[ 64 ];
-
- snprintf( ip, sizeof( ip ), "%u.%u.%u.%u:%u",
- inEvent->data.resolved->address.u.ipv4.addr.v8[ 0 ],
- inEvent->data.resolved->address.u.ipv4.addr.v8[ 1 ],
- inEvent->data.resolved->address.u.ipv4.addr.v8[ 2 ],
- inEvent->data.resolved->address.u.ipv4.addr.v8[ 3 ],
- ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) |
- inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ] );
-
- entry = new BrowserEntry;
- ASSERT( entry );
- if( entry )
- {
- UTF8StringToStringObject( inEvent->data.resolved->name, entry->name );
- UTF8StringToStringObject( ip, entry->ip );
- UTF8StringToStringObject( inEvent->data.resolved->textRecord, entry->text );
-
- posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_ADD, 0, (LPARAM) entry );
- ASSERT( posted );
- if( !posted )
- {
- delete entry;
- }
- }
- }
- break;
-
- case kDNSBrowserEventTypeRemoveService:
- entry = new BrowserEntry;
- ASSERT( entry );
- if( entry )
- {
- UTF8StringToStringObject( inEvent->data.removeService.name, entry->name );
-
- posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_REMOVE, 0, (LPARAM) entry );
- ASSERT( posted );
- if( !posted )
- {
- delete entry;
- }
- }
- break;
-
- default:
- break;
- }
-}
-
-//===========================================================================================================================
-// BrowserAddService
-//===========================================================================================================================
-
-LONG BrowserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
-{
- BrowserEntry * entry;
- INT_PTR lo;
- INT_PTR hi;
- INT_PTR mid;
- int result;
-
- (void) inWParam; // Unused
-
- entry = reinterpret_cast < BrowserEntry * > ( inLParam );
- ASSERT( entry );
-
- result = -1;
- mid = 0;
- lo = 0;
- hi = mBrowserEntries.GetSize() - 1;
- while( lo <= hi )
- {
- mid = ( lo + hi ) / 2;
- result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
- if( result == 0 )
- {
- break;
- }
- else if( result < 0 )
- {
- hi = mid - 1;
- }
- else
- {
- lo = mid + 1;
- }
- }
- if( result == 0 )
- {
- mBrowserEntries[ mid ].ip = entry->ip;
- mBrowserEntries[ mid ].text = entry->text;
- }
- else
- {
- if( result > 0 )
- {
- mid += 1;
- }
- mBrowserEntries.InsertAt( mid, *entry );
- mBrowserList.InsertItem( mid, entry->name );
- }
- delete entry;
- return( 0 );
-}
-
-//===========================================================================================================================
-// OnServiceRemove
-//===========================================================================================================================
-
-LONG BrowserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
-{
- BrowserEntry * entry;
- INT_PTR hi;
- INT_PTR lo;
- INT_PTR mid;
- int result;
-
- (void) inWParam; // Unused
-
- entry = reinterpret_cast < BrowserEntry * > ( inLParam );
- ASSERT( entry );
-
- result = -1;
- mid = 0;
- lo = 0;
- hi = mBrowserEntries.GetSize() - 1;
- while( lo <= hi )
- {
- mid = ( lo + hi ) / 2;
- result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
- if( result == 0 )
- {
- break;
- }
- else if( result < 0 )
- {
- hi = mid - 1;
- }
- else
- {
- lo = mid + 1;
- }
- }
- if( result == 0 )
- {
- mBrowserList.DeleteItem( mid );
- mBrowserEntries.RemoveAt( mid );
- }
- delete entry;
- return( 0 );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// UTF8StringToStringObject
-//===========================================================================================================================
-
-static DWORD UTF8StringToStringObject( const char *inUTF8, CString &inObject )
-{
- DWORD err;
- int n;
- wchar_t * unicode;
-
- unicode = NULL;
-
- n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
- if( n > 0 )
- {
- unicode = (wchar_t *) malloc( (size_t)( n * sizeof( wchar_t ) ) );
- if( !unicode ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; };
-
- n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
- inObject = unicode;
- }
- else
- {
- inObject = "";
- }
- err = 0;
-
-exit:
- if( unicode )
- {
- free( unicode );
- }
- return( err );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_)
-#define AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#include "afxtempl.h"
-#include "Resource.h"
-
-#include "DNSServices.h"
-
-//===========================================================================================================================
-// BrowserDialog
-//===========================================================================================================================
-
-class BrowserDialog : public CDialog
-{
- public:
-
- BrowserDialog( CWnd *inParent = NULL );
-
- //{{AFX_DATA(BrowserDialog)
- enum { IDD = IDD_APPLICATION_DIALOG };
- CListCtrl mBrowserList;
- //}}AFX_DATA
-
- // ClassWizard generated virtual function overrides
- //{{AFX_VIRTUAL(BrowserDialog)
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
- //}}AFX_VIRTUAL
-
- static void
- OnBrowserCallBack(
- void * inContext,
- DNSBrowserRef inRef,
- DNSStatus inStatusCode,
- const DNSBrowserEvent * inEvent );
-
- protected:
-
- struct BrowserEntry
- {
- CString name;
- CString ip;
- CString text;
- };
-
- HICON mIcon;
- DNSBrowserRef mBrowser;
- CArray < BrowserEntry, BrowserEntry > mBrowserEntries;
-
- // Generated message map functions
- //{{AFX_MSG(BrowserDialog)
- virtual BOOL OnInitDialog();
- afx_msg void OnBrowserListDoubleClick(NMHDR* pNMHDR, LRESULT* pResult);
- afx_msg LONG OnServiceAdd( WPARAM inWParam, LPARAM inLParam );
- afx_msg LONG OnServiceRemove( WPARAM inWParam, LPARAM inLParam );
- //}}AFX_MSG
- DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_)
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "stdafx.h"
+++ /dev/null
-/* -*- 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.
- */
-
-#if !defined(AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_)
-#define AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-
-
-#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
-
-#include <afxwin.h> // MFC core and standard components
-#include <afxext.h> // MFC extensions
-
-#if defined(_AFXDLL)
-#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
-#endif
-
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-#include <afxcmn.h> // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-
-#include <winsock2.h>
-//#include <afxsock.h> // MFC socket extensions
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_)
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="Java"\r
- ProjectGUID="{9CE2568A-3170-41C6-9F20-A0188A9EC114}"\r
- Keyword="MakeFileProj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="Debug"\r
- IntermediateDirectory="Debug"\r
- ConfigurationType="0"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- >\r
- <Tool\r
- Name="VCNMakeTool"\r
- BuildCommandLine="nmake /f makefile DEBUG=1"\r
- ReBuildCommandLine="nmake /f makefile DEBUG=1"\r
- CleanCommandLine="nmake /f makefile DEBUG=1 clean"\r
- Output=""\r
- PreprocessorDefinitions=""\r
- IncludeSearchPath=""\r
- ForcedIncludes=""\r
- AssemblySearchPath=""\r
- ForcedUsingAssemblies=""\r
- CompileAsManaged=""\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="0"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- >\r
- <Tool\r
- Name="VCNMakeTool"\r
- BuildCommandLine="nmake /f makefile64 DEBUG=1"\r
- ReBuildCommandLine="nmake /f makefile64 DEBUG=1"\r
- CleanCommandLine="nmake /f makefile64 DEBUG=1 clean"\r
- Output=""\r
- PreprocessorDefinitions=""\r
- IncludeSearchPath=""\r
- ForcedIncludes=""\r
- AssemblySearchPath=""\r
- ForcedUsingAssemblies=""\r
- CompileAsManaged=""\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="Release"\r
- IntermediateDirectory="Release"\r
- ConfigurationType="0"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- >\r
- <Tool\r
- Name="VCNMakeTool"\r
- BuildCommandLine="nmake /f makefile"\r
- ReBuildCommandLine="nmake /f makefile"\r
- CleanCommandLine="nmake /f makefile clean"\r
- Output=""\r
- PreprocessorDefinitions=""\r
- IncludeSearchPath=""\r
- ForcedIncludes=""\r
- AssemblySearchPath=""\r
- ForcedUsingAssemblies=""\r
- CompileAsManaged=""\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="0"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- >\r
- <Tool\r
- Name="VCNMakeTool"\r
- BuildCommandLine="nmake /f makefile64"\r
- ReBuildCommandLine="nmake /f makefile64"\r
- CleanCommandLine="nmake /f makefile64 clean"\r
- Output=""\r
- PreprocessorDefinitions=""\r
- IncludeSearchPath=""\r
- ForcedIncludes=""\r
- AssemblySearchPath=""\r
- ForcedUsingAssemblies=""\r
- CompileAsManaged=""\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{9CE2568A-3170-41C6-9F20-A0188A9EC114}</ProjectGuid>\r
- <Keyword>MakeFileProj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>Makefile</ConfigurationType>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>Makefile</ConfigurationType>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>Makefile</ConfigurationType>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>Makefile</ConfigurationType>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>\r
- <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f makefile DEBUG=1</NMakeBuildCommandLine>\r
- <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f makefile DEBUG=1</NMakeReBuildCommandLine>\r
- <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f makefile DEBUG=1 clean</NMakeCleanCommandLine>\r
- <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />\r
- <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
- <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
- <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
- <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
- <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f makefile64 DEBUG=1</NMakeBuildCommandLine>\r
- <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f makefile64 DEBUG=1</NMakeReBuildCommandLine>\r
- <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f makefile64 DEBUG=1 clean</NMakeCleanCommandLine>\r
- <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />\r
- <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
- <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
- <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
- <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
- <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>\r
- <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f makefile</NMakeBuildCommandLine>\r
- <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f makefile</NMakeReBuildCommandLine>\r
- <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f makefile clean</NMakeCleanCommandLine>\r
- <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />\r
- <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
- <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
- <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
- <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
- <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f makefile64</NMakeBuildCommandLine>\r
- <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f makefile64</NMakeReBuildCommandLine>\r
- <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f makefile64 clean</NMakeCleanCommandLine>\r
- <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />\r
- <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
- <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
- <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
- <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
- <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
- <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
- </ProjectReference>\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 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.
- */
-
-#ifndef JDNS_SD_RC
-#define JDNS_SD_RC
-
-#include "afxres.h"
-#include "../WinVersRes.h"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", MASTER_COMPANY_NAME
- VALUE "FileDescription", MASTER_PROD_NAME " support for Java"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "jdns_sd"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "jdns_sd.dll"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // JDNS_SD_RC
+++ /dev/null
-# -*- 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.
-#
-# This Makefile builds a .jar file and accompanying JNI support library
-# containing the DNSSD implementation for Java and support classes.
-#
-# Prior to building Java support, you must build DNSSD.dll.
-#
-# nmake with no arguments builds all production targets.
-# 'nmake DEBUG=1' to build debugging targets.
-# 'nmake clean' or 'nmake clean DEBUG=1' to delete prod/debug objects & targets
-#
-# To run nmake, you may need to set up your PATH correctly, using a script
-# such as: "\Program Files\Microsoft Visual Studio .NET\Vc7\bin\vcvars32.bat"
-#
-# The default location of the JDK is \javasdk. You can override this on the
-# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
-
-############################################################################
-
-COREDIR = ..\..\mDNSCore
-SHAREDDIR = ..\..\mDNSShared
-
-JDK = "$(JAVA_HOME)"
-
-CC = cl
-RC = rc
-LD = ld
-CP = copy
-RM = del /Q
-RMDIR = rmdir /S /Q
-JAVAC = $(JDK)\bin\javac
-JAVAH = $(JDK)\bin\javah
-JAR = $(JDK)\bin\jar
-CFLAGS_COMMON = -LD -DAUTO_CALLBACKS=0 -I. -I..\.. \
- -I$(COREDIR) -I$(SHAREDDIR) -I$(JDK)\include -I$(JDK)\include\win32
-
-# Set up diverging paths for debug vs. prod builds
-DEBUG=0
-!if $(DEBUG) == 1
-CFLAGS_DEBUG = -Zi -DMDNS_DEBUGMSGS=2
-OBJDIR = objects\debug
-BUILDDIR = build\debug
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\Win32\Debug
-!else
-CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0
-OBJDIR = objects\prod
-BUILDDIR = build\prod
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\Win32\Release
-!endif
-
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
-JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
-
-#############################################################################
-
-all: setup Java postbuild
-
-# 'setup' sets up the build directory structure the way we want
-setup:
- @if not exist objects mkdir objects
- @if not exist build mkdir build
- @if not exist $(OBJDIR) mkdir $(OBJDIR)
- @if not exist $(BUILDDIR) mkdir $(BUILDDIR)
-
-postbuild:
- @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)
- copy $(BUILDDIR)\jdns_sd.dll $(INSTALLDIR)
-
-# clean removes targets and objects
-clean:
- @if exist $(OBJDIR) $(RMDIR) $(OBJDIR)
- @if exist $(BUILDDIR) $(RMDIR) $(BUILDDIR)
-
-#############################################################################
-
-# The following targets build Java wrappers for the dns-sd.h API.
-
-Java: setup $(BUILDDIR)\dns_sd.jar $(BUILDDIR)\jdns_sd.dll postbuild
- @echo "Java wrappers done"
-
-JAVASRC = $(SHAREDDIR)\Java
-JARCONTENTS = $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
- $(OBJDIR)\com\apple\dnssd\DNSSDException.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\DNSSD.class
-
-$(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
- $(JAR) -cf $@ -C $(OBJDIR) com
-
-$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
- $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
- $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES /link /NXCOMPAT /DYNAMICBASE /SAFESEH
-
-.SUFFIXES : .java
-{$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:
- $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
-
-$(OBJDIR)\DNSSD.java.h: $(OBJDIR)\com\apple\dnssd\DNSSD.class
- $(JAVAH) -classpath $(OBJDIR) -o $@ \
- com.apple.dnssd.AppleBrowser \
- com.apple.dnssd.AppleResolver \
- com.apple.dnssd.AppleRegistration \
- com.apple.dnssd.AppleQuery \
- com.apple.dnssd.AppleService
-
-$(OBJDIR)\jdns_sd.RES: jdns_sd.rc
- $(RC) /fo $@ $?
-
+++ /dev/null
-# -*- 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.
-#
-# This Makefile builds a .jar file and accompanying JNI support library
-# containing the DNSSD implementation for Java and support classes.
-#
-# Prior to building Java support, you must build DNSSD.dll.
-#
-# nmake with no arguments builds all production targets.
-# 'nmake DEBUG=1' to build debugging targets.
-# 'nmake clean' or 'nmake clean DEBUG=1' to delete prod/debug objects & targets
-#
-# To run nmake, you may need to set up your PATH correctly, using a script
-# such as: "\Program Files\Microsoft Visual Studio .NET\Vc7\bin\vcvars32.bat"
-#
-# The default location of the JDK is \javasdk. You can override this on the
-# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
-
-############################################################################
-
-COREDIR = ..\..\mDNSCore
-SHAREDDIR = ..\..\mDNSShared
-
-JDK = "$(JAVA_HOME)"
-
-CC = cl
-RC = rc
-LD = ld
-CP = copy
-RM = del /Q
-RMDIR = rmdir /S /Q
-JAVAC = $(JDK)\bin\javac
-JAVAH = $(JDK)\bin\javah
-JAR = $(JDK)\bin\jar
-CFLAGS_COMMON = -LD -DAUTO_CALLBACKS=0 -I. -I..\.. \
- -I$(COREDIR) -I$(SHAREDDIR) -I$(JDK)\include -I$(JDK)\include\win32
-
-# Set up diverging paths for debug vs. prod builds
-DEBUG=0
-!if $(DEBUG) == 1
-CFLAGS_DEBUG = -Zi -DMDNS_DEBUGMSGS=2
-OBJDIR = objects\debug\x64
-BUILDDIR = build\debug\x64
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\x64\Debug
-!else
-CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0
-OBJDIR = objects\prod\x64
-BUILDDIR = build\prod\x64
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\x64\Release
-!endif
-
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
-JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
-
-#############################################################################
-
-all: setup Java postbuild
-
-# 'setup' sets up the build directory structure the way we want
-setup:
- @if not exist objects mkdir objects
- @if not exist build mkdir build
- @if not exist $(OBJDIR) mkdir $(OBJDIR)
- @if not exist $(BUILDDIR) mkdir $(BUILDDIR)
-
-postbuild:
- @if not "%RC_XBS%"=="YES" GOTO CONT
- @if not exist "$(DSTROOT)\WINDOWS\system32\x64" mkdir "$(DSTROOT)\WINDOWS\system32\x64"
- @if not exist "$(DSTROOT)\Program Files\Bonjour\x64" mkdir "$(DSTROOT)\Program Files\Bonjour\x64"
- @copy $(BUILDDIR)\jdns_sd.dll "$(DSTROOT)\WINDOWS\system32\x64"
- @copy $(BUILDDIR)\dns_sd.jar "$(DSTROOT)\Program Files\Bonjour\x64"
- @: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)
- copy $(BUILDDIR)\jdns_sd.dll $(INSTALLDIR)
-
-# clean removes targets and objects
-clean:
- @if exist $(OBJDIR) $(RMDIR) $(OBJDIR)
- @if exist $(BUILDDIR) $(RMDIR) $(BUILDDIR)
-
-#############################################################################
-
-# The following targets build Java wrappers for the dns-sd.h API.
-
-Java: setup $(BUILDDIR)\dns_sd.jar $(BUILDDIR)\jdns_sd.dll postbuild
- @echo "Java wrappers done"
-
-JAVASRC = $(SHAREDDIR)\Java
-JARCONTENTS = $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
- $(OBJDIR)\com\apple\dnssd\DNSSDException.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\DNSSD.class
-
-$(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
- $(JAR) -cf $@ -C $(OBJDIR) com
-
-$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
- $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
- $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES /link /NXCOMPAT /DYNAMICBASE
-
-.SUFFIXES : .java
-{$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:
- $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
-
-$(OBJDIR)\DNSSD.java.h: $(OBJDIR)\com\apple\dnssd\DNSSD.class
- $(JAVAH) -classpath $(OBJDIR) -o $@ \
- com.apple.dnssd.AppleBrowser \
- com.apple.dnssd.AppleResolver \
- com.apple.dnssd.AppleRegistration \
- com.apple.dnssd.AppleQuery \
- com.apple.dnssd.AppleService
-
-$(OBJDIR)\jdns_sd.RES: jdns_sd.rc
- $(RC) /fo $@ $?
-
+++ /dev/null
-/* -*- 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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "CommonServices.h"
-#include "DebugServices.h"
-
-#include <guiddef.h>
-#include <ws2spi.h>
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-int main( int argc, char *argv[] );
-DEBUG_LOCAL void Usage( void );
-DEBUG_LOCAL int ProcessArgs( int argc, char *argv[] );
-DEBUG_LOCAL OSStatus InstallNSP( const char *inName, const char *inGUID, const char *inPath );
-DEBUG_LOCAL OSStatus RemoveNSP( const char *inGUID );
-DEBUG_LOCAL OSStatus EnableNSP( const char *inGUID, BOOL inEnable );
-DEBUG_LOCAL OSStatus ListNameSpaces( void );
-DEBUG_LOCAL OSStatus ReorderNameSpaces( void );
-
-DEBUG_LOCAL WCHAR * CharToWCharString( const char *inCharString, WCHAR *outWCharString );
-DEBUG_LOCAL char * GUIDtoString( const GUID *inGUID, size_t inLen, char *outString );
-DEBUG_LOCAL OSStatus StringToGUID( const char *inCharString, GUID *outGUID );
-
-DEBUG_LOCAL BOOL gToolQuietMode = FALSE;
-
-//===========================================================================================================================
-// main
-//===========================================================================================================================
-
-int main( int argc, char *argv[] )
-{
- OSStatus err;
-
- debug_initialize( kDebugOutputTypeMetaConsole );
- debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
-
- err = ProcessArgs( argc, argv );
- return( (int) err );
-}
-
-//===========================================================================================================================
-// Usage
-//===========================================================================================================================
-
-DEBUG_LOCAL void Usage( void )
-{
- fprintf( stderr, "\n" );
- fprintf( stderr, "NSP Tool 1.0d1\n" );
- fprintf( stderr, " Name Space Provider Tool\n" );
- fprintf( stderr, "\n" );
-
- fprintf( stderr, " -install <name> <guid> <path> - Installs a Name Space Provider\n" );
- fprintf( stderr, "\n" );
- fprintf( stderr, " <name> Name of the NSP\n" );
- fprintf( stderr, " <guid> GUID of the NSP\n" );
- fprintf( stderr, " <path> Path to the NSP file\n" );
- fprintf( stderr, "\n" );
-
- fprintf( stderr, " -remove <guid> - Removes a Name Space Provider\n" );
- fprintf( stderr, "\n" );
- fprintf( stderr, " <guid> GUID of the NSP\n" );
- fprintf( stderr, "\n" );
-
- fprintf( stderr, " -enable/-disable <guid> - Enables or Disables a Name Space Provider\n" );
- fprintf( stderr, "\n" );
- fprintf( stderr, " <guid> GUID of the NSP\n" );
- fprintf( stderr, "\n" );
-
- fprintf( stderr, " -list - Lists Name Space Providers\n" );
- fprintf( stderr, " -reorder - Reorders Name Space Providers\n" );
- fprintf( stderr, " -q - Enable quiet mode\n" );
- fprintf( stderr, " -h[elp] - Help\n" );
- fprintf( stderr, "\n" );
-}
-
-//===========================================================================================================================
-// ProcessArgs
-//===========================================================================================================================
-
-DEBUG_LOCAL int ProcessArgs( int argc, char* argv[] )
-{
- OSStatus err;
- int i;
- const char * name;
- const char * guid;
- const char * path;
-
- if( argc <= 1 )
- {
- Usage();
- err = 0;
- goto exit;
- }
- for( i = 1; i < argc; ++i )
- {
- if( strcmp( argv[ i ], "-install" ) == 0 )
- {
- // Install
-
- if( argc <= ( i + 3 ) )
- {
- fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
- Usage();
- err = kParamErr;
- goto exit;
- }
- name = argv[ ++i ];
- guid = argv[ ++i ];
- path = argv[ ++i ];
-
- if( *name == '\0' )
- {
- name = "DotLocalNSP";
- }
- if( *guid == '\0' )
- {
- guid = "B600E6E9-553B-4a19-8696-335E5C896153";
- }
-
- err = InstallNSP( name, guid, path );
- require_noerr( err, exit );
- }
- else if( strcmp( argv[ i ], "-remove" ) == 0 )
- {
- // Remove
-
- if( argc <= ( i + 1 ) )
- {
- fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
- Usage();
- err = kParamErr;
- goto exit;
- }
- guid = argv[ ++i ];
- if( *guid == '\0' )
- {
- guid = "B600E6E9-553B-4a19-8696-335E5C896153";
- }
-
- err = RemoveNSP( guid );
- require_noerr( err, exit );
- }
- else if( ( strcmp( argv[ i ], "-enable" ) == 0 ) ||
- ( strcmp( argv[ i ], "-disable" ) == 0 ) )
- {
- BOOL enable;
-
- // Enable/Disable
-
- enable = ( strcmp( argv[ i ], "-enable" ) == 0 );
- if( argc <= ( i + 1 ) )
- {
- fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
- Usage();
- err = kParamErr;
- goto exit;
- }
- guid = argv[ ++i ];
-
- err = EnableNSP( guid, enable );
- require_noerr( err, exit );
- }
- else if( strcmp( argv[ i ], "-list" ) == 0 )
- {
- // List
-
- err = ListNameSpaces();
- require_noerr( err, exit );
- }
- else if( strcmp( argv[ i ], "-reorder" ) == 0 )
- {
- // Reorder
-
- err = ReorderNameSpaces();
- require_noerr( err, exit );
- }
- else if( strcmp( argv[ i ], "-q" ) == 0 )
- {
- gToolQuietMode = TRUE;
- }
- else if( ( strcmp( argv[ i ], "-help" ) == 0 ) ||
- ( strcmp( argv[ i ], "-h" ) == 0 ) )
- {
- // Help
-
- Usage();
- err = 0;
- goto exit;
- }
- else
- {
- fprintf( stderr, "\n### ERROR: unknown argment: \"%s\"\n\n", argv[ i ] );
- Usage();
- err = kParamErr;
- goto exit;
- }
- }
- err = kNoErr;
-
-exit:
- return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// InstallNSP
-//===========================================================================================================================
-
-OSStatus InstallNSP( const char *inName, const char *inGUID, const char *inPath )
-{
- OSStatus err;
- size_t size;
- WSADATA wsd;
- WCHAR name[ 256 ];
- GUID guid;
- WCHAR path[ MAX_PATH ];
-
- require_action( inName && ( *inName != '\0' ), exit, err = kParamErr );
- require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
- require_action( inPath && ( *inPath != '\0' ), exit, err = kParamErr );
-
- size = strlen( inName );
- require_action( size < sizeof_array( name ), exit, err = kSizeErr );
- CharToWCharString( inName, name );
-
- err = StringToGUID( inGUID, &guid );
- require_noerr( err, exit );
-
- size = strlen( inPath );
- require_action( size < sizeof_array( path ), exit, err = kSizeErr );
- CharToWCharString( inPath, path );
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- err = WSCInstallNameSpace( name, path, NS_DNS, 1, &guid );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- WSACleanup();
- require_noerr( err, exit );
-
- if (!gToolQuietMode)
- {
- fprintf( stderr, "Installed NSP \"%s\" (%s) at %s\n", inName, inGUID, inPath );
- }
-
-exit:
- if( err != kNoErr )
- {
- fprintf( stderr, "### FAILED (%d) to install \"%s\" (%s) Name Space Provider at %s\n", err, inName, inGUID, inPath );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// RemoveNSP
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus RemoveNSP( const char *inGUID )
-{
- OSStatus err;
- WSADATA wsd;
- GUID guid;
-
- require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
-
- err = StringToGUID( inGUID, &guid );
- require_noerr( err, exit );
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- err = WSCUnInstallNameSpace( &guid );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- WSACleanup();
- require_noerr( err, exit );
-
- if (!gToolQuietMode)
- {
- fprintf( stderr, "Removed NSP %s\n", inGUID );
- }
-
-exit:
- if( err != kNoErr )
- {
- fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// EnableNSP
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus EnableNSP( const char *inGUID, BOOL inEnable )
-{
- OSStatus err;
- WSADATA wsd;
- GUID guid;
-
- require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
-
- err = StringToGUID( inGUID, &guid );
- require_noerr( err, exit );
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- err = WSCEnableNSProvider( &guid, inEnable );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- WSACleanup();
- require_noerr( err, exit );
-
- if (!gToolQuietMode)
- {
- fprintf( stderr, "Removed NSP %s\n", inGUID );
- }
-
-exit:
- if( err != kNoErr )
- {
- fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// ListNameSpaces
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus ListNameSpaces( void )
-{
- OSStatus err;
- WSADATA wsd;
- bool started;
- int n;
- int i;
- DWORD size;
- WSANAMESPACE_INFO * array;
- char s[ 256 ];
-
- array = NULL;
- started = false;
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
- started = true;
-
- // Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
-
- size = 0;
- n = WSAEnumNameSpaceProviders( &size, NULL );
- err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
- require_action( err == WSAEFAULT, exit, err = kUnknownErr );
-
- array = (WSANAMESPACE_INFO *) malloc( size );
- require_action( array, exit, err = kNoMemoryErr );
-
- n = WSAEnumNameSpaceProviders( &size, array );
- err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- fprintf( stdout, "\n" );
- for( i = 0; i < n; ++i )
- {
- fprintf( stdout, "Name Space %d\n", i + 1 );
- fprintf( stdout, " NSProviderId: %s\n", GUIDtoString( &array[ i ].NSProviderId, sizeof( s ), s ) );
- fprintf( stdout, " dwNameSpace: %d\n", array[ i ].dwNameSpace );
- fprintf( stdout, " fActive: %s\n", array[ i ].fActive ? "YES" : "NO" );
- fprintf( stdout, " dwVersion: %d\n", array[ i ].dwVersion );
- fprintf( stdout, " lpszIdentifier: \"%s\"\n", array[ i ].lpszIdentifier );
- fprintf( stdout, "\n" );
- }
- err = kNoErr;
-
-exit:
- if( array )
- {
- free( array );
- }
- if( started )
- {
- WSACleanup();
- }
- if( err != kNoErr )
- {
- fprintf( stderr, "### FAILED (%d) to list Name Space Providers\n", err );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// ReorderNameSpaces
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus ReorderNameSpaces( void )
-{
- OSStatus err;
- WSADATA wsd;
- bool started;
- int n;
- int i;
- DWORD size;
- WSANAMESPACE_INFO * array;
- WCHAR name[ 256 ];
- WCHAR path[ MAX_PATH ];
-
- array = NULL;
- started = false;
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
- started = true;
-
- // Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
-
- size = 0;
- n = WSAEnumNameSpaceProviders( &size, NULL );
- err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
- require_action( err == WSAEFAULT, exit, err = kUnknownErr );
-
- array = (WSANAMESPACE_INFO *) malloc( size );
- require_action( array, exit, err = kNoMemoryErr );
-
- n = WSAEnumNameSpaceProviders( &size, array );
- err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- // Find the "Tcpip" NSP.
-
- for( i = 0; i < n; ++i )
- {
- if( strcmp( array[ i ].lpszIdentifier, "Tcpip" ) == 0 )
- {
- break;
- }
- }
- require_action( i < n, exit, err = kNotFoundErr );
-
- // Uninstall it then re-install it to move it to the end.
-
- size = (DWORD) strlen( array[ i ].lpszIdentifier );
- require_action( size < sizeof_array( name ), exit, err = kSizeErr );
- CharToWCharString( array[ i ].lpszIdentifier, name );
-
- size = (DWORD) strlen( "%SystemRoot%\\System32\\mswsock.dll" );
- require_action( size < sizeof_array( path ), exit, err = kSizeErr );
- CharToWCharString( "%SystemRoot%\\System32\\mswsock.dll", path );
-
- err = WSCUnInstallNameSpace( &array[ i ].NSProviderId );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- err = WSCInstallNameSpace( name, path, NS_DNS, array[ i ].dwVersion, &array[ i ].NSProviderId );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- // Success!
-
- fprintf( stderr, "Reordered \"Tcpip\" NSP to to the bottom of the NSP chain\n" );
- err = kNoErr;
-
-exit:
- if( array )
- {
- free( array );
- }
- if( started )
- {
- WSACleanup();
- }
- if( err != kNoErr )
- {
- fprintf( stderr, "### FAILED (%d) to reorder Name Space Providers\n", err );
- }
- return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// CharToWCharString
-//===========================================================================================================================
-
-DEBUG_LOCAL WCHAR * CharToWCharString( const char *inCharString, WCHAR *outWCharString )
-{
- const char * src;
- WCHAR * dst;
- char c;
-
- check( inCharString );
- check( outWCharString );
-
- src = inCharString;
- dst = outWCharString;
- do
- {
- c = *src++;
- *dst++ = (WCHAR) c;
-
- } while( c != '\0' );
-
- return( outWCharString );
-}
-
-//===========================================================================================================================
-// GUIDtoString
-//===========================================================================================================================
-
-DEBUG_LOCAL char * GUIDtoString( const GUID *inGUID, size_t inLen, char *outString )
-{
- check( inGUID );
- check( outString );
-
- _snprintf( outString, inLen, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- inGUID->Data1, inGUID->Data2, inGUID->Data3,
- inGUID->Data4[ 0 ], inGUID->Data4[ 1 ], inGUID->Data4[ 2 ], inGUID->Data4[ 3 ],
- inGUID->Data4[ 4 ], inGUID->Data4[ 5 ], inGUID->Data4[ 6 ], inGUID->Data4[ 7 ] );
- return( outString );
-}
-
-//===========================================================================================================================
-// StringToGUID
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus StringToGUID( const char *inCharString, GUID *outGUID )
-{
- OSStatus err;
- int n;
- unsigned int v[ 8 ];
-
- check( inCharString );
- check( outGUID );
-
- n = sscanf( inCharString, "%lX-%hX-%hX-%02X%02X-%02X%02X%02X%02X%02X%02X",
- &outGUID->Data1, &outGUID->Data2, &outGUID->Data3,
- &v[ 0 ], &v[ 1 ], &v[ 2 ], &v[ 3 ], &v[ 4 ], &v[ 5 ], &v[ 6 ], &v[ 7 ] );
- require_action( n == 11, exit, err = kFormatErr );
-
- outGUID->Data4[ 0 ] = (unsigned char) v[ 0 ];
- outGUID->Data4[ 1 ] = (unsigned char) v[ 1 ];
- outGUID->Data4[ 2 ] = (unsigned char) v[ 2 ];
- outGUID->Data4[ 3 ] = (unsigned char) v[ 3 ];
- outGUID->Data4[ 4 ] = (unsigned char) v[ 4 ];
- outGUID->Data4[ 5 ] = (unsigned char) v[ 5 ];
- outGUID->Data4[ 6 ] = (unsigned char) v[ 6 ];
- outGUID->Data4[ 7 ] = (unsigned char) v[ 7 ];
- err = kNoErr;
-
-exit:
- return( err );
-}
+++ /dev/null
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
- "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
- "#include ""afxres.h""\r\n"\r
- "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
- "\r\n"\r
- "\0"\r
-END\r
-\r
-#endif // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x17L\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x1L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
- BLOCK "StringFileInfo"\r
- BEGIN\r
- BLOCK "040904b0"\r
- BEGIN\r
- VALUE "CompanyName", MASTER_COMPANY_NAME\r
- VALUE "FileDescription", "NSPTool Application"\r
- VALUE "FileVersion", MASTER_PROD_VERS_STR\r
- VALUE "InternalName", "NSPTool"\r
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
- VALUE "OriginalFilename", "NSPTool.exe"\r
- VALUE "ProductName", MASTER_PROD_NAME\r
- VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
- END\r
- END\r
- BLOCK "VarFileInfo"\r
- BEGIN\r
- VALUE "Translation", 0x409, 1200\r
- END\r
-END\r
-\r
-#endif // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif // not APSTUDIO_INVOKED\r
-\r
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="NSPTool"\r
- ProjectGUID="{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}"\r
- Keyword="Win32Proj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- EnableFunctionLevelLinking="false"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="4"\r
- CallingConvention="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="..\"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/NSPTool.exe"\r
- LinkIncremental="2"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/NSPTool.pdb"\r
- SubSystem="1"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- EnableFunctionLevelLinking="false"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="0"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="..\"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/NSPTool.exe"\r
- LinkIncremental="2"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/NSPTool.pdb"\r
- SubSystem="1"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="..\"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/NSPTool.exe"\r
- LinkIncremental="1"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
- SubSystem="1"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="..\"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
- OutputFile="$(OutDir)/NSPTool.exe"\r
- LinkIncremental="1"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
- SubSystem="1"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\NSPTool.c"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\resource.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- <File\r
- RelativePath=".\NSPTool.rc"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}</ProjectGuid>\r
- <Keyword>Win32Proj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <FunctionLevelLinking>false</FunctionLevelLinking>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r
- <CallingConvention>Cdecl</CallingConvention>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)NSPTool.pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <FunctionLevelLinking>false</FunctionLevelLinking>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>Cdecl</CallingConvention>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)NSPTool.pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
- <ClCompile Include="NSPTool.c" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
- <ClInclude Include="resource.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="NSPTool.rc" />\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
- <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="NSPTool.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="resource.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="NSPTool.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef __PREFIX__
-#define __PREFIX__
-
-#if( defined( _DEBUG ) )
- #define DEBUG 1
- #define MDNS_DEBUGMSGS 1
-#else
- #define DEBUG 0
-#endif
-
-#endif // __PREFIX__
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by NSPTool.rc
-//
-#define IDS_PROJNAME 100
-#define IDR_WMDMLOGGER 101
-#define IDS_LOG_SEV_INFO 201
-#define IDS_LOG_SEV_WARN 202
-#define IDS_LOG_SEV_ERROR 203
-#define IDS_LOG_DATETIME 204
-#define IDS_LOG_SRCNAME 205
-#define IDS_DEF_LOGFILE 301
-#define IDS_DEF_MAXSIZE 302
-#define IDS_DEF_SHRINKTOSIZE 303
-#define IDS_DEF_LOGENABLED 304
-#define IDS_MUTEX_TIMEOUT 401
-
-// 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 101
-#endif
-#endif
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Poll.h"
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-#include <process.h>
-#include "GenLinkedList.h"
-#include "DebugServices.h"
-
-
-typedef struct PollSource_struct
-{
- SOCKET socket;
- HANDLE handle;
- void *context;
-
- union
- {
- mDNSPollSocketCallback socket;
- mDNSPollEventCallback event;
- } callback;
-
- struct Worker_struct *worker;
- struct PollSource_struct *next;
-
-} PollSource;
-
-
-typedef struct Worker_struct
-{
- HANDLE thread; // NULL for main worker
- unsigned id; // 0 for main worker
-
- HANDLE start; // NULL for main worker
- HANDLE stop; // NULL for main worker
- BOOL done; // Not used for main worker
-
- DWORD numSources;
- PollSource *sources[ MAXIMUM_WAIT_OBJECTS ];
- HANDLE handles[ MAXIMUM_WAIT_OBJECTS ];
- DWORD result;
- struct Worker_struct *next;
-} Worker;
-
-
-typedef struct Poll_struct
-{
- mDNSBool setup;
- HANDLE wakeup;
- GenLinkedList sources;
- DWORD numSources;
- Worker main;
- GenLinkedList workers;
- HANDLE workerHandles[ MAXIMUM_WAIT_OBJECTS ];
- DWORD numWorkers;
-
-} Poll;
-
-
-/*
- * Poll Methods
- */
-
-mDNSlocal mStatus PollSetup();
-mDNSlocal mStatus PollRegisterSource( PollSource *source );
-mDNSlocal void PollUnregisterSource( PollSource *source );
-mDNSlocal mStatus PollStartWorkers();
-mDNSlocal mStatus PollStopWorkers();
-mDNSlocal void PollRemoveWorker( Worker *worker );
-
-
-/*
- * Worker Methods
- */
-
-mDNSlocal mStatus WorkerInit( Worker *worker );
-mDNSlocal void WorkerFree( Worker *worker );
-mDNSlocal void WorkerRegisterSource( Worker *worker, PollSource *source );
-mDNSlocal int WorkerSourceToIndex( Worker *worker, PollSource *source );
-mDNSlocal void WorkerUnregisterSource( Worker *worker, PollSource *source );
-mDNSlocal void WorkerDispatch( Worker *worker);
-mDNSlocal void CALLBACK WorkerWakeupNotification( HANDLE event, void *context );
-mDNSlocal unsigned WINAPI WorkerMain( LPVOID inParam );
-
-
-static void
-ShiftDown( void * arr, size_t arraySize, size_t itemSize, int index )
-{
- memmove( ( ( unsigned char* ) arr ) + ( ( index - 1 ) * itemSize ), ( ( unsigned char* ) arr ) + ( index * itemSize ), ( arraySize - index ) * itemSize );
-}
-
-
-#define DEBUG_NAME "[mDNSWin32] "
-#define gMDNSRecord mDNSStorage
-mDNSlocal Poll gPoll = { mDNSfalse, NULL };
-
-#define LogErr( err, FUNC ) LogMsg( "%s:%d - %s failed: %d\n", __FUNCTION__, __LINE__, FUNC, err );
-
-
-mStatus
-mDNSPollRegisterSocket( SOCKET socket, int networkEvents, mDNSPollSocketCallback callback, void *context )
-{
- PollSource *source = NULL;
- HANDLE event = INVALID_HANDLE_VALUE;
- mStatus err = mStatus_NoError;
-
- if ( !gPoll.setup )
- {
- err = PollSetup();
- require_noerr( err, exit );
- }
-
- source = malloc( sizeof( PollSource ) );
- require_action( source, exit, err = mStatus_NoMemoryErr );
-
- event = WSACreateEvent();
- require_action( event, exit, err = mStatus_NoMemoryErr );
-
- err = WSAEventSelect( socket, event, networkEvents );
- require_noerr( err, exit );
-
- source->socket = socket;
- source->handle = event;
- source->callback.socket = callback;
- source->context = context;
-
- err = PollRegisterSource( source );
- require_noerr( err, exit );
-
-exit:
-
- if ( err != mStatus_NoError )
- {
- if ( event != INVALID_HANDLE_VALUE )
- {
- WSACloseEvent( event );
- }
-
- if ( source != NULL )
- {
- free( source );
- }
- }
-
- return err;
-}
-
-
-void
-mDNSPollUnregisterSocket( SOCKET socket )
-{
- PollSource *source;
-
- for ( source = gPoll.sources.Head; source; source = source->next )
- {
- if ( source->socket == socket )
- {
- break;
- }
- }
-
- if ( source )
- {
- WSACloseEvent( source->handle );
- PollUnregisterSource( source );
- free( source );
- }
-}
-
-
-mStatus
-mDNSPollRegisterEvent( HANDLE event, mDNSPollEventCallback callback, void *context )
-{
- PollSource *source = NULL;
- mStatus err = mStatus_NoError;
-
- if ( !gPoll.setup )
- {
- err = PollSetup();
- require_noerr( err, exit );
- }
-
- source = malloc( sizeof( PollSource ) );
- require_action( source, exit, err = mStatus_NoMemoryErr );
-
- source->socket = INVALID_SOCKET;
- source->handle = event;
- source->callback.event = callback;
- source->context = context;
-
- err = PollRegisterSource( source );
- require_noerr( err, exit );
-
-exit:
-
- if ( err != mStatus_NoError )
- {
- if ( source != NULL )
- {
- free( source );
- }
- }
-
- return err;
-}
-
-
-void
-mDNSPollUnregisterEvent( HANDLE event )
-{
- PollSource *source;
-
- for ( source = gPoll.sources.Head; source; source = source->next )
- {
- if ( source->handle == event )
- {
- break;
- }
- }
-
- if ( source )
- {
- PollUnregisterSource( source );
- free( source );
- }
-}
-
-
-mStatus
-mDNSPoll( DWORD msec )
-{
- mStatus err = mStatus_NoError;
-
- if ( gPoll.numWorkers > 0 )
- {
- err = PollStartWorkers();
- require_noerr( err, exit );
- }
-
- gPoll.main.result = WaitForMultipleObjects( gPoll.main.numSources, gPoll.main.handles, FALSE, msec );
- err = translate_errno( ( gPoll.main.result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "WaitForMultipleObjects()" );
- require_action( gPoll.main.result != WAIT_FAILED, exit, err = ( mStatus ) GetLastError() );
-
- if ( gPoll.numWorkers > 0 )
- {
- err = PollStopWorkers();
- require_noerr( err, exit );
- }
-
- WorkerDispatch( &gPoll.main );
-
-exit:
-
- return ( err );
-}
-
-
-mDNSlocal mStatus
-PollSetup()
-{
- mStatus err = mStatus_NoError;
-
- if ( !gPoll.setup )
- {
- memset( &gPoll, 0, sizeof( gPoll ) );
-
- InitLinkedList( &gPoll.sources, offsetof( PollSource, next ) );
- InitLinkedList( &gPoll.workers, offsetof( Worker, next ) );
-
- gPoll.wakeup = CreateEvent( NULL, TRUE, FALSE, NULL );
- require_action( gPoll.wakeup, exit, err = mStatus_NoMemoryErr );
-
- err = WorkerInit( &gPoll.main );
- require_noerr( err, exit );
-
- gPoll.setup = mDNStrue;
- }
-
-exit:
-
- return err;
-}
-
-
-mDNSlocal mStatus
-PollRegisterSource( PollSource *source )
-{
- Worker *worker = NULL;
- mStatus err = mStatus_NoError;
-
- AddToTail( &gPoll.sources, source );
- gPoll.numSources++;
-
- // First check our main worker. In most cases, we won't have to worry about threads
-
- if ( gPoll.main.numSources < MAXIMUM_WAIT_OBJECTS )
- {
- WorkerRegisterSource( &gPoll.main, source );
- }
- else
- {
- // Try to find a thread to use that we've already created
-
- for ( worker = gPoll.workers.Head; worker; worker = worker->next )
- {
- if ( worker->numSources < MAXIMUM_WAIT_OBJECTS )
- {
- WorkerRegisterSource( worker, source );
- break;
- }
- }
-
- // If not, then create a worker and make a thread to run it in
-
- if ( !worker )
- {
- worker = ( Worker* ) malloc( sizeof( Worker ) );
- require_action( worker, exit, err = mStatus_NoMemoryErr );
-
- memset( worker, 0, sizeof( Worker ) );
-
- worker->start = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( worker->start, exit, err = mStatus_NoMemoryErr );
-
- worker->stop = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( worker->stop, exit, err = mStatus_NoMemoryErr );
-
- err = WorkerInit( worker );
- require_noerr( err, exit );
-
- // Create thread with _beginthreadex() instead of CreateThread() to avoid
- // memory leaks when using static run-time libraries.
- // See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
-
- worker->thread = ( HANDLE ) _beginthreadex_compat( NULL, 0, WorkerMain, worker, 0, &worker->id );
- err = translate_errno( worker->thread, ( mStatus ) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- AddToTail( &gPoll.workers, worker );
- gPoll.workerHandles[ gPoll.numWorkers++ ] = worker->stop;
-
- WorkerRegisterSource( worker, source );
- }
- }
-
-exit:
-
- if ( err && worker )
- {
- WorkerFree( worker );
- }
-
- return err;
-}
-
-
-mDNSlocal void
-PollUnregisterSource( PollSource *source )
-{
- RemoveFromList( &gPoll.sources, source );
- gPoll.numSources--;
-
- WorkerUnregisterSource( source->worker, source );
-}
-
-
-mDNSlocal mStatus
-PollStartWorkers()
-{
- Worker *worker;
- mStatus err = mStatus_NoError;
- BOOL ok;
-
- dlog( kDebugLevelChatty, DEBUG_NAME "starting workers\n" );
-
- worker = gPoll.workers.Head;
-
- while ( worker )
- {
- Worker *next = worker->next;
-
- if ( worker->numSources == 1 )
- {
- PollRemoveWorker( worker );
- }
- else
- {
- dlog( kDebugLevelChatty, DEBUG_NAME "waking up worker\n" );
-
- ok = SetEvent( worker->start );
- err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "SetEvent()" );
-
- if ( err )
- {
- PollRemoveWorker( worker );
- }
- }
-
- worker = next;
- }
-
- err = mStatus_NoError;
-
- return err;
-}
-
-
-mDNSlocal mStatus
-PollStopWorkers()
-{
- DWORD result;
- Worker *worker;
- BOOL ok;
- mStatus err = mStatus_NoError;
-
- dlog( kDebugLevelChatty, DEBUG_NAME "stopping workers\n" );
-
- ok = SetEvent( gPoll.wakeup );
- err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "SetEvent()" );
-
- // Wait For 5 seconds for all the workers to wake up
-
- result = WaitForMultipleObjects( gPoll.numWorkers, gPoll.workerHandles, TRUE, 5000 );
- err = translate_errno( ( result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "WaitForMultipleObjects()" );
-
- ok = ResetEvent( gPoll.wakeup );
- err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "ResetEvent()" );
-
- for ( worker = gPoll.workers.Head; worker; worker = worker->next )
- {
- WorkerDispatch( worker );
- }
-
- err = mStatus_NoError;
-
- return err;
-}
-
-
-mDNSlocal void
-PollRemoveWorker( Worker *worker )
-{
- DWORD result;
- mStatus err;
- BOOL ok;
- DWORD i;
-
- dlog( kDebugLevelChatty, DEBUG_NAME "removing worker %d\n", worker->id );
-
- RemoveFromList( &gPoll.workers, worker );
-
- // Remove handle from gPoll.workerHandles
-
- for ( i = 0; i < gPoll.numWorkers; i++ )
- {
- if ( gPoll.workerHandles[ i ] == worker->stop )
- {
- ShiftDown( gPoll.workerHandles, gPoll.numWorkers, sizeof( gPoll.workerHandles[ 0 ] ), i + 1 );
- break;
- }
- }
-
- worker->done = TRUE;
- gPoll.numWorkers--;
-
- // Cause the thread to exit.
-
- ok = SetEvent( worker->start );
- err = translate_errno( ok, ( OSStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "SetEvent()" );
-
- result = WaitForSingleObject( worker->thread, 5000 );
- err = translate_errno( result != WAIT_FAILED, ( OSStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "WaitForSingleObject()" );
-
- if ( ( result == WAIT_FAILED ) || ( result == WAIT_TIMEOUT ) )
- {
- ok = TerminateThread( worker->thread, 0 );
- err = translate_errno( ok, ( OSStatus ) GetLastError(), kUnknownErr );
- if ( err ) LogErr( err, "TerminateThread()" );
- }
-
- CloseHandle( worker->thread );
- worker->thread = NULL;
-
- WorkerFree( worker );
-}
-
-
-mDNSlocal void
-WorkerRegisterSource( Worker *worker, PollSource *source )
-{
- source->worker = worker;
- worker->sources[ worker->numSources ] = source;
- worker->handles[ worker->numSources ] = source->handle;
- worker->numSources++;
-}
-
-
-mDNSlocal int
-WorkerSourceToIndex( Worker *worker, PollSource *source )
-{
- int index;
-
- for ( index = 0; index < ( int ) worker->numSources; index++ )
- {
- if ( worker->sources[ index ] == source )
- {
- break;
- }
- }
-
- if ( index == ( int ) worker->numSources )
- {
- index = -1;
- }
-
- return index;
-}
-
-
-mDNSlocal void
-WorkerUnregisterSource( Worker *worker, PollSource *source )
-{
- int sourceIndex = WorkerSourceToIndex( worker, source );
- DWORD delta;
-
- if ( sourceIndex == -1 )
- {
- LogMsg( "WorkerUnregisterSource: source not found in list" );
- goto exit;
- }
-
- delta = ( worker->numSources - sourceIndex - 1 );
-
- // If this source is not at the end of the list, then move memory
-
- if ( delta > 0 )
- {
- ShiftDown( worker->sources, worker->numSources, sizeof( worker->sources[ 0 ] ), sourceIndex + 1 );
- ShiftDown( worker->handles, worker->numSources, sizeof( worker->handles[ 0 ] ), sourceIndex + 1 );
- }
-
- worker->numSources--;
-
-exit:
-
- return;
-}
-
-
-mDNSlocal void CALLBACK
-WorkerWakeupNotification( HANDLE event, void *context )
-{
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- dlog( kDebugLevelChatty, DEBUG_NAME "Worker thread wakeup\n" );
-}
-
-
-mDNSlocal void
-WorkerDispatch( Worker *worker )
-{
- if ( worker->result == WAIT_FAILED )
- {
- /* What should we do here? */
- }
- else if ( worker->result == WAIT_TIMEOUT )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME "timeout\n" );
- }
- else
- {
- DWORD waitItemIndex = ( DWORD )( ( ( int ) worker->result ) - WAIT_OBJECT_0 );
- PollSource *source = NULL;
-
- // Sanity check
-
- if ( waitItemIndex >= worker->numSources )
- {
- LogMsg( "WorkerDispatch: waitItemIndex (%d) is >= numSources (%d)", waitItemIndex, worker->numSources );
- goto exit;
- }
-
- source = worker->sources[ waitItemIndex ];
-
- if ( source->socket != INVALID_SOCKET )
- {
- WSANETWORKEVENTS event;
-
- if ( WSAEnumNetworkEvents( source->socket, source->handle, &event ) == 0 )
- {
- source->callback.socket( source->socket, &event, source->context );
- }
- else
- {
- source->callback.socket( source->socket, NULL, source->context );
- }
- }
- else
- {
- source->callback.event( source->handle, source->context );
- }
- }
-
-exit:
-
- return;
-}
-
-
-mDNSlocal mStatus
-WorkerInit( Worker *worker )
-{
- PollSource *source = NULL;
- mStatus err = mStatus_NoError;
-
- require_action( worker, exit, err = mStatus_BadParamErr );
-
- source = malloc( sizeof( PollSource ) );
- require_action( source, exit, err = mStatus_NoMemoryErr );
-
- source->socket = INVALID_SOCKET;
- source->handle = gPoll.wakeup;
- source->callback.event = WorkerWakeupNotification;
- source->context = NULL;
-
- WorkerRegisterSource( worker, source );
-
-exit:
-
- return err;
-}
-
-
-mDNSlocal void
-WorkerFree( Worker *worker )
-{
- if ( worker->start )
- {
- CloseHandle( worker->start );
- worker->start = NULL;
- }
-
- if ( worker->stop )
- {
- CloseHandle( worker->stop );
- worker->stop = NULL;
- }
-
- free( worker );
-}
-
-
-mDNSlocal unsigned WINAPI
-WorkerMain( LPVOID inParam )
-{
- Worker *worker = ( Worker* ) inParam;
- mStatus err = mStatus_NoError;
-
- require_action( worker, exit, err = mStatus_BadParamErr );
-
- dlog( kDebugLevelVerbose, DEBUG_NAME, "entering WorkerMain()\n" );
-
- while ( TRUE )
- {
- DWORD result;
- BOOL ok;
-
- dlog( kDebugLevelChatty, DEBUG_NAME, "worker thread %d will wait on main loop\n", worker->id );
-
- result = WaitForSingleObject( worker->start, INFINITE );
- err = translate_errno( ( result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) { LogErr( err, "WaitForSingleObject()" ); break; }
- if ( worker->done ) break;
-
- dlog( kDebugLevelChatty, DEBUG_NAME "worker thread %d will wait on sockets\n", worker->id );
-
- worker->result = WaitForMultipleObjects( worker->numSources, worker->handles, FALSE, INFINITE );
- err = translate_errno( ( worker->result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) { LogErr( err, "WaitForMultipleObjects()" ); break; }
-
- dlog( kDebugLevelChatty, DEBUG_NAME "worker thread %d did wait on sockets: %d\n", worker->id, worker->result );
-
- ok = SetEvent( gPoll.wakeup );
- err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) { LogErr( err, "SetEvent()" ); break; }
-
- dlog( kDebugLevelChatty, DEBUG_NAME, "worker thread %d preparing to sleep\n", worker->id );
-
- ok = SetEvent( worker->stop );
- err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
- if ( err ) { LogErr( err, "SetEvent()" ); break; }
- }
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "exiting WorkerMain()\n" );
-
-exit:
-
- return 0;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef _Poll_h
-#define _Poll_h
-
-#include "CommonServices.h"
-#include <mswsock.h>
-#include "mDNSEmbeddedAPI.h"
-#include "uDNS.h"
-
-
-#if defined(__cplusplus )
-extern "C" {
-#endif
-
-
-typedef void ( CALLBACK *mDNSPollSocketCallback )( SOCKET socket, LPWSANETWORKEVENTS event, void *context );
-typedef void ( CALLBACK *mDNSPollEventCallback )( HANDLE event, void *context );
-
-
-extern mStatus
-mDNSPollRegisterSocket( SOCKET socket, int networkEvents, mDNSPollSocketCallback callback, void *context );
-
-
-extern void
-mDNSPollUnregisterSocket( SOCKET socket );
-
-
-extern mStatus
-mDNSPollRegisterEvent( HANDLE event, mDNSPollEventCallback callback, void *context );
-
-
-extern void
-mDNSPollUnregisterEvent( HANDLE event );
-
-
-extern mStatus
-mDNSPoll( DWORD msec );
-
-
-#if defined(__cplusplus)
-}
-#endif
-
-
-#endif
+++ /dev/null
-/* -*- 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.
- */
-
-#include "PosixCompat.h"
-#include <DebugServices.h>
-
-
-typedef PCHAR (WINAPI * if_indextoname_funcptr_t)(ULONG index, PCHAR name);
-typedef ULONG (WINAPI * if_nametoindex_funcptr_t)(PCSTR name);
-
-
-unsigned
-if_nametoindex( const char * ifname )
-{
- HMODULE library;
- unsigned index = 0;
-
- check( ifname );
-
- // 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( unsigned ifindex, char * ifname )
-{
- HMODULE library;
- char * name = NULL;
-
- check( ifname );
- *ifname = '\0';
-
- // 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;
-}
-
-
-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( ( LPSTR ) addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
- {
- if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
- else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
- else return 0;
- }
- else return 0;
-}
-
-
-int
-gettimeofday( struct timeval * tv, struct timezone * tz )
-{
-#define EPOCHFILETIME (116444736000000000i64)
-
- if ( tv != NULL )
- {
- FILETIME ft;
- LARGE_INTEGER li;
- __int64 t;
-
- GetSystemTimeAsFileTime(&ft);
- li.LowPart = ft.dwLowDateTime;
- li.HighPart = ft.dwHighDateTime;
- t = li.QuadPart; /* In 100-nanosecond intervals */
- t -= EPOCHFILETIME; /* Offset to the Epoch time */
- t /= 10; /* In microseconds */
- tv->tv_sec = ( long )( t / 1000000 );
- tv->tv_usec = ( long )( t % 1000000 );
- }
-
- return 0;
-}
-
-
-extern struct tm*
-localtime_r( const time_t * clock, struct tm * result )
-{
- localtime_s( result, clock );
- return result;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include "CommonServices.h"
-#include <winsock2.h>
-#include <time.h>
-
-
-/*
- * Posix process compatibility
- */
-typedef int pid_t;
-#if !defined( getpid )
-# define getpid _getpid
-#endif
-
-
-/*
- * Posix networking compatibility
- */
-extern unsigned
-if_nametoindex( const char * ifname );
-
-
-extern char*
-if_indextoname( unsigned ifindex, char * ifname );
-
-
-extern int
-inet_pton( int family, const char * addr, void * dst );
-
-
-/*
- * Posix time compatibility
- */
-extern int
-gettimeofday( struct timeval * tv, struct timezone * tz );
-
-
-extern struct tm*
-localtime_r( const time_t * clock, struct tm * result );
-
-
-/*
- * Posix string compatibility
- */
-#if !defined( strcasecmp )
-# define strcasecmp _stricmp
-#endif
-
-#if !defined( snprintf )
-# define snprint _snprintf
-#endif
-
+++ /dev/null
-This directory contains support files for running mDNS on Microsoft Windows
-and Windows CE/PocketPC. Building this code requires the Windows SDK 2003
-or later. The CodeWarrior builds require CodeWarrior 8 or later and if using
-CodeWarrior 8, the newer Windows headers from the Mac CodeWarrior 9 need to
-be used.
-
-mDNSWin32.c/.h
-
- Platform Support files that go below mDNS Core. These work on both Windows
- and Windows CE/PocketPC.
-
-DNSSD.c/.h
-
- High-level implementation of the DNS-SD API. This supports both "direct"
- (compiled-in mDNSCore) and "client" (IPC to service) usage. Conditionals
- can exclude either "direct" or "client" to reduce code size.
-
-DNSSDDirect.c/.h
-
- Portable implementation of the DNS-SD API. This interacts with mDNSCore
- to perform all the real work of the DNS-SD API. This code does not rely
- on any platform-specifics so it should run on any platform with an mDNS
- platform plugin available. Software that cannot or does not want to use
- the IPC mechanism (e.g. Windows CE, VxWorks, etc.) can use this code
- directly without any of the IPC pieces.
-
-RMxClient.c/.h
-
- Client-side implementation of the DNS-SD IPC API. This handles sending
- and receiving messages from the service to perform DNS-SD operations
- and get DNS-SD responses.
-
-RMxCommon.c/.h
-
- Common code between the RMxClient and RMxServer. This handles establishing
- and accepting connections, the underying message sending and receiving,
- portable data packing and unpacking, and shared utility routines.
-
-RMxServer.c/.h
-
- Server-side implementation of the DNS-SD IPC API. This listens for
- and accepts connections from IPC clients, starts server sessions, and
- acts as a mediator between the "direct" (compiled-in mDNSCore) code
- and the IPC client.
-
-DNSServices is an obsolete higher-level API for using mDNS. New code should
-use the DNS-SD APIs.
-
-DNSServiceDiscovery is an obsolete emulation layer that sits on top of
-DNSServices and provides the Mac OS X DNS Service Discovery API's on any
-platform. New code should use the DNS-SD APIs.
-
-Tool.c is an example client that uses the services of mDNS Core.
-
-ToolWin32.mcp is a CodeWarrior project (CodeWarrior for Windows version 8).
-ToolWin32.vcproj is a Visual Studio .NET 7 project. These projects build
-Tool.c to make DNSServiceTest.exe, a small Windows command-line tool to do all
-the standard DNS-SD stuff on Windows. It has the following features:
-
-- Browse for browsing and/or registration domains.
-- Browse for services.
-- Lookup Service Instances.
-- Register domains for browsing and/or registration.
-- Register services.
-
-For example, if you have a Windows machine running a Web server,
-then you can make it advertise that it is offering HTTP on port 80
-with the following command:
-
-DNSServiceTest -rs "Windows Web Server" "_http._tcp." "local." 80 ""
-
-To search for AFP servers, use this:
-
-DNSServiceTest -bs "_afpovertcp._tcp." "local."
-
-You can also do multiple things at once (e.g. register a service and
-browse for it so one instance of the app can be used for testing).
-Multiple instances can also be run on the same machine to discover each
-other. There is a -help command to show all the commands, their
-parameters, and some examples of using it.
-
-DNSServiceBrowser contains the source code for a graphical browser application
-for Windows CE/PocketPC. The Windows CE/PocketPC version requires Microsoft
-eMbedded C++ 4.0 with SP2 installed and the PocketPC 2003 SDK.
-
+++ /dev/null
-/* -*- 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.
- */
-
-//----------------------------------------------------------------------------------------
-// Registry Constants
-//----------------------------------------------------------------------------------------
-
-#if defined(UNICODE)
-
-# 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"
-# define kServiceDynDNSRegistrationDomains L"RegistrationDomains"
-# define kServiceDynDNSDomains L"Domains" // value is comma separated list of domains
-# define kServiceDynDNSEnabled L"Enabled"
-# define kServiceDynDNSStatus L"Status"
-# define kServiceManageLLRouting L"ManageLLRouting"
-# define kServiceCacheEntryCount L"CacheEntryCount"
-# define kServiceManageFirewall L"ManageFirewall"
-# define kServiceAdvertisedServices L"Services"
-
-# else
-
-# 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"
-# define kServiceDynDNSRegistrationDomains "RegistrationDomains"
-# define kServiceDynDNSDomains "Domains" // value is comma separated list of domains
-# define kServiceDynDNSEnabled "Enabled"
-# define kServiceDynDNSStatus "Status"
-# define kServiceManageLLRouting "ManageLLRouting"
-# define kServiceCacheEntryCount "CacheEntryCount"
-# define kServiceManageFirewall "ManageFirewall"
-
-#endif
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Secret.h"
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-#include <process.h>
-#include <ntsecapi.h>
-#include <lm.h>
-#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 );
-
-
-mDNSBool
-LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainSize, char * outKey, unsigned outKeySize, char * outSecret, unsigned outSecretSize )
-{
- 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;
-
- // Make sure we have enough space to add trailing dot
-
- dlen = strlen( inDomain );
- err = strcpy_s( outDomain, outDomainSize - 2, inDomain );
- require_noerr( err, exit );
-
- // If there isn't a trailing dot, add one because the mDNSResponder
- // presents names with the trailing dot.
-
- if ( outDomain[ dlen - 1 ] != '.' )
- {
- outDomain[ dlen++ ] = '.';
- outDomain[ dlen ] = '\0';
- }
-
- // Canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
-
- 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 );
-
- // <rdar://problem/4192119> 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, outKeySize, 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, outSecretSize, 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 );
-
- // If there isn't a trailing dot, add one because the mDNSResponder
- // presents names with the trailing dot.
-
- ZeroMemory( domain, sizeof( domain ) );
- inDomainLength = strlen( inDomain );
- require_action( inDomainLength > 0, exit, ok = FALSE );
- err = strcpy_s( domain, sizeof( domain ) - 2, inDomain );
- require_action( !err, exit, ok = FALSE );
-
- if ( domain[ inDomainLength - 1 ] != '.' )
- {
- domain[ inDomainLength++ ] = '.';
- domain[ inDomainLength ] = '\0';
- }
-
- // <rdar://problem/4192119>
- //
- // Prepend "$" to the key name, so that there will
- // be no conflict between the zone name and the key
- // name
-
- ZeroMemory( key, sizeof( key ) );
- inKeyLength = strlen( inKey );
- require_action( inKeyLength > 0 , exit, ok = FALSE );
- key[ 0 ] = '$';
- err = strcpy_s( key + 1, sizeof( key ) - 3, inKey );
- require_action( !err, exit, ok = FALSE );
- inKeyLength++;
-
- if ( key[ inKeyLength - 1 ] != '.' )
- {
- key[ inKeyLength++ ] = '.';
- key[ inKeyLength ] = '\0';
- }
-
- // 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
-
- err = MakeLsaStringFromUTF8String( &lucZoneName, domain );
- require_noerr( err, exit );
-
- err = MakeLsaStringFromUTF8String( &lucKeyName, key );
- require_noerr( err, exit );
-
- err = MakeLsaStringFromUTF8String( &lucSecretName, inSecret );
- 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;
-}
-
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _Secret_h
-#define _Secret_h
-
-#include "mDNSEmbeddedAPI.h"
-
-
-#if defined(__cplusplus )
-extern "C" {
-#endif
-
-
-extern mDNSBool
-LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainSize, char * outKey, unsigned outKeySize, char * outSecret, unsigned outSecretSize );
-
-
-extern mDNSBool
-LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret );
-
-
-#if defined(__cplusplus)
-}
-#endif
-
-
-#endif
+++ /dev/null
-MessageIdTypedef=WORD
-LanguageNames=(English=0x409:MSG00409)
-
-MessageId=100
-SymbolicName=MDNSRESPONDER_LOG
-Severity=Success
-Facility=Application
-Language=English
-%1
-.
-
+++ /dev/null
-/* -*- 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.
- */
-
-// <rdar://problem/4278931> Doesn't compile correctly with latest Platform SDK
-
-#if !defined(_WIN32_DCOM)
-# define _WIN32_DCOM
-#endif
-
-
-#include "Firewall.h"
-#include <windows.h>
-#include <crtdbg.h>
-#include <netfw.h>
-#include <objbase.h>
-#include <oleauto.h>
-
-
-static const int kMaxTries = 30;
-static const int kRetrySleepPeriod = 1 * 1000; // 1 second
-
-
-static OSStatus
-mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile)
-{
- INetFwMgr * fwMgr = NULL;
- INetFwPolicy * fwPolicy = NULL;
- int numRetries = 0;
- HRESULT err = kNoErr;
-
- _ASSERT(fwProfile != NULL);
-
- *fwProfile = NULL;
-
- // Use COM to get a reference to the firewall settings manager. This
- // call will fail on anything other than XP SP2
-
- err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
- require(SUCCEEDED(err) && ( fwMgr != NULL ), exit);
-
- // Use the reference to get the local firewall policy
-
- err = fwMgr->get_LocalPolicy(&fwPolicy);
- 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
- // service whose startup type is automatic calls this method.
- // This is true even when the service declares itself to be dependent
- // on the firewall service. Re-trying the method will succeed within
- // a few seconds.
-
- do
- {
- err = fwPolicy->get_CurrentProfile(fwProfile);
-
- if (err)
- {
- Sleep(kRetrySleepPeriod);
- }
- }
- while (err && (numRetries++ < kMaxTries));
-
- require(SUCCEEDED(err), exit);
-
- err = kNoErr;
-
-exit:
-
- // Release temporary COM objects
-
- if (fwPolicy != NULL)
- {
- fwPolicy->Release();
- }
-
- if (fwMgr != NULL)
- {
- fwMgr->Release();
- }
-
- return err;
-}
-
-
-static void
-mDNSFirewallCleanup
- (
- IN INetFwProfile * fwProfile
- )
-{
- // Call Release on the COM reference.
-
- if (fwProfile != NULL)
- {
- fwProfile->Release();
- }
-}
-
-
-static OSStatus
-mDNSFirewallAppIsEnabled
- (
- IN INetFwProfile * fwProfile,
- IN const wchar_t * fwProcessImageFileName,
- OUT BOOL * fwAppEnabled
- )
-{
- BSTR fwBstrProcessImageFileName = NULL;
- VARIANT_BOOL fwEnabled;
- INetFwAuthorizedApplication * fwApp = NULL;
- INetFwAuthorizedApplications* fwApps = NULL;
- OSStatus err = kNoErr;
-
- _ASSERT(fwProfile != NULL);
- _ASSERT(fwProcessImageFileName != NULL);
- _ASSERT(fwAppEnabled != NULL);
-
- *fwAppEnabled = FALSE;
-
- // Get the list of authorized applications
-
- err = fwProfile->get_AuthorizedApplications(&fwApps);
- require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
-
- fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
- require_action( ( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
-
- // Look for us
-
- err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
-
- if (SUCCEEDED(err) && ( fwApp != NULL ) )
- {
- // It's listed, but is it enabled?
-
- err = fwApp->get_Enabled(&fwEnabled);
- require(SUCCEEDED(err), exit);
-
- if (fwEnabled != VARIANT_FALSE)
- {
- // Yes, it's enabled
-
- *fwAppEnabled = TRUE;
- }
- }
-
- err = kNoErr;
-
-exit:
-
- // Deallocate the BSTR
-
- if ( fwBstrProcessImageFileName != NULL )
- {
- SysFreeString(fwBstrProcessImageFileName);
- }
-
- // Release the COM objects
-
- if (fwApp != NULL)
- {
- fwApp->Release();
- }
-
- if (fwApps != NULL)
- {
- fwApps->Release();
- }
-
- return err;
-}
-
-
-static OSStatus
-mDNSFirewallAddApp
- (
- IN INetFwProfile * fwProfile,
- IN const wchar_t * fwProcessImageFileName,
- IN const wchar_t * fwName
- )
-{
- BOOL fwAppEnabled;
- BSTR fwBstrName = NULL;
- BSTR fwBstrProcessImageFileName = NULL;
- INetFwAuthorizedApplication * fwApp = NULL;
- INetFwAuthorizedApplications* fwApps = NULL;
- OSStatus err = S_OK;
-
- _ASSERT(fwProfile != NULL);
- _ASSERT(fwProcessImageFileName != NULL);
- _ASSERT(fwName != NULL);
-
- // First check to see if the application is already authorized.
- err = mDNSFirewallAppIsEnabled( fwProfile, fwProcessImageFileName, &fwAppEnabled );
- require_noerr(err, exit);
-
- // Only add the application if it isn't enabled
-
- if (!fwAppEnabled)
- {
- // Get the list of authorized applications
-
- err = fwProfile->get_AuthorizedApplications(&fwApps);
- 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) && ( fwApp != NULL ), exit);
-
- fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
- require_action(( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
-
- // Set the executable file name
-
- err = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
- require(SUCCEEDED(err), exit);
-
- fwBstrName = SysAllocString(fwName);
- require_action( ( fwBstrName != NULL ) && ( SysStringLen(fwBstrName) > 0 ), exit, err = kNoMemoryErr);
-
- // Set the friendly name
-
- err = fwApp->put_Name(fwBstrName);
- require(SUCCEEDED(err), exit);
-
- // Now add the application
-
- err = fwApps->Add(fwApp);
- require(SUCCEEDED(err), exit);
- }
-
- err = kNoErr;
-
-exit:
-
- // Deallocate the BSTR objects
-
- if ( fwBstrName != NULL )
- {
- SysFreeString(fwBstrName);
- }
-
- if ( fwBstrProcessImageFileName != NULL )
- {
- SysFreeString(fwBstrProcessImageFileName);
- }
-
- // Release the COM objects
-
- if (fwApp != NULL)
- {
- fwApp->Release();
- }
-
- if (fwApps != NULL)
- {
- fwApps->Release();
- }
-
- 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;
-
-}
-
-
-OSStatus
-mDNSAddToFirewall
- (
- LPWSTR executable,
- LPWSTR name
- )
-{
- INetFwProfile * fwProfile = NULL;
- HRESULT comInit = E_FAIL;
- 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);
-
- // Add us to the list of exempt programs
-
- err = mDNSFirewallAddApp( fwProfile, executable, name );
- require_noerr(err, exit);
-
-exit:
-
- // Disconnect from the firewall
-
- if ( fwProfile != NULL )
- {
- mDNSFirewallCleanup(fwProfile);
- }
-
- // De-initialize COM
-
- if (SUCCEEDED(comInit))
- {
- CoUninitialize();
- }
-
- return err;
-}
-
-
-BOOL
-mDNSIsFileAndPrintSharingEnabled( BOOL * retry )
-{
- INetFwProfile * fwProfile = NULL;
- HRESULT comInit = E_FAIL;
- BOOL enabled = FALSE;
- OSStatus err = kNoErr;
-
- // Initialize COM.
-
- *retry = FALSE;
- 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)
- {
- *retry = TRUE;
- 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;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-
-
-#ifndef _Firewall_h
-
-#define _Firewall_h
-
-
-
-
-
-#include "CommonServices.h"
-
-#include "DebugServices.h"
-
-
-
-
-
-#if defined(__cplusplus)
-
-extern "C"
-
-{
-
-#endif
-
-
-
-
-
-OSStatus
-
-mDNSAddToFirewall
-
- (
-
- LPWSTR executable,
-
- LPWSTR name
-
- );
-
-
-BOOL
-mDNSIsFileAndPrintSharingEnabled( BOOL * retry );
-
-
-
-
-
-#if defined(__cplusplus)
-
-}
-
-#endif
-
-
-
-
-
-#endif
-
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef __PREFIX__
-#define __PREFIX__
-
-#if( defined( _DEBUG ) )
- #define DEBUG 1
- #define MDNS_DEBUGMSGS 1
-#else
- #define DEBUG 0
-#endif
-
-#define DNS_SD_CLIENT_ENABLED 0
-
-#endif // __PREFIX__
+++ /dev/null
-/* -*- 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.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <crtdbg.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#include "Poll.h"
-#include "CommonServices.h"
-#include "DebugServices.h"
-#include "RegNames.h"
-
-#include "uds_daemon.h"
-#include "GenLinkedList.h"
-#include "Service.h"
-#include "EventLog.h"
-
-#include "Resource.h"
-
-#include "mDNSEmbeddedAPI.h"
-#include "uDNS.h"
-#include "mDNSWin32.h"
-#include "mDNSDebug.h"
-
-#include "Firewall.h"
-
-#if( !TARGET_OS_WINDOWS_CE )
- #include <mswsock.h>
- #include <process.h>
- #include <ipExport.h>
- #include <ws2def.h>
- #include <ws2ipdef.h>
- #include <iphlpapi.h>
- #include <netioapi.h>
- #include <iptypes.h>
- #include <powrprof.h>
-#endif
-
-#ifndef HeapEnableTerminationOnCorruption
-# define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME "[mDNSWin32] "
-#define kServiceFirewallName L"Bonjour"
-#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 kSecondsTo100NSUnits ( 10 * 1000 * 1000 )
-#define kSPSMaintenanceWakePeriod -30
-#define kWaitToRetry (60 * 5)
-
-#define RR_CACHE_SIZE 500
-static CacheEntity gRRCache[RR_CACHE_SIZE];
-#if 0
-#pragma mark == Structures ==
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-static void Usage( void );
-static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
-static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
-static OSStatus RemoveService( LPCTSTR inName );
-static OSStatus SetServiceParameters();
-static OSStatus GetServiceParameters();
-static OSStatus CheckFirewall();
-static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
-static void ReportStatus( int inType, const char *inFormat, ... );
-
-static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] );
-static OSStatus ServiceSetupEventLogging( void );
-static DWORD WINAPI ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
-
-static OSStatus ServiceRun( int argc, LPTSTR argv[] );
-static void ServiceStop( void );
-
-static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] );
-static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] );
-static OSStatus ServiceSpecificStop( void );
-static void ServiceSpecificFinalize( int argc, LPTSTR argv[] );
-static mStatus SetupServiceEvents();
-static mStatus TearDownServiceEvents();
-static mStatus SetupNotifications();
-static mStatus TearDownNotifications();
-static void CALLBACK StopNotification( HANDLE event, void * context );
-static void CALLBACK PowerSuspendNotification( HANDLE event, void * context );
-static void CALLBACK PowerResumeNotification( HANDLE event, void * context );
-static void CALLBACK InterfaceListNotification( SOCKET socket, LPWSANETWORKEVENTS event, void *context );
-static void CALLBACK ComputerDescriptionNotification( HANDLE event, void *context );
-static void CALLBACK TCPChangedNotification( HANDLE event, void *context );
-static void CALLBACK DDNSChangedNotification( HANDLE event, void *context );
-static void CALLBACK FileSharingChangedNotification( HANDLE event, void *context );
-static void CALLBACK FirewallChangedNotification( HANDLE event, void *context );
-static void CALLBACK AdvertisedServicesChangedNotification( HANDLE event, void *context );
-static void CALLBACK SPSWakeupNotification( HANDLE event, void *context );
-static void CALLBACK SPSSleepNotification( HANDLE event, void *context );
-static void CALLBACK UDSAcceptNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-static void CALLBACK UDSReadNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-static void CoreCallback(mDNS * const inMDNS, mStatus result);
-static mDNSu8 SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
-static OSStatus GetRouteDestination(DWORD * ifIndex, DWORD * address);
-static OSStatus SetLLRoute( mDNS * const inMDNS );
-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)
-# define StrCmp(X,Y) wcscmp(X,Y)
-#else
-# define StrLen(X) strlen(X)
-# define StrCmp(X,Y) strcmp(X,Y)
-#endif
-
-
-#define kLLNetworkAddr "169.254.0.0"
-#define kLLNetworkAddrMask "255.255.0.0"
-
-
-#include "mDNSEmbeddedAPI.h"
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-#define gMDNSRecord mDNSStorage
-DEBUG_LOCAL mDNS_PlatformSupport gPlatformStorage;
-DEBUG_LOCAL BOOL gServiceQuietMode = FALSE;
-DEBUG_LOCAL SERVICE_TABLE_ENTRY gServiceDispatchTable[] =
-{
- { kServiceName, ServiceMain },
- { NULL, NULL }
-};
-DEBUG_LOCAL HANDLE gStopEvent = NULL;
-DEBUG_LOCAL HANDLE gPowerSuspendEvent = NULL;
-DEBUG_LOCAL HANDLE gPowerSuspendAckEvent = NULL;
-DEBUG_LOCAL HANDLE gPowerResumeEvent = NULL;
-DEBUG_LOCAL SOCKET gInterfaceListChangedSocket = INVALID_SOCKET;
-DEBUG_LOCAL HKEY gDescKey = NULL;
-DEBUG_LOCAL HANDLE gDescChangedEvent = NULL; // Computer description changed event
-DEBUG_LOCAL HKEY gTcpipKey = NULL;
-DEBUG_LOCAL HANDLE gTcpipChangedEvent = NULL; // TCP/IP config changed
-DEBUG_LOCAL HKEY gDdnsKey = NULL;
-DEBUG_LOCAL HANDLE gDdnsChangedEvent = NULL; // DynDNS config changed
-DEBUG_LOCAL HKEY gFileSharingKey = NULL;
-DEBUG_LOCAL HANDLE gFileSharingChangedEvent = NULL; // File Sharing changed
-DEBUG_LOCAL HKEY gFirewallKey = NULL;
-DEBUG_LOCAL HANDLE gFirewallChangedEvent = NULL; // Firewall changed
-DEBUG_LOCAL HKEY gAdvertisedServicesKey = NULL;
-DEBUG_LOCAL HANDLE gAdvertisedServicesChangedEvent = NULL; // Advertised services changed
-DEBUG_LOCAL SERVICE_STATUS gServiceStatus;
-DEBUG_LOCAL SERVICE_STATUS_HANDLE gServiceStatusHandle = NULL;
-DEBUG_LOCAL HANDLE gServiceEventSource = NULL;
-DEBUG_LOCAL bool gServiceAllowRemote = false;
-DEBUG_LOCAL int gServiceCacheEntryCount = 0; // 0 means to use the DNS-SD default.
-DEBUG_LOCAL bool gServiceManageLLRouting = true;
-DEBUG_LOCAL HANDLE gSPSWakeupEvent = NULL;
-DEBUG_LOCAL HANDLE gSPSSleepEvent = NULL;
-DEBUG_LOCAL SocketRef gUDSSocket = 0;
-DEBUG_LOCAL udsEventCallback gUDSCallback = NULL;
-DEBUG_LOCAL BOOL gRetryFirewall = FALSE;
-
-typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
-mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
-mDNSlocal GetIpInterfaceEntryFunctionPtr gGetIpInterfaceEntryFunctionPtr = NULL;
-
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// Main
-//===========================================================================================================================
-int Main( int argc, LPTSTR argv[] )
-{
- OSStatus err;
- BOOL ok;
- BOOL start;
- int i;
-
- HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
-
- debug_initialize( kDebugOutputTypeMetaConsole );
- debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
-
- // Default to automatically starting the service dispatcher if no extra arguments are specified.
-
- start = ( argc <= 1 );
-
- // Parse arguments.
-
- for( i = 1; i < argc; ++i )
- {
- if( StrCmp( argv[ i ], TEXT("-install") ) == 0 ) // Install
- {
- TCHAR desc[ 256 ];
-
- desc[ 0 ] = 0;
- LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
- err = InstallService( kServiceName, kServiceName, desc, argv[0] );
- if( err )
- {
- ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
- goto exit;
- }
- }
- else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 ) // Remove
- {
- err = RemoveService( kServiceName );
- if( err )
- {
- ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
- goto exit;
- }
- }
- else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 ) // Start
- {
- start = TRUE;
- }
- else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 ) // Server
- {
- err = RunDirect( argc, argv );
- if( err )
- {
- ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
- }
- goto exit;
- }
- else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 ) // Quiet Mode (toggle)
- {
- gServiceQuietMode = !gServiceQuietMode;
- }
- else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) || // Help
- ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
- {
- Usage();
- err = 0;
- break;
- }
- else
- {
- Usage();
- err = kParamErr;
- break;
- }
- }
-
- // Start the service dispatcher if requested. This does not return until all services have terminated. If any
- // global initialization is needed, it should be done before starting the service dispatcher, but only if it
- // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
-
- if( start )
- {
- ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
- err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
- if( err != kNoErr )
- {
- ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
- goto exit;
- }
- }
- err = 0;
-
-exit:
- dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
- _CrtDumpMemoryLeaks();
- return( (int) err );
-}
-
-//===========================================================================================================================
-// Usage
-//===========================================================================================================================
-
-static void Usage( void )
-{
- fprintf( stderr, "\n" );
- fprintf( stderr, "mDNSResponder 1.0d1\n" );
- fprintf( stderr, "\n" );
- fprintf( stderr, " <no args> Runs the service normally\n" );
- fprintf( stderr, " -install Creates the service and starts it\n" );
- fprintf( stderr, " -remove Stops the service and deletes it\n" );
- fprintf( stderr, " -start Starts the service dispatcher after processing all other arguments\n" );
- fprintf( stderr, " -server Runs the service directly as a server (for debugging)\n" );
- fprintf( stderr, " -q Toggles Quiet Mode (no events or output)\n" );
- fprintf( stderr, " -remote Allow remote connections\n" );
- fprintf( stderr, " -cache n Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
- fprintf( stderr, " -h[elp] Display Help/Usage\n" );
- fprintf( stderr, "\n" );
-}
-
-//===========================================================================================================================
-// ConsoleControlHandler
-//===========================================================================================================================
-
-static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
-{
- BOOL handled;
- OSStatus err;
-
- handled = FALSE;
- switch( inControlEvent )
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_LOGOFF_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- err = ServiceSpecificStop();
- require_noerr( err, exit );
-
- handled = TRUE;
- break;
-
- default:
- break;
- }
-
-exit:
- return( handled );
-}
-
-//===========================================================================================================================
-// InstallService
-//===========================================================================================================================
-
-static OSStatus InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
-{
- OSStatus err;
- SC_HANDLE scm;
- SC_HANDLE service;
- BOOL ok;
- TCHAR fullPath[ MAX_PATH ];
- TCHAR * namePtr;
- DWORD size;
-
- scm = NULL;
- service = NULL;
-
- // Get a full path to the executable since a relative path may have been specified.
-
- size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
- err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
- require_noerr( err, exit );
-
- // Create the service and start it.
-
- scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
- require_noerr( err, exit );
-
- service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS,
- SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies,
- NULL, NULL );
- err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
- require_noerr( err, exit );
-
- err = SetServiceParameters();
- check_noerr( err );
-
- if( inDescription )
- {
- err = SetServiceInfo( scm, inName, inDescription );
- check_noerr( err );
- }
-
- ok = StartService( service, 0, NULL );
- err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
- require_noerr( err, exit );
-
- ReportStatus( EVENTLOG_SUCCESS, "installed service\n" );
- err = kNoErr;
-
-exit:
- if( service )
- {
- CloseServiceHandle( service );
- }
- if( scm )
- {
- CloseServiceHandle( scm );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// RemoveService
-//===========================================================================================================================
-
-static OSStatus RemoveService( LPCTSTR inName )
-{
- OSStatus err;
- SC_HANDLE scm;
- SC_HANDLE service;
- BOOL ok;
- SERVICE_STATUS status;
-
- scm = NULL;
- service = NULL;
-
- // Open a connection to the service.
-
- scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
- err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
- require_noerr( err, exit );
-
- service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
- err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
- require_noerr( err, exit );
-
- // Stop the service, if it is not already stopped, then delete it.
-
- ok = QueryServiceStatus( service, &status );
- err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
- require_noerr( err, exit );
-
- if( status.dwCurrentState != SERVICE_STOPPED )
- {
- ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
- check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
- }
-
- ok = DeleteService( service );
- err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
- require_noerr( err, exit );
-
- ReportStatus( EVENTLOG_SUCCESS, "Removed service\n" );
- err = ERROR_SUCCESS;
-
-exit:
- if( service )
- {
- CloseServiceHandle( service );
- }
- if( scm )
- {
- CloseServiceHandle( scm );
- }
- return( err );
-}
-
-
-
-//===========================================================================================================================
-// SetServiceParameters
-//===========================================================================================================================
-
-static OSStatus SetServiceParameters()
-{
- DWORD value;
- DWORD valueLen = sizeof(DWORD);
- DWORD type;
- OSStatus err;
- HKEY key;
-
- key = NULL;
-
- //
- // Add/Open Parameters section under service entry in registry
- //
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
- require_noerr( err, exit );
-
- //
- // If the value isn't already there, then we create it
- //
- err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
-
- if (err != ERROR_SUCCESS)
- {
- value = 1;
-
- err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
- require_noerr( err, exit );
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return( err );
-}
-
-
-
-//===========================================================================================================================
-// GetServiceParameters
-//===========================================================================================================================
-
-static OSStatus GetServiceParameters()
-{
- DWORD value;
- DWORD valueLen;
- DWORD type;
- OSStatus err;
- HKEY key;
-
- key = NULL;
-
- //
- // Add/Open Parameters section under service entry in registry
- //
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
- require_noerr( err, exit );
-
- valueLen = sizeof(DWORD);
- err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
- if (err == ERROR_SUCCESS)
- {
- gServiceManageLLRouting = (value) ? true : false;
- }
-
- valueLen = sizeof(DWORD);
- err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
- if (err == ERROR_SUCCESS)
- {
- gServiceCacheEntryCount = value;
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return( err );
-}
-
-
-//===========================================================================================================================
-// CheckFirewall
-//===========================================================================================================================
-
-static OSStatus CheckFirewall()
-{
- DWORD value;
- DWORD valueLen;
- DWORD type;
- ENUM_SERVICE_STATUS * lpService = NULL;
- SC_HANDLE sc = NULL;
- HKEY key = NULL;
- BOOL ok;
- DWORD bytesNeeded = 0;
- DWORD srvCount;
- DWORD resumeHandle = 0;
- DWORD srvType;
- DWORD srvState;
- DWORD dwBytes = 0;
- DWORD i;
- BOOL isRunning = FALSE;
- OSStatus err = kUnknownErr;
-
- // Check to see if the firewall service is running. If it isn't, then
- // we want to return immediately
-
- sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
- err = translate_errno( sc, GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- srvType = SERVICE_WIN32;
- srvState = SERVICE_STATE_ALL;
-
- for ( ;; )
- {
- // Call EnumServicesStatus using the handle returned by OpenSCManager
-
- ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
-
- if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
- {
- break;
- }
-
- if ( lpService )
- {
- free( lpService );
- }
-
- dwBytes = bytesNeeded;
-
- lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
- require_action( lpService, exit, err = mStatus_NoMemoryErr );
- }
-
- err = translate_errno( ok, GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- for ( i = 0; i < srvCount; i++ )
- {
- if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
- {
- if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
- {
- isRunning = TRUE;
- }
-
- break;
- }
- }
-
- require_action( isRunning, exit, err = kUnknownErr );
-
- // Check to see if we've managed the firewall.
- // This package might have been installed, then
- // the OS was upgraded to SP2 or above. If that's
- // the case, then we need to manipulate the firewall
- // so networking works correctly.
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
- require_noerr( err, exit );
-
- valueLen = sizeof(DWORD);
- err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
-
- if ((err != ERROR_SUCCESS) || (value == 0))
- {
- wchar_t fullPath[ MAX_PATH ];
- DWORD size;
-
- // Get a full path to the executable
-
- size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
- err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
- require_noerr( err, exit );
-
- err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
- require_noerr( err, exit );
-
- value = 1;
- err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
- require_noerr( err, exit );
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- if ( lpService )
- {
- free( lpService );
- }
-
- if ( sc )
- {
- CloseServiceHandle ( sc );
- }
-
- return( err );
-}
-
-
-
-//===========================================================================================================================
-// SetServiceInfo
-//===========================================================================================================================
-
-static OSStatus SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
-{
- OSStatus err;
- SC_LOCK lock;
- SC_HANDLE service;
- SERVICE_DESCRIPTION description;
- SERVICE_FAILURE_ACTIONS actions;
- SC_ACTION action;
- BOOL ok;
-
- check( inServiceName );
- check( inDescription );
-
- lock = NULL;
- service = NULL;
-
- // Open the database (if not provided) and lock it to prevent other access while re-configuring.
-
- if( !inSCM )
- {
- inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
- err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
- require_noerr( err, exit );
- }
-
- lock = LockServiceDatabase( inSCM );
- err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
- require_noerr( err, exit );
-
- // Open a handle to the service.
-
- service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
- err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
- require_noerr( err, exit );
-
- // Change the description.
-
- description.lpDescription = (LPTSTR) inDescription;
- ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
- err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
- require_noerr( err, exit );
-
- actions.dwResetPeriod = INFINITE;
- actions.lpRebootMsg = NULL;
- actions.lpCommand = NULL;
- actions.cActions = 1;
- actions.lpsaActions = &action;
- action.Delay = 500;
- action.Type = SC_ACTION_RESTART;
-
- ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
- err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
- require_noerr( err, exit );
-
- err = ERROR_SUCCESS;
-
-exit:
- // Close the service and release the lock.
-
- if( service )
- {
- CloseServiceHandle( service );
- }
- if( lock )
- {
- UnlockServiceDatabase( lock );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// ReportStatus
-//===========================================================================================================================
-
-static void ReportStatus( int inType, const char *inFormat, ... )
-{
- if( !gServiceQuietMode )
- {
- va_list args;
-
- va_start( args, inFormat );
- if( gServiceEventSource )
- {
- char s[ 1024 ];
- BOOL ok;
- const char * array[ 1 ];
-
- vsnprintf( s, sizeof( s ), inFormat, args );
- array[ 0 ] = s;
- ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- }
- else
- {
- int n;
-
- n = vfprintf( stderr, inFormat, args );
- check( n >= 0 );
- }
- va_end( args );
- }
-}
-
-//===========================================================================================================================
-// RunDirect
-//===========================================================================================================================
-
-int RunDirect( int argc, LPTSTR argv[] )
-{
- OSStatus err;
- BOOL initialized;
- BOOL ok;
-
- initialized = FALSE;
-
- err = SetupServiceEvents();
- require_noerr( err, exit );
-
- // Install a Console Control Handler to handle things like control-c signals.
-
- ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- err = ServiceSpecificInitialize( argc, argv );
- require_noerr( err, exit );
- initialized = TRUE;
-
- // Run the service. This does not return until the service quits or is stopped.
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Running service directly\n" );
-
- err = ServiceSpecificRun( argc, argv );
- require_noerr( err, exit );
-
- // Clean up.
-
-exit:
- if( initialized )
- {
- ServiceSpecificFinalize( argc, argv );
- }
-
- TearDownServiceEvents();
-
- return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// ServiceMain
-//===========================================================================================================================
-
-static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
-{
- OSStatus err;
- BOOL ok;
-
- err = SetupServiceEvents();
- require_noerr( err, exit );
-
- err = ServiceSetupEventLogging();
- check_noerr( err );
-
- err = GetServiceParameters();
- check_noerr( err );
-
- // Initialize the service status and register the service control handler with the name of the service.
-
- gServiceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
- gServiceStatus.dwCurrentState = 0;
- gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_POWEREVENT;
- gServiceStatus.dwWin32ExitCode = NO_ERROR;
- gServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
- gServiceStatus.dwCheckPoint = 0;
- gServiceStatus.dwWaitHint = 0;
-
- gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
- err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
- require_noerr( err, exit );
-
- // Mark the service as starting.
-
- gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
- gServiceStatus.dwCheckPoint = 0;
- gServiceStatus.dwWaitHint = 5000; // 5 seconds
- ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
- check_translated_errno( ok, GetLastError(), kParamErr );
-
- // Run the service. This does not return until the service quits or is stopped.
-
- err = ServiceRun( (int) argc, argv );
- if( err != kNoErr )
- {
- gServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
- gServiceStatus.dwServiceSpecificExitCode = (DWORD) err;
- }
-
- // Service-specific work is done so mark the service as stopped.
-
- gServiceStatus.dwCurrentState = SERVICE_STOPPED;
- ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
- check_translated_errno( ok, GetLastError(), kParamErr );
-
- // Note: The service status handle should not be closed according to Microsoft documentation.
-
-exit:
-
- if( gServiceEventSource )
- {
- ok = DeregisterEventSource( gServiceEventSource );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- gServiceEventSource = NULL;
- }
-
- TearDownServiceEvents();
-}
-
-//===========================================================================================================================
-// ServiceSetupEventLogging
-//===========================================================================================================================
-
-static OSStatus ServiceSetupEventLogging( void )
-{
- OSStatus err;
- HKEY key;
- LPCTSTR s;
- DWORD typesSupported;
- TCHAR path[ MAX_PATH ];
- DWORD n;
-
- key = NULL;
-
- // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
-
- s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
- err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
- require_noerr( err, exit );
-
- // Add the name to the EventMessageFile subkey.
-
- path[ 0 ] = '\0';
- GetModuleFileName( NULL, path, MAX_PATH );
- n = (DWORD) ( ( StrLen( path ) + 1 ) * sizeof( TCHAR ) );
- err = RegSetValueEx( key, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
- require_noerr( err, exit );
-
- // Set the supported event types in the TypesSupported subkey.
-
- typesSupported = 0
- | EVENTLOG_SUCCESS
- | EVENTLOG_ERROR_TYPE
- | EVENTLOG_WARNING_TYPE
- | EVENTLOG_INFORMATION_TYPE
- | EVENTLOG_AUDIT_SUCCESS
- | EVENTLOG_AUDIT_FAILURE;
- err = RegSetValueEx( key, TEXT("TypesSupported"), 0, REG_DWORD, (const LPBYTE) &typesSupported, sizeof( DWORD ) );
- require_noerr( err, exit );
-
- // Set up the event source.
-
- gServiceEventSource = RegisterEventSource( NULL, kServiceName );
- err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
- require_noerr( err, exit );
-
-exit:
- if( key )
- {
- RegCloseKey( key );
- }
- return( err );
-}
-
-
-//===========================================================================================================================
-// ServiceControlHandler
-//===========================================================================================================================
-
-static DWORD WINAPI ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
-{
- BOOL setStatus;
- OSStatus err;
- BOOL ok;
-
- DEBUG_UNUSED( inEventData );
- DEBUG_UNUSED( inContext );
-
- setStatus = TRUE;
- switch( inControl )
- {
- case SERVICE_CONTROL_STOP:
- case SERVICE_CONTROL_SHUTDOWN:
-
- dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
-
- ServiceStop();
- setStatus = FALSE;
- break;
-
- case SERVICE_CONTROL_POWEREVENT:
-
- if (inEventType == PBT_APMSUSPEND)
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
-
- if ( gPowerSuspendEvent )
- {
- ok = SetEvent( gPowerSuspendEvent );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- check_noerr( err );
-
- switch ( WaitForSingleObject( gPowerSuspendAckEvent, 5 * 1000 ) )
- {
- case WAIT_OBJECT_0:
- {
- // No error
- }
- break;
-
- case WAIT_TIMEOUT:
- {
- dlog( kDebugLevelError, DEBUG_NAME "Timed out waiting for acknowledgement of machine sleep\n" );
- ReportStatus( EVENTLOG_ERROR_TYPE, "Timed out waiting for acknowledgement of machine sleep" );
- }
- break;
-
- default:
- {
- dlog( kDebugLevelError, DEBUG_NAME "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
- ReportStatus( EVENTLOG_ERROR_TYPE, "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
- }
- break;
- }
- }
- }
- else if (inEventType == PBT_APMRESUMESUSPEND)
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
-
- if ( gPowerResumeEvent )
- {
- ok = SetEvent( gPowerResumeEvent );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- check_noerr( err );
- }
- }
-
- break;
-
- default:
- dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
- break;
- }
-
- if( setStatus && gServiceStatusHandle )
- {
- ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- }
-
- return NO_ERROR;
-}
-
-//===========================================================================================================================
-// ServiceRun
-//===========================================================================================================================
-
-static OSStatus ServiceRun( int argc, LPTSTR argv[] )
-{
- OSStatus err;
- BOOL initialized;
- BOOL ok;
-
- DEBUG_UNUSED( argc );
- DEBUG_UNUSED( argv );
-
- initialized = FALSE;
-
- // <rdar://problem/5727548> 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
-
- while ( 1 )
- {
- DWORD ret;
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initializing" );
-
- err = ServiceSpecificInitialize( argc, argv );
-
- if ( !err )
- {
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initialized" );
- break;
- }
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initialization failed with err %d. Waiting %d seconds to retry...", err, kWaitToRetry );
-
- ret = WaitForSingleObject( gStopEvent, 1000 * kWaitToRetry );
-
- if ( ret == WAIT_OBJECT_0 )
- {
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a stop event" );
- goto exit;
- }
- else if ( ret == WAIT_OBJECT_0 + 1 )
- {
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a power suspend event" );
- }
- else if ( ret == WAIT_OBJECT_0 + 2 )
- {
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a power resume event" );
- }
- else if ( ret != WAIT_TIMEOUT )
- {
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received an error in WaitForSingleObject() : %d, %d", ret, GetLastError() );
- goto exit;
- }
- }
-
- initialized = TRUE;
-
- err = CheckFirewall();
- check_noerr( err );
-
- if ( err )
- {
- gRetryFirewall = TRUE;
- }
-
- // Run the service-specific stuff. This does not return until the service quits or is stopped.
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service started\n" );
-
- err = ServiceSpecificRun( argc, argv );
- require_noerr( err, exit );
-
-exit:
-
- // Service stopped. Clean up and we're done.
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service stopped (%d)\n", err );
-
- if( initialized )
- {
- ServiceSpecificFinalize( argc, argv );
- }
-
- return( err );
-}
-
-//===========================================================================================================================
-// ServiceStop
-//===========================================================================================================================
-
-static void ServiceStop( void )
-{
- BOOL ok;
- OSStatus err;
-
- // Signal the event to cause the service to exit.
-
- if( gServiceStatusHandle )
- {
- gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
- ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
- check_translated_errno( ok, GetLastError(), kParamErr );
- }
-
- err = ServiceSpecificStop();
- check_noerr( err );
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark == Service Specific ==
-#endif
-
-//===========================================================================================================================
-// ServiceSpecificInitialize
-//===========================================================================================================================
-
-static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] )
-{
- OSStatus err;
-
- DEBUG_UNUSED( argc );
- DEBUG_UNUSED( argv );
-
- mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
- mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
-
- gPlatformStorage.reportStatusFunc = ReportStatus;
-
- err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext);
- require_noerr( err, exit);
-
- err = SetupNotifications();
- check_noerr( err );
-
- err = udsserver_init(mDNSNULL, 0);
- require_noerr( err, exit);
-
- SetLLRoute( &gMDNSRecord );
-
-exit:
- if( err != kNoErr )
- {
- ServiceSpecificFinalize( argc, argv );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// ServiceSpecificRun
-//===========================================================================================================================
-
-static OSStatus ServiceSpecificRun( int argc, LPTSTR argv[] )
-{
- mDNSBool done = mDNSfalse;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( argc );
- DEBUG_UNUSED( argv );
-
- err = SetupInterfaceList( &gMDNSRecord );
- check( !err );
-
- err = uDNS_SetupDNSConfig( &gMDNSRecord );
- check( !err );
-
- while( !done )
- {
- static mDNSs32 RepeatedBusy = 0;
- mDNSs32 nextTimerEvent;
- mStatus err;
-
- // Give the mDNS core a chance to do its work and determine next event time.
-
- nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
-
- if ( nextTimerEvent < 0) nextTimerEvent = 0;
- else if ( nextTimerEvent > (0x7FFFFFFF / 1000)) nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
- else nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
-
- // Debugging sanity check, to guard against CPU spins
-
- if ( nextTimerEvent > 0 )
- {
- RepeatedBusy = 0;
- }
- else
- {
- nextTimerEvent = 1;
-
- if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
- {
- ShowTaskSchedulingError( &gMDNSRecord );
- RepeatedBusy = 0;
- }
- }
-
- if ( gMDNSRecord.ShutdownTime )
- {
- mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
-
- if ( mDNS_ExitNow( &gMDNSRecord, now ) )
- {
- mDNS_FinalExit( &gMDNSRecord );
- done = TRUE;
- break;
- }
-
- if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
- {
- nextTimerEvent = gMDNSRecord.ShutdownTime;
- }
- }
-
- err = mDNSPoll( nextTimerEvent );
-
- if ( err )
- {
- Sleep( 3 * 1000 );
-
- err = SetupInterfaceList( &gMDNSRecord );
- check( !err );
-
- err = uDNS_SetupDNSConfig( &gMDNSRecord );
- check( !err );
-
- break;
- }
- }
-
- return ( err );
-}
-
-
-//===========================================================================================================================
-// ServiceSpecificStop
-//===========================================================================================================================
-
-static OSStatus ServiceSpecificStop( void )
-{
- OSStatus err;
- BOOL ok;
-
- ok = SetEvent(gStopEvent);
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
-
- return( err );
-}
-
-//===========================================================================================================================
-// ServiceSpecificFinalize
-//===========================================================================================================================
-
-static void ServiceSpecificFinalize( int argc, LPTSTR argv[] )
-{
- DEBUG_UNUSED( argc );
- DEBUG_UNUSED( argv );
-
- //
- // clean up the notifications
- //
- TearDownNotifications();
-
- //
- // clean up loaded library
- //
-
- if( gIPHelperLibraryInstance )
- {
- gGetIpInterfaceEntryFunctionPtr = NULL;
-
- FreeLibrary( gIPHelperLibraryInstance );
- gIPHelperLibraryInstance = NULL;
- }
-}
-
-
-//===========================================================================================================================
-// SetupServiceEvents
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupServiceEvents()
-{
- mStatus err;
-
- // Stop Event
-
- gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- err = translate_errno( gStopEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
-
- if ( err )
- {
- TearDownServiceEvents();
- }
-
- return err;
-}
-
-
-//===========================================================================================================================
-// TearDownServiceNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownServiceEvents()
-{
- if ( gStopEvent )
- {
- CloseHandle( gStopEvent );
- gStopEvent = NULL;
- }
-
- return mStatus_NoError;
-}
-
-
-//===========================================================================================================================
-// SetupNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupNotifications()
-{
- mStatus err;
- SocketRef sock;
- unsigned long param;
- int inBuffer;
- int outBuffer;
- DWORD outSize;
-
- require_action( gStopEvent, exit, err = kUnknownErr );
- err = mDNSPollRegisterEvent( gStopEvent, StopNotification, NULL );
- require_noerr( err, exit );
-
- // Power Suspend
-
- gPowerSuspendEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- err = translate_errno( gPowerSuspendEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gPowerSuspendEvent, PowerSuspendNotification, NULL );
- require_noerr( err, exit );
-
- // Power Suspend Ack
-
- gPowerSuspendAckEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- err = translate_errno( gPowerSuspendAckEvent, ( mStatus ) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- // Power Resume
-
- gPowerResumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- err = translate_errno( gPowerResumeEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gPowerResumeEvent, PowerResumeNotification, NULL );
- require_noerr( err, exit );
-
- // Register to listen for address list changes.
-
- sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
- err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- require_noerr( err, exit );
- gInterfaceListChangedSocket = sock;
-
- // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event
- // when a change to the interface list is detected.
-
- param = 1;
- err = ioctlsocket( sock, FIONBIO, ¶m );
- err = translate_errno( err == 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- inBuffer = 0;
- outBuffer = 0;
- err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
- if( err < 0 )
- {
- check( errno_compat() == WSAEWOULDBLOCK );
- }
-
- err = mDNSPollRegisterSocket( sock, FD_ADDRESS_LIST_CHANGE, InterfaceListNotification, NULL );
- require_noerr( err, exit );
-
- gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
- check_translated_errno( err == 0, errno_compat(), kNameErr );
-
- if ( gDescKey != NULL )
- {
- err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
- require_noerr( err, exit );
- }
-
- err = mDNSPollRegisterEvent( gDescChangedEvent, ComputerDescriptionNotification, NULL );
- require_noerr( err, exit );
-
- // This will catch all changes to tcp/ip networking, including changes to the domain search list
-
- gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
- require_noerr( err, exit );
- err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gTcpipChangedEvent, TCPChangedNotification, NULL );
- require_noerr( err, exit );
-
- // This will catch all changes to ddns configuration
-
- gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
- require_noerr( err, exit );
- err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gDdnsChangedEvent, DDNSChangedNotification, NULL );
- require_noerr( err, exit );
-
- // This will catch all changes to file sharing
-
- gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
-
- // 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.
-
- if ( !err )
- {
- err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gFileSharingChangedEvent, FileSharingChangedNotification, NULL );
- require_noerr( err, exit );
- }
- else
- {
- err = mStatus_NoError;
- }
-
- // This will catch changes to the Windows firewall
-
- gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- err = translate_errno( gFirewallChangedEvent, (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"), &gFirewallKey );
-
- if ( !err )
- {
- err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gFirewallChangedEvent, FirewallChangedNotification, NULL );
- require_noerr( err, exit );
- }
- else
- {
- err = mStatus_NoError;
- }
-
- // This will catch all changes to advertised services configuration
-
- gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
- require_noerr( err, exit );
- err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gAdvertisedServicesChangedEvent, AdvertisedServicesChangedNotification, NULL );
- require_noerr( err, exit );
-
- // SPSWakeup timer
-
- gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
- err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gSPSWakeupEvent, SPSWakeupNotification, NULL );
- require_noerr( err, exit );
-
- // SPSSleep timer
-
- gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
- err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- err = mDNSPollRegisterEvent( gSPSSleepEvent, SPSSleepNotification, NULL );
- require_noerr( err, exit );
-
-exit:
- if( err )
- {
- TearDownNotifications();
- }
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownNotifications()
-{
- if( IsValidSocket( gInterfaceListChangedSocket ) )
- {
- mDNSPollUnregisterSocket( gInterfaceListChangedSocket );
-
- close_compat( gInterfaceListChangedSocket );
- gInterfaceListChangedSocket = kInvalidSocketRef;
- }
-
- if ( gDescChangedEvent != NULL )
- {
- mDNSPollUnregisterEvent( gDescChangedEvent );
- CloseHandle( gDescChangedEvent );
- gDescChangedEvent = NULL;
- }
-
- if ( gDescKey != NULL )
- {
- RegCloseKey( gDescKey );
- gDescKey = NULL;
- }
-
- if ( gTcpipChangedEvent != NULL )
- {
- mDNSPollUnregisterEvent( gTcpipChangedEvent );
- CloseHandle( gTcpipChangedEvent );
- gTcpipChangedEvent = NULL;
- }
-
- if ( gDdnsChangedEvent != NULL )
- {
- mDNSPollUnregisterEvent( gDdnsChangedEvent );
- CloseHandle( gDdnsChangedEvent );
- gDdnsChangedEvent = NULL;
- }
-
- if ( gDdnsKey != NULL )
- {
- RegCloseKey( gDdnsKey );
- gDdnsKey = NULL;
- }
-
- if ( gFileSharingChangedEvent != NULL )
- {
- mDNSPollUnregisterEvent( gFileSharingChangedEvent );
- CloseHandle( gFileSharingChangedEvent );
- gFileSharingChangedEvent = NULL;
- }
-
- if ( gFileSharingKey != NULL )
- {
- RegCloseKey( gFileSharingKey );
- gFileSharingKey = NULL;
- }
-
- if ( gFirewallChangedEvent != NULL )
- {
- mDNSPollUnregisterEvent( gFirewallChangedEvent );
- CloseHandle( gFirewallChangedEvent );
- gFirewallChangedEvent = NULL;
- }
-
- if ( gFirewallKey != NULL )
- {
- RegCloseKey( gFirewallKey );
- gFirewallKey = NULL;
- }
-
- if ( gAdvertisedServicesChangedEvent != NULL )
- {
- mDNSPollUnregisterEvent( gAdvertisedServicesChangedEvent );
- CloseHandle( gAdvertisedServicesChangedEvent );
- gAdvertisedServicesChangedEvent = NULL;
- }
-
- if ( gAdvertisedServicesKey != NULL )
- {
- RegCloseKey( gAdvertisedServicesKey );
- gAdvertisedServicesKey = NULL;
- }
-
- if ( gSPSWakeupEvent )
- {
- mDNSPollUnregisterEvent( gSPSWakeupEvent );
- CloseHandle( gSPSWakeupEvent );
- gSPSWakeupEvent = NULL;
- }
-
- if ( gSPSSleepEvent )
- {
- mDNSPollUnregisterEvent( gSPSSleepEvent );
- CloseHandle( gSPSSleepEvent );
- gSPSSleepEvent = NULL;
- }
-
- if ( gPowerResumeEvent )
- {
- mDNSPollUnregisterEvent( gPowerResumeEvent );
- CloseHandle( gPowerResumeEvent );
- gPowerResumeEvent = NULL;
- }
-
- if ( gPowerSuspendAckEvent )
- {
- CloseHandle( gPowerSuspendAckEvent );
- gPowerSuspendAckEvent = NULL;
- }
-
- if ( gPowerSuspendEvent )
- {
- mDNSPollUnregisterEvent( gPowerSuspendEvent );
- CloseHandle( gPowerSuspendEvent );
- gPowerSuspendEvent = NULL;
- }
-
- if ( gStopEvent )
- {
- mDNSPollUnregisterEvent( gStopEvent );
- }
-
- return( mStatus_NoError );
-}
-
-
-mDNSlocal void CALLBACK
-StopNotification( HANDLE event, void *context )
-{
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
- udsserver_exit();
- mDNS_StartExit( &gMDNSRecord );
-}
-
-
-mDNSlocal void CALLBACK
-PowerSuspendNotification( HANDLE event, void * context )
-{
- LARGE_INTEGER timeout;
- BOOL ok;
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "PowerSuspendNotification\n" );
-
- gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
-
- if ( gMDNSRecord.SystemWakeOnLANEnabled )
- {
- ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
- check( ok );
- }
-
- mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
-
- ok = SetEvent( gPowerSuspendAckEvent );
-
- if ( !ok )
- {
- dlog( kDebugLevelError, DEBUG_NAME "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
- ReportStatus( EVENTLOG_ERROR_TYPE, "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
- }
-}
-
-
-mDNSlocal void CALLBACK
-PowerResumeNotification( HANDLE event, void * context )
-{
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "PowerResumeNotification\n" );
-
- if ( gSPSWakeupEvent )
- {
- CancelWaitableTimer( gSPSWakeupEvent );
- }
-
- if ( gSPSSleepEvent )
- {
- CancelWaitableTimer( gSPSSleepEvent );
- }
-
- mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
-}
-
-
-
-mDNSlocal void CALLBACK
-InterfaceListNotification( SOCKET socket, LPWSANETWORKEVENTS event, void *context )
-{
- int inBuffer;
- int outBuffer;
- DWORD outSize;
- int err;
-
- DEBUG_UNUSED( socket );
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- // 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.
-
- InterfaceListDidChange( &gMDNSRecord );
-
- // reset the event handler
- inBuffer = 0;
- outBuffer = 0;
- err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
- if( err < 0 )
- {
- check( errno_compat() == WSAEWOULDBLOCK );
- }
-}
-
-
-mDNSlocal void CALLBACK
-ComputerDescriptionNotification( HANDLE event, void *context )
-{
- // The computer description might have changed
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- ComputerDescriptionDidChange( &gMDNSRecord );
- udsserver_handle_configchange( &gMDNSRecord );
-
- // and reset the event handler
- if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
- {
- int err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
- check_noerr( err );
- }
-}
-
-
-mDNSlocal void CALLBACK
-TCPChangedNotification( HANDLE event, void *context )
-{
- // The TCP/IP might have changed
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- TCPIPConfigDidChange( &gMDNSRecord );
- udsserver_handle_configchange( &gMDNSRecord );
-
- // and reset the event handler
-
- if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
- {
- int err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
- check_noerr( err );
- }
-}
-
-
-mDNSlocal void CALLBACK
-DDNSChangedNotification( HANDLE event, void *context )
-{
- // The DynDNS config might have changed
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- DynDNSConfigDidChange( &gMDNSRecord );
- udsserver_handle_configchange( &gMDNSRecord );
-
- // and reset the event handler
-
- if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
- {
- int err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
- check_noerr( err );
- }
-}
-
-
-mDNSlocal void CALLBACK
-FileSharingChangedNotification( HANDLE event, void *context )
-{
- // File sharing changed
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- FileSharingDidChange( &gMDNSRecord );
-
- // and reset the event handler
-
- if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
- {
- int err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
- check_noerr( err );
- }
-}
-
-
-mDNSlocal void CALLBACK
-FirewallChangedNotification( HANDLE event, void *context )
-{
- // Firewall configuration changed
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- FirewallDidChange( &gMDNSRecord );
-
- // and reset the event handler
-
- if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
- {
- int err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
- check_noerr( err );
- }
-}
-
-
-mDNSlocal void CALLBACK
-AdvertisedServicesChangedNotification( HANDLE event, void *context )
-{
- // Ultimately we'll want to manage multiple services, but right now the only service
- // we'll be managing is SMB.
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- FileSharingDidChange( &gMDNSRecord );
-
- // and reset the event handler
-
- if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
- {
- int err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
- check_noerr( err );
- }
-}
-
-
-mDNSlocal void CALLBACK
-SPSWakeupNotification( HANDLE event, void *context )
-{
- LARGE_INTEGER timeout;
-
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
-
- timeout.QuadPart = kSPSMaintenanceWakePeriod;
- timeout.QuadPart *= kSecondsTo100NSUnits;
-
- SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
-}
-
-
-mDNSlocal void CALLBACK
-SPSSleepNotification( HANDLE event, void *context )
-{
- DEBUG_UNUSED( event );
- DEBUG_UNUSED( context );
-
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
-
- // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
- // call HandlePowerSuspend() explicity. This will reset the
- // maintenance wake timers.
-
- PowerSuspendNotification( gPowerSuspendEvent, NULL );
- SetSuspendState( FALSE, FALSE, FALSE );
-}
-
-
-//===========================================================================================================================
-// CoreCallback
-//===========================================================================================================================
-
-static void
-CoreCallback(mDNS * const inMDNS, mStatus status)
-{
- if (status == mStatus_ConfigChanged)
- {
- SetLLRoute( inMDNS );
- }
-}
-
-
-//===========================================================================================================================
-// UDSAcceptNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDSAcceptNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
- ( void ) sock;
- ( void ) event;
- ( void ) context;
-
- if ( gUDSCallback )
- {
- gUDSCallback( ( int ) gUDSSocket, 0, context );
- }
-}
-
-
-//===========================================================================================================================
-// UDSReadNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDSReadNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
- TCPSocket *tcpSock = ( TCPSocket* ) context;
-
- ( void ) sock;
- ( void ) event;
-
- if ( tcpSock )
- {
- tcpSock->userCallback( ( int ) tcpSock->fd, 0, tcpSock->userContext );
- }
-}
-
-
-//===========================================================================================================================
-// udsSupportAddFDToEventLoop
-//===========================================================================================================================
-
-mStatus
-udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
-{
- mStatus err = mStatus_NoError;
-
- // We are using some knowledge of what is being passed to us here. If the fd is a listen socket,
- // then the "context" parameter is NULL. If it is an actual read/write socket, then the "context"
- // parameter is not null.
-
- if ( context )
- {
- TCPSocket * sock;
-
- sock = malloc( sizeof( TCPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
- mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
-
- sock->fd = (SOCKET) fd;
- sock->userCallback = callback;
- sock->userContext = context;
- sock->m = &gMDNSRecord;
-
- *platform_data = sock;
-
- err = mDNSPollRegisterSocket( sock->fd, FD_READ | FD_CLOSE, UDSReadNotification, sock );
- require_noerr( err, exit );
- }
- else
- {
- gUDSSocket = fd;
- gUDSCallback = callback;
-
- err = mDNSPollRegisterSocket( gUDSSocket, FD_ACCEPT | FD_CLOSE, UDSAcceptNotification, NULL );
- require_noerr( err, exit );
- }
-
-exit:
-
- return err;
-}
-
-
-int
-udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
-{
- TCPSocket * sock;
- mDNSBool closed;
- int ret;
-
- ( void ) flags;
-
- sock = ( TCPSocket* ) platform_data;
- require_action( sock, exit, ret = -1 );
- require_action( sock->fd == fd, exit, ret = -1 );
-
- ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
-
- if ( closed )
- {
- ret = 0;
- }
- else if ( !ret && ( WSAGetLastError() == WSAEWOULDBLOCK ) )
- {
- // mDNSPlatformReadTCP will return 0 if it gets WSAEWOULDBLOCK, but
- // that caller of this routine interprets that as close connection.
- // We'll fix that by returning -1 in that case.
-
- ret = -1;
- }
-
-exit:
-
- return ret;
-}
-
-
-mStatus
-udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data) // Note: This also CLOSES the socket
-{
- mStatus err = kNoErr;
-
- mDNSPollUnregisterSocket( fd );
-
- if ( platform_data != NULL )
- {
- TCPSocket * sock;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
- sock = ( TCPSocket* ) platform_data;
- check( sock->fd == fd );
- mDNSPlatformTCPCloseConnection( sock );
- }
-
- return err;
-}
-
-
-mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
- {
- (void)m;
- (void)delay;
- // No-op, for now
- }
-
-
-//===========================================================================================================================
-// SystemWakeForNetworkAccess
-//===========================================================================================================================
-
-mDNSu8
-SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
-{
- HKEY key = NULL;
- DWORD dwSize;
- DWORD enabled;
- mDNSu8 ok;
- SYSTEM_POWER_STATUS powerStatus;
- time_t startTime;
- time_t nextWakeupTime;
- int delta;
- DWORD err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
-
- // Make sure we have a timer
-
- require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
- require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
-
- // Make sure the user enabled bonjour sleep proxy client
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
- require_action( !err, exit, ok = FALSE );
- dwSize = sizeof( DWORD );
- err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
- require_action( !err, exit, ok = FALSE );
- require_action( enabled, exit, ok = FALSE );
-
- // Make sure machine is on AC power
-
- ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
- require_action( ok, exit, ok = FALSE );
- require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
-
- // Now make sure we have a network interface that does wake-on-lan
-
- ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
- require_action( ok, exit, ok = FALSE );
-
- // Now make sure we have advertised services. Doesn't make sense to
- // enable sleep proxy if we have no multicast services that could
- // potentially wake us up.
-
- ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
- require_action( ok, exit, ok = FALSE );
-
- // Calculate next wake up time
-
- startTime = time( NULL ); // Seconds since midnight January 1, 1970
- nextWakeupTime = startTime + ( 120 * 60 ); // 2 hours later
-
- if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
- {
- nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
- }
-
- // Finally calculate the next relative wakeup time
-
- delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
- ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
-
- // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
-
- timeout->QuadPart = -delta;
- timeout->QuadPart *= kSecondsTo100NSUnits;
-
- ok = TRUE;
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return ok;
-}
-
-
-//===========================================================================================================================
-// HaveRoute
-//===========================================================================================================================
-
-static bool
-HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
-{
- PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
- DWORD dwSize = 0;
- BOOL bOrder = FALSE;
- OSStatus err;
- bool found = false;
- unsigned long int i;
-
- //
- // Find out how big our buffer needs to be.
- //
- err = GetIpForwardTable(NULL, &dwSize, bOrder);
- require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
-
- //
- // Allocate the memory for the table
- //
- pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
- require_action( pIpForwardTable, exit, err = kNoMemoryErr );
-
- //
- // Now get the table.
- //
- err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
- require_noerr( err, exit );
-
- //
- // Search for the row in the table we want.
- //
- for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
- {
- if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
- {
- memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
- found = true;
- break;
- }
- }
-
-exit:
-
- if ( pIpForwardTable != NULL )
- {
- free(pIpForwardTable);
- }
-
- return found;
-}
-
-
-//===========================================================================================================================
-// IsValidAddress
-//===========================================================================================================================
-
-static bool
-IsValidAddress( const char * addr )
-{
- return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
-}
-
-
-//===========================================================================================================================
-// GetAdditionalMetric
-//===========================================================================================================================
-
-static ULONG
-GetAdditionalMetric( DWORD ifIndex )
-{
- ULONG metric = 0;
-
- if( !gIPHelperLibraryInstance )
- {
- gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
-
- gGetIpInterfaceEntryFunctionPtr =
- (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
-
- if( !gGetIpInterfaceEntryFunctionPtr )
- {
- BOOL ok;
-
- ok = FreeLibrary( gIPHelperLibraryInstance );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- gIPHelperLibraryInstance = NULL;
- }
- }
-
- if ( gGetIpInterfaceEntryFunctionPtr )
- {
- 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 );
-
- //
- // <rdar://problem/4096464> Don't call SetLLRoute on loopback
- // <rdar://problem/6885843> 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 ( ( inMDNS->p->osMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
- {
- DWORD ifIndex;
- MIB_IPFORWARDROW rowExtant;
- bool addRoute;
- MIB_IPFORWARDROW row;
-
- 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 = 20 + GetAdditionalMetric( ifIndex );
- 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 ), 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)
- {
- //
- // 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;
- }
- }
-
- if (addRoute && row.dwForwardNextHop)
- {
- err = CreateIpForwardEntry(&row);
- check_noerr( err );
- }
- }
-
-exit:
-
- return ( err );
-}
-
-
-//===========================================================================================================================
-// GetRouteDestination
-//===========================================================================================================================
-
-static OSStatus
-GetRouteDestination(DWORD * ifIndex, DWORD * address)
-{
- struct in_addr ia;
- IP_ADAPTER_INFO * pAdapterInfo = NULL;
- IP_ADAPTER_INFO * pAdapter = NULL;
- ULONG bufLen;
- mDNSBool done = mDNSfalse;
- OSStatus err;
-
- //
- // GetBestInterface will fail if there is no default gateway
- // configured. If that happens, we will just take the first
- // interface in the list. MSDN support says there is no surefire
- // way to manually determine what the best interface might
- // be for a particular network address.
- //
- ia.s_addr = inet_addr(kLLNetworkAddr);
- err = GetBestInterface(*(IPAddr*) &ia, ifIndex);
-
- if (err)
- {
- *ifIndex = 0;
- }
-
- //
- // Make an initial call to GetAdaptersInfo to get
- // the necessary size into the bufLen variable
- //
- err = GetAdaptersInfo( NULL, &bufLen);
- require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
-
- pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
- require_action( pAdapterInfo, exit, err = kNoMemoryErr );
-
- err = GetAdaptersInfo( pAdapterInfo, &bufLen);
- require_noerr( err, exit );
-
- pAdapter = pAdapterInfo;
- err = kUnknownErr;
-
- // <rdar://problem/3718122>
- // <rdar://problem/5652098>
- //
- // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
- //
- // If these interfaces are active (i.e., has a non-zero IP Address),
- // then we want to disable routing table modifications.
-
- while (pAdapter)
- {
- 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;
- }
-
- pAdapter = pAdapter->Next;
- }
-
- while ( !done )
- {
- pAdapter = pAdapterInfo;
- err = kUnknownErr;
-
- while (pAdapter)
- {
- // If we don't have an interface selected, choose the first one that is of type ethernet and
- // has a valid IP Address
-
- if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
- {
- *address = inet_addr( pAdapter->IpAddressList.IpAddress.String );
- *ifIndex = pAdapter->Index;
- err = kNoErr;
- break;
- }
-
- pAdapter = pAdapter->Next;
- }
-
- // If we found the right interface, or we weren't trying to find a specific interface then we're done
-
- if ( !err || !( *ifIndex) )
- {
- done = mDNStrue;
- }
-
- // Otherwise, try again by wildcarding the interface
-
- else
- {
- *ifIndex = 0;
- }
- }
-
-exit:
-
- if ( pAdapterInfo != NULL )
- {
- free( pAdapterInfo );
- }
-
- 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;
-}
-
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef __MDNS_SERVICE_H__
-#define __MDNS_SERVICE_H__
-
-
-#include <windows.h>
-
-
-extern int RunDirect( int argc, LPTSTR argv[] );
-extern int Main( int argc, LPTSTR argv[] );
-
-
-#endif
-
+++ /dev/null
-// 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"
-#include "EventLog.rc"
-/////////////////////////////////////////////////////////////////////////////
-#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
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// 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 0x1L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", MASTER_COMPANY_NAME
- VALUE "FileDescription", "Bonjour Service"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "mDNSResponder.exe"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "mDNSResponder.exe"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
- "resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
- "#include ""winres.h""\r\n"
- "#include ""WinVersRes.h""\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE
-BEGIN
- IDS_SERVICE_DESCRIPTION "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence, so that users can discover and use those services without any unnecessary manual setup or administration."
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="mDNSResponder"\r
- ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"\r
- RootNamespace="mDNSResponder"\r
- Keyword="Win32Proj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;"$(VCInstallDir)include";"$(VCInstallDir)atlmfc\include";"C:/Program Files/Microsoft SDKs/Windows/v6.1/Include""\r
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="""";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- DisableSpecificWarnings="4127;4201"\r
- ShowIncludes="false"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
- OutputFile="$(OutDir)/mDNSResponder.exe"\r
- LinkIncremental="2"\r
- IgnoreAllDefaultLibraries="false"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"\r
- SubSystem="1"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\mDNSResponder.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;"$(VCInstallDir)include";"$(VCInstallDir)atlmfc\include";"C:/Program Files/Microsoft SDKs/Windows/v6.1/Include""\r
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="""";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- DisableSpecificWarnings="4127;4201"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
- OutputFile="$(OutDir)/mDNSResponder.exe"\r
- LinkIncremental="2"\r
- IgnoreAllDefaultLibraries="false"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"\r
- SubSystem="1"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\mDNSResponder64.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;"$(VCInstallDir)include";"$(VCInstallDir)atlmfc\include";"C:/Program Files/Microsoft SDKs/Windows/v6.1/Include""\r
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="""";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- DisableSpecificWarnings="4127;4201"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
- OutputFile="$(OutDir)/mDNSResponder.exe"\r
- LinkIncremental="1"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
- SubSystem="1"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\mDNSResponder.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)"
if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"
if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)"
xcopy /I/Y "$(TargetDir)$(TargetName).pdb" "$(DSTROOT)\AppleInternal\bin"
:END
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="1"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;"$(VCInstallDir)include";"$(VCInstallDir)atlmfc\include";"C:/Program Files/Microsoft SDKs/Windows/v6.1/Include""\r
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="""";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- DisableSpecificWarnings="4127;4201"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="ws2_32.lib iphlpapi.lib netapi32.lib powrprof.lib"\r
- OutputFile="$(OutDir)/mDNSResponder.exe"\r
- LinkIncremental="1"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
- SubSystem="1"\r
- OptimizeReferences="2"\r
- EnableCOMDATFolding="2"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- AdditionalManifestFiles="res\mDNSResponder64.manifest"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- CommandLine="if not "%RC_XBS%" == "YES" goto END
if not exist "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)"
if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"
if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"
xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(PlatformName)"
xcopy /I/Y "$(TargetDir)$(TargetName).pdb" "$(DSTROOT)\AppleInternal\bin"
:END
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\DNSCommon.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\DNSDigest.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dnssd_ipc.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\EventLog.mc"\r
- >\r
- <FileConfiguration\r
- Name="Debug|Win32"\r
- >\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- Description="Compiling Message Resource"\r
- CommandLine="mc.exe EventLog.mc"\r
- Outputs="EventLog.rc EventLog.h"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Debug|x64"\r
- >\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- Description="Compiling Message Resource"\r
- CommandLine="mc.exe EventLog.mc"\r
- Outputs="EventLog.rc EventLog.h"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|Win32"\r
- >\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- Description="Compiling Message Resource"\r
- CommandLine="mc.exe EventLog.mc"\r
- Outputs="EventLog.rc EventLog.h"\r
- />\r
- </FileConfiguration>\r
- <FileConfiguration\r
- Name="Release|x64"\r
- >\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- Description="Compiling Message Resource"\r
- CommandLine="mc.exe EventLog.mc"\r
- Outputs="EventLog.rc EventLog.h"\r
- />\r
- </FileConfiguration>\r
- </File>\r
- <File\r
- RelativePath="Firewall.cpp"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\GenLinkedList.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSMacOSX\LegacyNATTraversal.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\main.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\mDNS.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\mDNSDebug.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\mDNSWin32.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Poll.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Secret.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\Service.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\uDNS.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\uds_daemon.c"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\DNSCommon.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\dnssd_ipc.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\GenLinkedList.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\mDNSDebug.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\mDNSEmbeddedAPI.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\mDNSWin32.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Poll.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\Resource.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\Secret.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\Service.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSCore\uDNS.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\uds_daemon.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- <File\r
- RelativePath=".\Service.rc"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectName>mDNSResponder</ProjectName>\r
- <ProjectGuid>{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}</ProjectGuid>\r
- <RootNamespace>mDNSResponder</RootNamespace>\r
- <Keyword>Win32Proj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>Application</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- <ShowIncludes>false</ShowIncludes>\r
- <PrecompiledHeaderFile>\r
- </PrecompiledHeaderFile>\r
- <PrecompiledHeaderOutputFile>\r
- </PrecompiledHeaderOutputFile>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;crypt32.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
- <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)mDNSResponder.pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\mDNSResponder.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;crypt32.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
- <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)mDNSResponder.pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\mDNSResponder64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;crypt32.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\mDNSResponder.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetDir)$(TargetName).pdb" "$(DSTROOT)\AppleInternal\bin"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Console</SubSystem>\r
- <OptimizeReferences>true</OptimizeReferences>\r
- <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
- </Link>\r
- <Manifest>\r
- <AdditionalManifestFiles>res\mDNSResponder64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
- </Manifest>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-if not exist "$(DSTROOT)\AppleInternal" mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin" mkdir "$(DSTROOT)\AppleInternal\bin"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetDir)$(TargetName).pdb" "$(DSTROOT)\AppleInternal\bin"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\mDNSCore\anonymous.c" />\r
- <ClCompile Include="..\..\mDNSCore\CryptoAlg.c" />\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
- <ClCompile Include="..\..\mDNSCore\DNSCommon.c" />\r
- <ClCompile Include="..\..\mDNSCore\DNSDigest.c" />\r
- <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c" />\r
- <ClCompile Include="Firewall.cpp" />\r
- <ClCompile Include="..\..\mDNSShared\GenLinkedList.c" />\r
- <ClCompile Include="..\..\mDNSMacOSX\LegacyNATTraversal.c" />\r
- <ClCompile Include="main.c" />\r
- <ClCompile Include="..\..\mDNSCore\mDNS.c" />\r
- <ClCompile Include="..\..\mDNSShared\mDNSDebug.c" />\r
- <ClCompile Include="..\mDNSWin32.c" />\r
- <ClCompile Include="..\Poll.c" />\r
- <ClCompile Include="..\Secret.c" />\r
- <ClCompile Include="Service.c" />\r
- <ClCompile Include="..\..\mDNSCore\uDNS.c" />\r
- <ClCompile Include="..\..\mDNSShared\uds_daemon.c" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <CustomBuild Include="EventLog.mc">\r
- <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling Message Resource</Message>\r
- <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc.exe EventLog.mc</Command>\r
- <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
- <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling Message Resource</Message>\r
- <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc.exe EventLog.mc</Command>\r
- <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
- <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling Message Resource</Message>\r
- <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc.exe EventLog.mc</Command>\r
- <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
- <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling Message Resource</Message>\r
- <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc.exe EventLog.mc</Command>\r
- <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
- </CustomBuild>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\mDNSCore\anonymous.h" />\r
- <ClInclude Include="..\..\mDNSCore\CryptoAlg.h" />\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
- <ClInclude Include="..\..\mDNSCore\DNSCommon.h" />\r
- <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h" />\r
- <ClInclude Include="..\..\mDNSShared\GenLinkedList.h" />\r
- <ClInclude Include="..\..\mDNSCore\mDNSDebug.h" />\r
- <ClInclude Include="..\..\mDNSCore\mDNSEmbeddedAPI.h" />\r
- <ClInclude Include="..\mDNSWin32.h" />\r
- <ClInclude Include="..\Poll.h" />\r
- <ClInclude Include="Resource.h" />\r
- <ClInclude Include="..\Secret.h" />\r
- <ClInclude Include="Service.h" />\r
- <ClInclude Include="..\..\mDNSCore\uDNS.h" />\r
- <ClInclude Include="..\..\mDNSShared\uds_daemon.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="Service.rc" />\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
- <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSCore\DNSCommon.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSCore\DNSDigest.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="Firewall.cpp">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\GenLinkedList.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSMacOSX\LegacyNATTraversal.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="main.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSCore\mDNS.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\mDNSDebug.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\mDNSWin32.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\Poll.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\Secret.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="Service.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSCore\uDNS.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\uds_daemon.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSCore\anonymous.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSCore\CryptoAlg.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSCore\DNSCommon.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\GenLinkedList.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSCore\mDNSDebug.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSCore\mDNSEmbeddedAPI.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\mDNSWin32.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\Poll.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="Resource.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\Secret.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="Service.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSCore\uDNS.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\uds_daemon.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSCore\anonymous.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSCore\CryptoAlg.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="Service.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <CustomBuild Include="EventLog.mc">\r
- <Filter>Source Files</Filter>\r
- </CustomBuild>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Service.h"
-
-
-//===========================================================================================================================
-// main
-//===========================================================================================================================
-#if defined(UNICODE)
-int __cdecl wmain( int argc, wchar_t * argv[] )
-#else
-int __cdecl main( int argc, char *argv[] )
-#endif
-{
- return Main( argc, argv );
-}
-
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.mDNSResponder" type="win32"/>
- <description>Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network.</description>
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
- </requestedPrivileges>
- </security>
- </trustInfo>
-</assembly>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
- <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
- <description>Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network.</description>
- <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
- </requestedPrivileges>
- </security>
- </trustInfo>
-</assembly>
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Service.rc
-//
-
-#define IDS_SERVICE_DESCRIPTION 100
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 101
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1000
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Service.rc
-//
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 101
-#define _APS_NEXT_COMMAND_VALUE 40001
-#define _APS_NEXT_CONTROL_VALUE 1000
-#define _APS_NEXT_SYMED_VALUE 101
-#endif
-#endif
+++ /dev/null
-/* -*- 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.
- */
-
-#define _WIN32_DCOM
-#include "VPCDetect.h"
-#include "DebugServices.h"
-#include <comdef.h>
-#include <Wbemidl.h>
-
-# pragma comment(lib, "wbemuuid.lib")
-
-static BOOL g_doneCheck = FALSE;
-static BOOL g_isVPC = FALSE;
-
-
-mStatus
-IsVPCRunning( BOOL * inVirtualPC )
-{
- IWbemLocator * pLoc = 0;
- IWbemServices * pSvc = 0;
- IEnumWbemClassObject * pEnumerator = NULL;
- bool coInit = false;
- HRESULT hres;
- SC_HANDLE scm = NULL;
- SC_HANDLE service = NULL;
- SERVICE_STATUS status;
- mStatus err;
- BOOL ok = TRUE;
-
- // Initialize flag
-
- *inVirtualPC = FALSE;
-
- // Find out if WMI is running
-
- scm = OpenSCManager( 0, 0, SC_MANAGER_CONNECT );
- err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
- require_noerr( err, exit );
-
- service = OpenService( scm, TEXT( "winmgmt" ), SERVICE_QUERY_STATUS );
- err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
- require_noerr( err, exit );
-
- ok = QueryServiceStatus( service, &status );
- err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
- require_noerr( err, exit );
- require_action( status.dwCurrentState == SERVICE_RUNNING, exit, err = kUnknownErr );
-
- // Initialize COM.
-
- hres = CoInitializeEx(0, COINIT_MULTITHREADED);
- require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
- coInit = true;
-
- // Initialize Security
-
- hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL );
- require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
-
-
- // Obtain the initial locator to Windows Management on a particular host computer.
-
- hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc );
- require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
-
- // Connect to the root\cimv2 namespace with the
- // current user and obtain pointer pSvc
- // to make IWbemServices calls.
-
- hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, WBEM_FLAG_CONNECT_USE_MAX_WAIT, 0, 0, &pSvc );
- require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
-
- // Set the IWbemServices proxy so that impersonation
- // of the user (client) occurs.
-
- hres = CoSetProxyBlanket( pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );
- require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
-
- // Use the IWbemServices pointer to make requests of WMI.
- // Make requests here:
-
- hres = pSvc->ExecQuery( bstr_t("WQL"), bstr_t("SELECT * from Win32_BaseBoard"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
-
- require_action( SUCCEEDED( hres ), exit, err = kUnknownErr );
-
- do
- {
- IWbemClassObject* pInstance = NULL;
- ULONG dwCount = NULL;
-
- hres = pEnumerator->Next( WBEM_INFINITE, 1, &pInstance, &dwCount);
-
- if ( pInstance )
- {
- VARIANT v;
- BSTR strClassProp = SysAllocString(L"Manufacturer");
- HRESULT hr;
-
- hr = pInstance->Get(strClassProp, 0, &v, 0, 0);
- SysFreeString(strClassProp);
-
- // check the HRESULT to see if the action succeeded.
-
- if (SUCCEEDED(hr) && (V_VT(&v) == VT_BSTR))
- {
- wchar_t * wstring = wcslwr( V_BSTR( &v ) );
-
- if (wcscmp( wstring, L"microsoft corporation" ) == 0 )
- {
- *inVirtualPC = TRUE;
- }
- }
-
- VariantClear(&v);
- }
- } while (hres == WBEM_S_NO_ERROR);
-
-exit:
-
- if ( pSvc != NULL )
- {
- pSvc->Release();
- }
-
- if ( pLoc != NULL )
- {
- pLoc->Release();
- }
-
- if ( coInit )
- {
- CoUninitialize();
- }
-
- if ( service )
- {
- CloseServiceHandle( service );
- }
-
- if ( scm )
- {
- CloseServiceHandle( scm );
- }
-
- if ( *inVirtualPC )
- {
- dlog( kDebugLevelTrace, "Virtual PC detected" );
- }
-
- return err;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#pragma once
-
-#include <windows.h>
-#include <mDNSEmbeddedAPI.h>
-
-
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
-
-
-extern mStatus
-IsVPCRunning( BOOL * inVirtualPC );
-
-
-#if defined(__cplusplus)
-}
-#endif
+++ /dev/null
-/* -*- 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.
- */
-
-#include "WinServices.h"
-#include <DebugServices.h>
-
-
-//===========================================================================================================================
-// UTF8StringToStringObject
-//===========================================================================================================================
-
-OSStatus UTF8StringToStringObject( const char *inUTF8, CString &inObject )
-{
- OSStatus err;
- int n;
- BSTR unicode;
-
- unicode = NULL;
-
- n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
- if( n > 0 )
- {
- unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
- if( !unicode )
- {
- err = ERROR_INSUFFICIENT_BUFFER;
- goto exit;
- }
-
- n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
- try
- {
- inObject = unicode;
- }
- catch( ... )
- {
- err = ERROR_NO_UNICODE_TRANSLATION;
- goto exit;
- }
- }
- else
- {
- inObject = "";
- }
- err = ERROR_SUCCESS;
-
-exit:
- if( unicode )
- {
- free( unicode );
- }
- 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;
-}
+++ /dev/null
-/* -*- 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.
- */
-
-
-#pragma once
-
-#include <afxwin.h> // MFC core and standard components
-#include <afxext.h> // MFC extensions
-#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-# include <afxcmn.h> // MFC support for Windows Common Controls
-#endif
-
-#include <winsock2.h>
-#include <afxsock.h> // MFC socket extensions
-#include "CommonServices.h"
-
-
-OSStatus UTF8StringToStringObject( const char *inUTF8, CString &outObject );
-OSStatus StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len );
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 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.
- */
-
-#ifndef WINRESVERS_H
-#define WINRESVERS_H
-
-#define MASTER_PROD_NAME "Bonjour"
-
-// Define the company name for mDNSResponder on Windows
-#define MASTER_COMPANY_NAME "Apple Inc."
-
-// Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS 3,1,0,2
-#define MASTER_PROD_VERS_STR "3,1,0,2"
-#define MASTER_PROD_VERS_STR2 "3.1.0.2"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 3.1.0.2"
-
-// Define the legal copyright
-#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2011 Apple Inc."
-
-#endif // WINRESVERS_H
+++ /dev/null
-/* -*- 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.
- */
-
-/* isocode.h */
-/* ----------------------------------------------------------------------*/
-/* THIS FILE HAS BEEN AUTO-GENERATED. DO NOT EDIT DIRECTLY */
-/* If a language needs to be added, edit isocode.txt, and run isocode.pl */
-/* to generate a new version of this file */
-/* ----------------------------------------------------------------------*/
-/* ----------------------------------------------------------------------*/
-
-
-unsigned char ISOCODES[] = {
-12, 9, 'e','n', 0 , 0 , 0 , 0 ,
-40, 9, 'e','n', 0 , 0 , 0 , 0 ,
-16, 9, 'e','n', 0 , 0 , 0 , 0 ,
-36, 9, 'e','n', 0 , 0 , 0 , 0 ,
-24, 9, 'e','n', 0 , 0 , 0 , 0 ,
-32, 9, 'e','n', 0 , 0 , 0 , 0 ,
-20, 9, 'e','n', 0 , 0 , 0 , 0 ,
-52, 9, 'e','n', 0 , 0 , 0 , 0 ,
-28, 9, 'e','n', 0 , 0 , 0 , 0 ,
-44, 9, 'e','n', 0 , 0 , 0 , 0 ,
-8, 9, 'e','n', 0 , 0 , 0 , 0 ,
-4, 9, 'e','n', 0 , 0 , 0 , 0 ,
-48, 9, 'e','n', 0 , 0 , 0 , 0 ,
-8, 12, 'f','r', 0 , 0 , 0 , 0 ,
-44, 12, 'f','r', 0 , 0 , 0 , 0 ,
-12, 12, 'f','r', 0 , 0 , 0 , 0 ,
-36, 12, 'f','r', 0 , 0 , 0 , 0 ,
-48, 12, 'f','r', 0 , 0 , 0 , 0 ,
-4, 12, 'f','r', 0 , 0 , 0 , 0 ,
-20, 12, 'f','r', 0 , 0 , 0 , 0 ,
-52, 12, 'f','r', 0 , 0 , 0 , 0 ,
-24, 12, 'f','r', 0 , 0 , 0 , 0 ,
-40, 12, 'f','r', 0 , 0 , 0 , 0 ,
-16, 12, 'f','r', 0 , 0 , 0 , 0 ,
-28, 12, 'f','r', 0 , 0 , 0 , 0 ,
-4, 98, 'f','r', 0 , 0 , 0 , 0 ,
-12, 7, 'd','e', 0 , 0 , 0 , 0 ,
-4, 7, 'd','e', 0 , 0 , 0 , 0 ,
-20, 7, 'd','e', 0 , 0 , 0 , 0 ,
-16, 7, 'd','e', 0 , 0 , 0 , 0 ,
-8, 7, 'd','e', 0 , 0 , 0 , 0 ,
-4, 17, 'j','a', 0 , 0 , 0 , 0 ,
-8, 19, 'n','l', 0 , 0 , 0 , 0 ,
-4, 19, 'n','l', 0 , 0 , 0 , 0 ,
-4, 16, 'i','t', 0 , 0 , 0 , 0 ,
-8, 16, 'i','t', 0 , 0 , 0 , 0 ,
-44, 10, 'e','s', 0 , 0 , 0 , 0 ,
-64, 10, 'e','s', 0 , 0 , 0 , 0 ,
-52, 10, 'e','s', 0 , 0 , 0 , 0 ,
-36, 10, 'e','s', 0 , 0 , 0 , 0 ,
-20, 10, 'e','s', 0 , 0 , 0 , 0 ,
-28, 10, 'e','s', 0 , 0 , 0 , 0 ,
-48, 10, 'e','s', 0 , 0 , 0 , 0 ,
-68, 10, 'e','s', 0 , 0 , 0 , 0 ,
-16, 10, 'e','s', 0 , 0 , 0 , 0 ,
-72, 10, 'e','s', 0 , 0 , 0 , 0 ,
-12, 10, 'e','s', 0 , 0 , 0 , 0 ,
-8, 10, 'e','s', 0 , 0 , 0 , 0 ,
-76, 10, 'e','s', 0 , 0 , 0 , 0 ,
-24, 10, 'e','s', 0 , 0 , 0 , 0 ,
-60, 10, 'e','s', 0 , 0 , 0 , 0 ,
-40, 10, 'e','s', 0 , 0 , 0 , 0 ,
-80, 10, 'e','s', 0 , 0 , 0 , 0 ,
-4, 10, 'e','s', 0 , 0 , 0 , 0 ,
-56, 10, 'e','s', 0 , 0 , 0 , 0 ,
-32, 10, 'e','s', 0 , 0 , 0 , 0 ,
-8, 4, 'z','h','_','C','N', 0 ,
-16, 4, 'z','h','_','C','N', 0 ,
-12, 4, 'z','h','_','T','W', 0 ,
-20, 4, 'z','h','_','T','W', 0 ,
-4, 4, 'z','h','_','T','W', 0 ,
-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','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 ,
-20, 1, 'a','r', 0 , 0 , 0 , 0 ,
-60, 1, 'a','r', 0 , 0 , 0 , 0 ,
-12, 1, 'a','r', 0 , 0 , 0 , 0 ,
-8, 1, 'a','r', 0 , 0 , 0 , 0 ,
-44, 1, 'a','r', 0 , 0 , 0 , 0 ,
-52, 1, 'a','r', 0 , 0 , 0 , 0 ,
-48, 1, 'a','r', 0 , 0 , 0 , 0 ,
-16, 1, 'a','r', 0 , 0 , 0 , 0 ,
-24, 1, 'a','r', 0 , 0 , 0 , 0 ,
-32, 1, 'a','r', 0 , 0 , 0 , 0 ,
-64, 1, 'a','r', 0 , 0 , 0 , 0 ,
-4, 1, 'a','r', 0 , 0 , 0 , 0 ,
-40, 1, 'a','r', 0 , 0 , 0 , 0 ,
-28, 1, 'a','r', 0 , 0 , 0 , 0 ,
-56, 1, 'a','r', 0 , 0 , 0 , 0 ,
-36, 1, 'a','r', 0 , 0 , 0 , 0 ,
-4, 2, 'b','g', 0 , 0 , 0 , 0 ,
-4, 26, 'h','r', 0 , 0 , 0 , 0 ,
-4, 5, 'c','s', 0 , 0 , 0 , 0 ,
-4, 8, 'e','l', 0 , 0 , 0 , 0 ,
-4, 13, 'i','w', 0 , 0 , 0 , 0 ,
-4, 14, 'h','u', 0 , 0 , 0 , 0 ,
-4, 15, 'i','s', 0 , 0 , 0 , 0 ,
-4, 21, 'p','l', 0 , 0 , 0 , 0 ,
-8, 22, 'p','t','_','P','T', 0 ,
-4, 24, 'r','o', 0 , 0 , 0 , 0 ,
-8, 24, 'r','o', 0 , 0 , 0 , 0 ,
-4, 25, 'r','u', 0 , 0 , 0 , 0 ,
-8, 25, 'r','u', 0 , 0 , 0 , 0 ,
-4, 30, 't','h', 0 , 0 , 0 , 0 ,
-4, 31, 't','r', 0 , 0 , 0 , 0 ,
-4, 34, 'u','k', 0 , 0 , 0 , 0 ,
-};
-
-#define NUM_ISOCODES 101
-#define LANG_CODE_LEN 5
-#define MODULO_ISOCODES 8
-
-
+++ /dev/null
-/* -*- 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.
- */
-
-/* loclibrary.c
- * ----------------------------------------------------------------------
- * Source for localization library
- * Originally created by jsantamaria: 3 may 2004
- * ----------------------------------------------------------------------
- */
-
-#include "DebugServices.h"
-#include <windows.h>
-#include <stdio.h>
-#include "isocode.h"
-#include "loclibrary.h"
-#include "Shlwapi.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <wchar.h>
-
-
-#ifdef __cplusplus
-extern "c" {
-#endif
-
-#ifdef _MSC_VER
-#define swprintf _snwprintf
-#define snprintf _snprintf
-#endif
-
-
-
-#define DEFAULT_LANG_CODE "en"
-
-// gets the user language
-static LANGID _getUserLanguage( void ) {
-
- return GetUserDefaultUILanguage();
-
-}
-
-
-// gets the ISO mapping
-static int _getISOCode(LANGID wLangID, char *isoLangCode, int codeLen) {
- int i;
- unsigned short langCode;
-
- for (i = 0; i < NUM_ISOCODES; i++) {
- int startIndex = i * MODULO_ISOCODES;
-
- langCode = (ISOCODES[startIndex] << 8);
- langCode = langCode + ( (unsigned short) (ISOCODES[startIndex + 1]) );
-
- if (langCode == wLangID) {
- char *langStr = (char *)&(ISOCODES[startIndex+2]);
- strncpy(isoLangCode, langStr, codeLen);
- return 0;
- }
- }
- return 1;
-}
-
-static char isoLangCode[LANG_CODE_LEN + 1] = "";
-static LANGID wLangID = (LANGID) -1;
-
-static void _setLanguageIfNeeded(void) {
-
- // get the language code if we don't have it cached
- if (!strncmp(isoLangCode,"",LANG_CODE_LEN + 1)) {
-
- // if we haven't cached the language id, do the lookup
- if (wLangID == (LANGID) -1) {
- wLangID = _getUserLanguage();
- }
-
- // if no ISOCode, set it to DEFAULT_LANG_CODE
- if (_getISOCode(wLangID, isoLangCode, LANG_CODE_LEN + 1)) {
- strncpy(isoLangCode, DEFAULT_LANG_CODE, LANG_CODE_LEN+1);
- }
- }
-
-}
-
-//// PathForResource
-
-// Gets the PathForResource for handle 0 for the current process
-
-
-static char appPathNameA[MAX_PATH] = "";
-
-int PathForResourceA ( HMODULE module, const char *name, char *locFile, int locFileLen)
-{
- int ret = 0;
-
- if ( !strcmp( appPathNameA, "" ) )
- {
- char folder[MAX_PATH];
- char * ext;
- char * app;
-
- GetModuleFileNameA( module, folder, MAX_PATH );
-
- // Get folder string
-
- app = strrchr( folder, '\\' );
- require_action( app, exit, ret = 0 );
- *app++ = '\0';
-
- // Strip the extension
-
- if ( ( ( ext = strstr( app, ".exe" ) ) != NULL ) || ( ( ext = strstr( app, ".dll" ) ) != NULL ) )
- {
- *ext = '\0';
- }
-
- snprintf( appPathNameA, MAX_PATH, "%s\\%s", folder, app );
- }
-
- ret = PathForResourceWithPathA (appPathNameA, name, locFile, locFileLen);
-
-exit:
-
- return ret;
-}
-
-static wchar_t appPathNameW[MAX_PATH] = L"";
-
-int PathForResourceW ( HMODULE module, const wchar_t *name, wchar_t *locFile, int locFileLen)
-{
- int ret = 0;
-
- if ( !wcscmp( appPathNameW, L"" ) )
- {
- wchar_t folder[MAX_PATH];
- wchar_t * app;
- wchar_t * ext;
-
- GetModuleFileNameW( module, folder, MAX_PATH);
-
- // Get folder string
-
- app = wcsrchr( folder, '\\' );
- require_action( app, exit, ret = 0 );
- *app++ = '\0';
-
- // Strip the extension
-
- if ( ( ( ext = wcsstr( app, L".exe" ) ) != NULL ) || ( ( ext = wcsstr( app, L".dll" ) ) != NULL ) )
- {
- *ext = '\0';
- }
-
- swprintf( appPathNameW, MAX_PATH, L"%ls\\%ls", folder, app );
- }
-
- ret = PathForResourceWithPathW (appPathNameW, name, locFile, locFileLen);
-
-exit:
-
- return ret;
-}
-
-
-//// PathForResourceWithPath
-
-#define TMP_BUF_SIZE MAX_PATH
-
-int PathForResourceWithPathA (const char *path, const char *nm,
- char *locFile, int locFileLen) {
- char tmpBuffer[TMP_BUF_SIZE];
-
- // build the path to the executable in the generic
- // resources folder, check there first
- snprintf(tmpBuffer, MAX_PATH, "%s.Resources\\%s", path, nm);
-
- if (!PathFileExistsA(tmpBuffer)) {
-
- // didn't hit generic resource folder, so need to get language codes
- _setLanguageIfNeeded();
-
- // test to see if localized directory exists,
- // if so, we don't fall back if we don't find the file.
- snprintf(tmpBuffer, TMP_BUF_SIZE,
- "%s.Resources\\%s.lproj", path, isoLangCode);
-
- if (PathFileExistsA(tmpBuffer)) {
- snprintf(tmpBuffer, TMP_BUF_SIZE, "%s\\%s", tmpBuffer, nm);
-
- if (!PathFileExistsA(tmpBuffer)) return 0;
-
- strncpy(locFile, tmpBuffer, locFileLen);
- return (int) strlen(locFile);
- }
-
- // fall back on DEFAULT_LANG_CODE if still no good
- snprintf(tmpBuffer, TMP_BUF_SIZE, "%s.Resources\\%s.lproj\\%s",
- path, DEFAULT_LANG_CODE, nm);
-
- // we can't find the resource, so return 0
- if (!PathFileExistsA(tmpBuffer)) return 0;
- }
-
- strncpy(locFile, tmpBuffer, locFileLen);
- return (int) strlen(locFile);
-
-}
-
-
-int PathForResourceWithPathW (const wchar_t *path, const wchar_t *nm,
- wchar_t *locFile, int locFileLen) {
-
- wchar_t tmpBuffer[TMP_BUF_SIZE];
-
- // build the path to the executable in the generic
- // resources folder, check there first
- swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls.Resources\\%ls", path, nm);
-
- if (!PathFileExistsW(tmpBuffer)) {
- // didn't hit generic resource folder, so need to get language codes
- _setLanguageIfNeeded();
-
- // test to see if localized directory exists,
- // if so, we don't fall back if we don't find the file.
- swprintf(tmpBuffer, TMP_BUF_SIZE,
- L"%ls.Resources\\%S.lproj", path, isoLangCode);
-
- if (PathFileExistsW(tmpBuffer)) {
- swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls\\%ls", tmpBuffer, nm);
-
- if (!PathFileExistsW(tmpBuffer)) return 0;
-
- wcsncpy(locFile, tmpBuffer, locFileLen);
- return (int) wcslen(locFile);
- }
-
- // fall back on DEFAULT_LANG_CODE if still no good
- swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls.Resources\\%S.lproj\\%ls",
- path, DEFAULT_LANG_CODE, nm);
-
- // we can't find the resource, so return 0
- if (!PathFileExistsW(tmpBuffer)) return 0;
- }
-
- wcsncpy(locFile, tmpBuffer, locFileLen);
- return (int) wcslen(locFile);
-
-
-}
-
-
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-/* -*- 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.
- */
-
-/* loclibrary.h
- * ----------------------------------------------------------------------
- * Header file for localization library
- * Originally created by jsantamaria: 3 may 2004
- * ----------------------------------------------------------------------
- */
-
-#ifndef _loclibrary_h_
-#define _loclibrary_h_
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-int PathForResourceW ( HMODULE module, const wchar_t *name, wchar_t *locFile, int locFileLen);
-int PathForResourceWithPathW ( const wchar_t *path, const wchar_t *name, wchar_t *locFile, int locFileLen);
-
-int PathForResourceA ( HMODULE module, const char *name, char *locFile, int locFileLen);
-int PathForResourceWithPathA ( const char *path, const char *name, char *locFile, int locFileLen);
-
-
-#ifdef UNICODE
-#define PathForResource PathForResourceW
-#define PathForResourceWithPath PathForResourceWithPathW
-#else
-#define PathForResource PathForResourceA
-#define PathForResourceWithPath PathForResourceWithPathA
-#endif // UNICODE
-
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-
-#endif // _loclibrary_h_
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013, 2015 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.
-
- To Do:
-
- - Get unicode name of machine for nice name instead of just the host name.
- - Use the IPv6 Internet Connection Firewall API to allow IPv6 mDNS without manually changing the firewall.
- - Get DNS server address(es) from Windows and provide them to the uDNS layer.
- - Implement TCP support for truncated packets (only stubs now).
-
-*/
-
-#define _CRT_RAND_S
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <crtdbg.h>
-#include <string.h>
-
-#include "Poll.h"
-#include "CommonServices.h"
-#include "DebugServices.h"
-#include "Firewall.h"
-#include "RegNames.h"
-#include "Secret.h"
-#include <dns_sd.h>
-
-#include <Iphlpapi.h>
-#include <mswsock.h>
-#include <process.h>
-#include <ntsecapi.h>
-#include <lm.h>
-#include <winioctl.h>
-#include <ntddndis.h> // This defines the IOCTL constants.
-
-#include "mDNSEmbeddedAPI.h"
-#include "GenLinkedList.h"
-#include "DNSCommon.h"
-#include "mDNSWin32.h"
-#include "dnssec.h"
-#include "nsec.h"
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-// Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME "[mDNSWin32] "
-
-#define MDNS_WINDOWS_USE_IPV6_IF_ADDRS 1
-#define MDNS_WINDOWS_ENABLE_IPV4 1
-#define MDNS_WINDOWS_ENABLE_IPV6 1
-#define MDNS_FIX_IPHLPAPI_PREFIX_BUG 1
-#define MDNS_SET_HINFO_STRINGS 0
-
-#define kMDNSDefaultName "My Computer"
-
-#define kWinSockMajorMin 2
-#define kWinSockMinorMin 2
-
-#define kRegistryMaxKeyLength 255
-#define kRegistryMaxValueName 16383
-
-static GUID kWSARecvMsgGUID = WSAID_WSARECVMSG;
-
-#define kIPv6IfIndexBase (10000000L)
-#define SMBPortAsNumber 445
-#define DEVICE_PREFIX "\\\\.\\"
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupNiceName( mDNS * const inMDNS );
-mDNSlocal mStatus SetupHostName( mDNS * const inMDNS );
-mDNSlocal mStatus SetupName( mDNS * const inMDNS );
-mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
-mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
-mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD );
-mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef );
-mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
-mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
-mDNSlocal int getifaddrs( struct ifaddrs **outAddrs );
-mDNSlocal void freeifaddrs( struct ifaddrs *inAddrs );
-
-
-// Platform Accessors
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-typedef struct mDNSPlatformInterfaceInfo mDNSPlatformInterfaceInfo;
-struct mDNSPlatformInterfaceInfo
-{
- const char * name;
- mDNSAddr ip;
-};
-
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
-
-
-// Wakeup Structs
-
-#define kMulticastWakeupNumTries ( 18 )
-#define kMulticastWakeupSleepBetweenTries ( 100 )
-
-typedef struct MulticastWakeupStruct
-{
- mDNS *inMDNS;
- struct sockaddr_in addr;
- INT addrLen;
- unsigned char data[ 102 ];
- INT dataLen;
- INT numTries;
- INT msecSleep;
-} MulticastWakeupStruct;
-
-
-// Utilities
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
- mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs );
-#endif
-
-mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
-
-mDNSlocal DWORD GetPrimaryInterface();
-mDNSlocal mStatus AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
-mDNSlocal mDNSBool CanReceiveUnicast( void );
-mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
-
-mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string );
-mDNSlocal mStatus RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
-mDNSlocal struct ifaddrs* myGetIfAddrs(int refresh);
-mDNSlocal OSStatus TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal OSStatus WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal void CALLBACK TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-mDNSlocal void TCPCloseSocket( TCPSocket * socket );
-mDNSlocal void CALLBACK UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-mDNSlocal void UDPCloseSocket( UDPSocket * sock );
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
-mDNSlocal void GetDDNSFQDN( domainname *const fqdn );
-#ifdef UNICODE
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
-#else
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
-#endif
-mDNSlocal void SetDomainSecrets( mDNS * const inMDNS );
-mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain );
-mDNSlocal VOID CALLBACK CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
-mDNSlocal void CheckFileShares( mDNS * const inMDNS );
-mDNSlocal void SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-mDNSlocal mDNSu8 IsWOMPEnabledForAdapter( const char * adapterName );
-mDNSlocal void SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep );
-mDNSlocal void _cdecl SendMulticastWakeupPacket( void *arg );
-
-#ifdef __cplusplus
- }
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSs32 mDNSPlatformOneSecond = 0;
-mDNSlocal UDPSocket * gUDPSockets = NULL;
-mDNSlocal int gUDPNumSockets = 0;
-mDNSlocal BOOL gEnableIPv6 = TRUE;
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-
- typedef DWORD
- ( WINAPI * GetAdaptersAddressesFunctionPtr )(
- ULONG inFamily,
- DWORD inFlags,
- PVOID inReserved,
- PIP_ADAPTER_ADDRESSES inAdapter,
- PULONG outBufferSize );
-
- mDNSlocal HMODULE gIPHelperLibraryInstance = NULL;
- mDNSlocal GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
-
-#endif
-
-#ifndef HCRYPTPROV
- typedef ULONG_PTR HCRYPTPROV; // WinCrypt.h, line 249
-#endif
-
-#ifndef CRYPT_MACHINE_KEYSET
-# define CRYPT_MACHINE_KEYSET 0x00000020
-#endif
-
-#ifndef CRYPT_NEWKEYSET
-# define CRYPT_NEWKEYSET 0x00000008
-#endif
-
-#ifndef PROV_RSA_FULL
-# define PROV_RSA_FULL 1
-#endif
-
-typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* );
-typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
-typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
-
-static fnCryptAcquireContext g_lpCryptAcquireContext = NULL;
-static fnCryptReleaseContext g_lpCryptReleaseContext = NULL;
-static fnCryptGenRandom g_lpCryptGenRandom = NULL;
-static HINSTANCE g_hAAPI32 = NULL;
-static HCRYPTPROV g_hProvider = ( ULONG_PTR ) NULL;
-
-
-typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
- (
- DNSServiceRef *sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- const char *name, /* may be NULL */
- const char *regtype,
- const char *domain, /* may be NULL */
- const char *host, /* may be NULL */
- uint16_t port,
- uint16_t txtLen,
- const void *txtRecord, /* may be NULL */
- DNSServiceRegisterReply callBack, /* may be NULL */
- void *context /* may be NULL */
- );
-
-
-typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
-
-mDNSlocal HMODULE gDNSSDLibrary = NULL;
-mDNSlocal DNSServiceRegisterFunc gDNSServiceRegister = NULL;
-mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
-mDNSlocal HANDLE gSMBThread = NULL;
-mDNSlocal HANDLE gSMBThreadRegisterEvent = NULL;
-mDNSlocal HANDLE gSMBThreadDeregisterEvent = NULL;
-mDNSlocal HANDLE gSMBThreadStopEvent = NULL;
-mDNSlocal HANDLE gSMBThreadQuitEvent = NULL;
-
-#define kSMBStopEvent ( WAIT_OBJECT_0 + 0 )
-#define kSMBRegisterEvent ( WAIT_OBJECT_0 + 1 )
-#define kSMBDeregisterEvent ( WAIT_OBJECT_0 + 2 )
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Support ==
-#endif
-
-//===========================================================================================================================
-// mDNSPlatformInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
-{
- mStatus err;
- OSVERSIONINFO osInfo;
- BOOL ok;
- WSADATA wsaData;
- int supported;
- struct sockaddr_in sa4;
- struct sockaddr_in6 sa6;
- int sa4len;
- int sa6len;
- DWORD size;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
-
- // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is
- // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
-
- mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
- if( !inMDNS->p ) inMDNS->p = &gMDNSPlatformSupport;
- inMDNS->p->mainThread = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
- require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
- inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
- require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
- inMDNS->p->checkFileSharesTimeout = 10; // Retry time for CheckFileShares() in seconds
- mDNSPlatformOneSecond = 1000; // Use milliseconds as the quantum of time
-
- // Get OS version info
-
- osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
- ok = GetVersionEx( &osInfo );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
- inMDNS->p->osMajorVersion = osInfo.dwMajorVersion;
- inMDNS->p->osMinorVersion = osInfo.dwMinorVersion;
-
- // Don't enable IPv6 on anything less recent than Windows Vista
-
- if ( inMDNS->p->osMajorVersion < 6 )
- {
- gEnableIPv6 = FALSE;
- }
-
- // Startup WinSock 2.2 or later.
-
- err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
- require_noerr( err, exit );
-
- supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
- require_action( supported, exit, err = mStatus_UnsupportedErr );
-
- inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
-
- // Setup the HINFO HW strings.
- //<rdar://problem/7245119> device-info should have model=Windows
-
- strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
- inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
- dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
-
- // Setup the HINFO SW strings.
-#if ( MDNS_SET_HINFO_STRINGS )
- mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2,
- "mDNSResponder (%s %s)", __DATE__, __TIME__ );
- inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
- dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
-#endif
-
- // Set up the IPv4 unicast socket
-
- inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
- inMDNS->p->unicastSock4.recvMsgPtr = NULL;
- inMDNS->p->unicastSock4.ifd = NULL;
- inMDNS->p->unicastSock4.next = NULL;
- inMDNS->p->unicastSock4.m = inMDNS;
-
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-
- sa4.sin_family = AF_INET;
- sa4.sin_addr.s_addr = INADDR_ANY;
- err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
- check_noerr( err );
- sa4len = sizeof( sa4 );
- err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
- require_noerr( err, exit );
- inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
- inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
- err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
-
- if ( err )
- {
- inMDNS->p->unicastSock4.recvMsgPtr = NULL;
- }
-
- err = mDNSPollRegisterSocket( inMDNS->p->unicastSock4.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock4 );
- require_noerr( err, exit );
-
-#endif
-
- // Set up the IPv6 unicast socket
-
- inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
- inMDNS->p->unicastSock6.recvMsgPtr = NULL;
- inMDNS->p->unicastSock6.ifd = NULL;
- inMDNS->p->unicastSock6.next = NULL;
- inMDNS->p->unicastSock6.m = inMDNS;
-
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- sa6.sin6_family = AF_INET6;
- sa6.sin6_addr = in6addr_any;
- sa6.sin6_scope_id = 0;
-
- // This call will fail if the machine hasn't installed IPv6. In that case,
- // the error will be WSAEAFNOSUPPORT.
-
- err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
- require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
- err = kNoErr;
-
- // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
-
- if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
- {
- sa6len = sizeof( sa6 );
- err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
- require_noerr( err, exit );
- inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
- inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
-
- err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
-
- if ( err != 0 )
- {
- inMDNS->p->unicastSock6.recvMsgPtr = NULL;
- }
-
- err = mDNSPollRegisterSocket( inMDNS->p->unicastSock6.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock6 );
- require_noerr( err, exit );
- }
- }
-
-#endif
-
- // Notify core of domain secret keys
-
- SetDomainSecrets( inMDNS );
-
- // Success!
-
- mDNSCoreInitComplete( inMDNS, err );
-
-
-exit:
-
- if ( err )
- {
- mDNSPlatformClose( inMDNS );
- }
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformClose
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformClose( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
- check( inMDNS );
-
- if ( gSMBThread != NULL )
- {
- dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
- SetEvent( gSMBThreadStopEvent );
-
- if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
- {
- if ( gSMBThreadQuitEvent )
- {
- CloseHandle( gSMBThreadQuitEvent );
- gSMBThreadQuitEvent = NULL;
- }
-
- if ( gSMBThreadStopEvent )
- {
- CloseHandle( gSMBThreadStopEvent );
- gSMBThreadStopEvent = NULL;
- }
-
- if ( gSMBThreadDeregisterEvent )
- {
- CloseHandle( gSMBThreadDeregisterEvent );
- gSMBThreadDeregisterEvent = NULL;
- }
-
- if ( gSMBThreadRegisterEvent )
- {
- CloseHandle( gSMBThreadRegisterEvent );
- gSMBThreadRegisterEvent = NULL;
- }
-
- if ( gDNSSDLibrary )
- {
- FreeLibrary( gDNSSDLibrary );
- gDNSSDLibrary = NULL;
- }
- }
- else
- {
- LogMsg( "Unable to stop SMBThread" );
- }
-
- inMDNS->p->smbFileSharing = mDNSfalse;
- inMDNS->p->smbPrintSharing = mDNSfalse;
- }
-
- // Tear everything down in reverse order to how it was set up.
-
- err = TearDownInterfaceList( inMDNS );
- check_noerr( err );
- check( !inMDNS->p->inactiveInterfaceList );
-
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-
- UDPCloseSocket( &inMDNS->p->unicastSock4 );
-
-#endif
-
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- UDPCloseSocket( &inMDNS->p->unicastSock6 );
- }
-
-#endif
-
- // Free the DLL needed for IPv6 support.
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
- if( gIPHelperLibraryInstance )
- {
- gGetAdaptersAddressesFunctionPtr = NULL;
-
- FreeLibrary( gIPHelperLibraryInstance );
- gIPHelperLibraryInstance = NULL;
- }
-#endif
-
- if ( g_hAAPI32 )
- {
- // Release any resources
-
- if ( g_hProvider && g_lpCryptReleaseContext )
- {
- ( g_lpCryptReleaseContext )( g_hProvider, 0 );
- }
-
- // Free the AdvApi32.dll
-
- FreeLibrary( g_hAAPI32 );
-
- // And reset all the data
-
- g_lpCryptAcquireContext = NULL;
- g_lpCryptReleaseContext = NULL;
- g_lpCryptGenRandom = NULL;
- g_hProvider = ( ULONG_PTR ) NULL;
- g_hAAPI32 = NULL;
- }
-
- WSACleanup();
-
- dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
-}
-
-//===========================================================================================================================
-// mDNSPlatformLock
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformLock( const mDNS * const inMDNS )
-{
- ( void ) inMDNS;
-}
-
-//===========================================================================================================================
-// mDNSPlatformUnlock
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
- ( void ) inMDNS;
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrCopy
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
- check( inSrc );
- check( inDst );
-
- strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrLCopy
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformStrLCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- const char * src = (const char *) inSrc;
-
- if( inSize > 0 )
- {
- size_t n;
- char * dst = (char *) inDst;
-
- for( n = inSize - 1; n > 0; --n )
- {
- if( ( *dst++ = *src++ ) == '\0' )
- {
- // Null terminator encountered, so exit.
- goto exit;
- }
- }
- *dst = '\0';
- }
-
- while( *src++ != '\0' )
- {
- // Stop at null terminator.
- }
-
-exit:
- return( (mDNSu32)( src - (const char *) inSrc ) - 1 );
-}
-
-//===========================================================================================================================
-// mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformStrLen( const void *inSrc )
-{
- check( inSrc );
-
- return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemCopy
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSexport mDNSBool mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemCmp
-//===========================================================================================================================
-
-mDNSexport int mDNSPlatformMemCmp( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
- check( inSrc );
- check( inDst );
-
- return( memcmp( inSrc, inDst, inSize ) );
-}
-
-mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
-{
- (void)base;
- (void)nel;
- (void)width;
- (void)compar;
-}
-
-// DNSSEC stub functions
-mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
- {
- (void)m;
- (void)dv;
- (void)q;
- }
-
-mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
- {
- (void)m;
- (void)crlist;
- (void)negcr;
- (void)rcode;
- return mDNSfalse;
- }
-
-mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
- {
- (void)m;
- (void)action;
- (void)type;
- (void)value;
- }
-
-// Proxy stub functions
-mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
-{
- (void) q;
- (void) h;
- (void) msg;
- (void) ptr;
- (void) limit;
-
- return ptr;
-}
-
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
-{
- (void) m;
- (void) IpIfArr;
- (void) OpIf;
-}
-
-mDNSexport void DNSProxyTerminate(mDNS *const m)
-{
- (void) m;
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemZero
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
- check( inDst );
-
- memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void * mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
- void * mem;
-
- check( inSize > 0 );
-
- mem = malloc( inSize );
- check( mem );
-
- return( mem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemFree( void *inMem )
-{
- check( inMem );
-
- free( inMem );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRandomNumber
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
-{
- unsigned int randomNumber;
- errno_t err;
-
- err = rand_s( &randomNumber );
- require_noerr( err, exit );
-
-exit:
-
- if ( err )
- {
- randomNumber = rand();
- }
-
- return ( mDNSu32 ) randomNumber;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTimeInit( void )
-{
- // No special setup is required on Windows -- we just use GetTickCount().
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSexport mDNSs32 mDNSPlatformRawTime( void )
-{
- return( (mDNSs32) GetTickCount() );
-}
-
-//===========================================================================================================================
-// mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32 mDNSPlatformUTC( void )
-{
- return ( mDNSs32 ) time( NULL );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
- mStatus err;
- mDNSInterfaceData * ifd;
-
- check( inMDNS );
- check( inMDNS->p );
- check( inName );
-
- // Search for an interface with the specified name,
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( strcmp( ifd->name, inName ) == 0 )
- {
- break;
- }
- }
- require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
-
- // Success!
-
- if( outID )
- {
- *outID = (mDNSInterfaceID) ifd;
- }
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
- mStatus err;
- mDNSInterfaceData * ifd;
-
- check( inMDNS );
- check( inID );
- check( outInfo );
-
- // Search for an interface with the specified ID,
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( ifd == (mDNSInterfaceData *) inID )
- {
- break;
- }
- }
- require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
-
- // Success!
-
- outInfo->name = ifd->name;
- outInfo->ip = ifd->interfaceInfo.ip;
- err = mStatus_NoError;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIDfromInterfaceIndex
-//===========================================================================================================================
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
-{
- mDNSInterfaceID id;
-
- id = mDNSNULL;
- if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
- {
- id = mDNSInterface_LocalOnly;
- }
- else if( inIndex != 0 )
- {
- mDNSInterfaceData * ifd;
-
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
- {
- id = ifd->interfaceInfo.InterfaceID;
- break;
- }
- }
- check( ifd );
- }
- return( id );
-}
-
-//===========================================================================================================================
-// mDNSPlatformInterfaceIndexfromInterfaceID
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSBool suppressNetworkChange )
-{
- mDNSu32 index;
-
- (void) suppressNetworkChange;
-
- index = 0;
- if( inID == mDNSInterface_LocalOnly )
- {
- index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
- }
- else if( inID )
- {
- mDNSInterfaceData * ifd;
-
- // Search active interfaces.
- for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
- {
- if( (mDNSInterfaceID) ifd == inID )
- {
- index = ifd->scopeID;
- break;
- }
- }
-
- // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
-
- if( !ifd )
- {
- for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
- {
- if( (mDNSInterfaceID) ifd == inID )
- {
- index = ifd->scopeID;
- break;
- }
- }
- }
- check( ifd );
- }
- return( index );
-}
-
-//===========================================================================================================================
-// mDNSPlatformTCPSocket
-//===========================================================================================================================
-
-TCPSocket *
-mDNSPlatformTCPSocket
- (
- mDNS * const m,
- TCPSocketFlags flags,
- mDNSIPPort * port,
- mDNSBool useBackgroundTrafficClass
- )
-{
- TCPSocket * sock = NULL;
- u_long on = 1; // "on" for setsockopt
- struct sockaddr_in saddr;
- int len;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( useBackgroundTrafficClass );
-
- require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
-
- // Setup connection data object
-
- sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
- mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
- sock->fd = INVALID_SOCKET;
- sock->flags = flags;
- sock->m = m;
-
- mDNSPlatformMemZero(&saddr, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = htonl( INADDR_ANY );
- saddr.sin_port = port->NotAnInteger;
-
- // Create the socket
-
- sock->fd = socket(AF_INET, SOCK_STREAM, 0);
- err = translate_errno( sock->fd != INVALID_SOCKET, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // bind
-
- err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // Set it to be non-blocking
-
- err = ioctlsocket( sock->fd, FIONBIO, &on );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- // Get port number
-
- mDNSPlatformMemZero( &saddr, sizeof( saddr ) );
- len = sizeof( saddr );
-
- err = getsockname( sock->fd, ( struct sockaddr* ) &saddr, &len );
- err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- port->NotAnInteger = saddr.sin_port;
-
-exit:
-
- if ( err && sock )
- {
- TCPCloseSocket( sock );
- free( sock );
- sock = mDNSNULL;
- }
-
- return sock;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTCPConnect
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformTCPConnect
- (
- TCPSocket * sock,
- const mDNSAddr * inDstIP,
- mDNSOpaque16 inDstPort,
- domainname * hostname,
- mDNSInterfaceID inInterfaceID,
- TCPConnectionCallback inCallback,
- void * inContext
- )
-{
- struct sockaddr_in saddr;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( hostname );
- DEBUG_UNUSED( inInterfaceID );
-
- if ( inDstIP->type != mDNSAddrType_IPv4 )
- {
- LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
- return mStatus_UnknownErr;
- }
-
- // Setup connection data object
-
- sock->userCallback = inCallback;
- sock->userContext = inContext;
-
- mDNSPlatformMemZero(&saddr, sizeof(saddr));
- saddr.sin_family = AF_INET;
- saddr.sin_port = inDstPort.NotAnInteger;
- memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
-
- // Try and do connect
-
- err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
- require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
- sock->connected = !err ? TRUE : FALSE;
-
- err = mDNSPollRegisterSocket( sock->fd, FD_CONNECT | FD_READ | FD_CLOSE, TCPSocketNotification, sock );
- require_noerr( err, exit );
-
-exit:
-
- if ( !err )
- {
- err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
- }
-
- return err;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTCPAccept
-//===========================================================================================================================
-
-mDNSexport TCPSocket *mDNSPlatformTCPAccept( TCPSocketFlags flags, int fd )
- {
- TCPSocket * sock = NULL;
- mStatus err = mStatus_NoError;
-
- require_action( !flags, exit, err = mStatus_UnsupportedErr );
-
- sock = malloc( sizeof( TCPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
-
- mDNSPlatformMemZero( sock, sizeof( *sock ) );
-
- sock->fd = fd;
- sock->flags = flags;
-
-exit:
-
- if ( err && sock )
- {
- free( sock );
- sock = NULL;
- }
-
- return sock;
- }
-
-//===========================================================================================================================
-// mDNSPlatformTCPCloseConnection
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
-{
- check( sock );
-
- if ( sock )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformTCPCloseConnection 0x%x:%d\n", sock, sock->fd );
-
- if ( sock->fd != INVALID_SOCKET )
- {
- mDNSPollUnregisterSocket( sock->fd );
- closesocket( sock->fd );
- sock->fd = INVALID_SOCKET;
- }
-
- free( sock );
- }
-}
-
-//===========================================================================================================================
-// mDNSPlatformReadTCP
-//===========================================================================================================================
-
-mDNSexport long mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
-{
- int nread;
- OSStatus err;
-
- *closed = mDNSfalse;
- nread = recv( sock->fd, inBuffer, inBufferSize, 0 );
- err = translate_errno( ( nread >= 0 ), WSAGetLastError(), mStatus_UnknownErr );
-
- if ( nread > 0 )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformReadTCP: 0x%x:%d read %d bytes\n", sock, sock->fd, nread );
- }
- else if ( !nread )
- {
- *closed = mDNStrue;
- }
- else if ( err == WSAECONNRESET )
- {
- *closed = mDNStrue;
- nread = 0;
- }
- else if ( err == WSAEWOULDBLOCK )
- {
- nread = 0;
- }
- else
- {
- LogMsg( "ERROR: mDNSPlatformReadTCP - recv: %d\n", err );
- nread = -1;
- }
-
- return nread;
-}
-
-//===========================================================================================================================
-// mDNSPlatformWriteTCP
-//===========================================================================================================================
-
-mDNSexport long mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
-{
- int nsent;
- OSStatus err;
-
- nsent = send( sock->fd, inMsg, inMsgSize, 0 );
-
- err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
- require_noerr( err, exit );
-
- if ( nsent < 0)
- {
- nsent = 0;
- }
-
-exit:
-
- return nsent;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTCPGetFD
-//===========================================================================================================================
-
-mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
-{
- return ( int ) sock->fd;
-}
-
-//===========================================================================================================================
-// TCPSocketNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
- TCPSocket *tcpSock = ( TCPSocket* ) context;
- TCPConnectionCallback callback;
- int err;
-
- DEBUG_UNUSED( sock );
-
- require_action( tcpSock, exit, err = mStatus_BadParamErr );
- callback = ( TCPConnectionCallback ) tcpSock->userCallback;
- require_action( callback, exit, err = mStatus_BadParamErr );
-
- if ( event && ( event->lNetworkEvents & FD_CONNECT ) )
- {
- if ( event->iErrorCode[ FD_CONNECT_BIT ] == 0 )
- {
- callback( tcpSock, tcpSock->userContext, mDNStrue, 0 );
- tcpSock->connected = mDNStrue;
- }
- else
- {
- callback( tcpSock, tcpSock->userContext, mDNSfalse, event->iErrorCode[ FD_CONNECT_BIT ] );
- }
- }
- else
- {
- callback( tcpSock, tcpSock->userContext, mDNSfalse, 0 );
- }
-
-exit:
-
- return;
-}
-
-//===========================================================================================================================
-// mDNSPlatformUDPSocket
-//===========================================================================================================================
-
-mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
-{
- UDPSocket* sock = NULL;
- mDNSIPPort port = requestedport;
- mStatus err = mStatus_NoError;
- unsigned i;
-
- // Setup connection data object
-
- sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
- require_action( sock, exit, err = mStatus_NoMemoryErr );
- memset( sock, 0, sizeof( UDPSocket ) );
-
- // Create the socket
-
- sock->fd = INVALID_SOCKET;
- sock->recvMsgPtr = m->p->unicastSock4.recvMsgPtr;
- sock->addr = m->p->unicastSock4.addr;
- sock->ifd = NULL;
- sock->m = m;
-
- // Try at most 10000 times to get a unique random port
-
- for (i=0; i<10000; i++)
- {
- struct sockaddr_in saddr;
-
- saddr.sin_family = AF_INET;
- saddr.sin_addr.s_addr = 0;
-
- // The kernel doesn't do cryptographically strong random port
- // allocation, so we do it ourselves here
-
- if (mDNSIPPortIsZero(requestedport))
- {
- port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
- }
-
- saddr.sin_port = port.NotAnInteger;
-
- err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
- if (!err) break;
- }
-
- require_noerr( err, exit );
-
- // Set the port
-
- sock->port = port;
-
- // Arm the completion routine
-
- err = mDNSPollRegisterSocket( sock->fd, FD_READ, UDPSocketNotification, sock );
- require_noerr( err, exit );
-
- // Bookkeeping
-
- sock->next = gUDPSockets;
- gUDPSockets = sock;
- gUDPNumSockets++;
-
-exit:
-
- if ( err && sock )
- {
- UDPCloseSocket( sock );
- free( sock );
- sock = NULL;
- }
-
- return sock;
-}
-
-//===========================================================================================================================
-// mDNSPlatformUDPClose
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
-{
- UDPSocket * current = gUDPSockets;
- UDPSocket * last = NULL;
-
- while ( current )
- {
- if ( current == sock )
- {
- if ( last == NULL )
- {
- gUDPSockets = sock->next;
- }
- else
- {
- last->next = sock->next;
- }
-
- UDPCloseSocket( sock );
- free( sock );
-
- gUDPNumSockets--;
-
- break;
- }
-
- last = current;
- current = current->next;
- }
-}
-
-//===========================================================================================================================
-// mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mDNSexport mStatus
- mDNSPlatformSendUDP(
- const mDNS * const inMDNS,
- const void * const inMsg,
- const mDNSu8 * const inMsgEnd,
- mDNSInterfaceID inInterfaceID,
- UDPSocket * inSrcSocket,
- const mDNSAddr * inDstIP,
- mDNSIPPort inDstPort,
- mDNSBool useBackgroundTrafficClass )
-{
- SOCKET sendingsocket = INVALID_SOCKET;
- mStatus err = mStatus_NoError;
- mDNSInterfaceData * ifd = (mDNSInterfaceData*) inInterfaceID;
- struct sockaddr_storage addr;
- int n;
-
- DEBUG_USE_ONLY( inMDNS );
- DEBUG_USE_ONLY( useBackgroundTrafficClass );
-
- n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
- check( inMDNS );
- check( inMsg );
- check( inMsgEnd );
- check( inDstIP );
-
- dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
-
- if( inDstIP->type == mDNSAddrType_IPv4 )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) &addr;
- sa4->sin_family = AF_INET;
- sa4->sin_port = inDstPort.NotAnInteger;
- sa4->sin_addr.s_addr = inDstIP->ip.v4.NotAnInteger;
- sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
-
- if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
- }
- else if( inDstIP->type == mDNSAddrType_IPv6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) &addr;
- sa6->sin6_family = AF_INET6;
- sa6->sin6_port = inDstPort.NotAnInteger;
- sa6->sin6_flowinfo = 0;
- sa6->sin6_addr = *( (struct in6_addr *) &inDstIP->ip.v6 );
- sa6->sin6_scope_id = 0; // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
- sendingsocket = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
- }
- else
- {
- dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
- err = mStatus_BadParamErr;
- goto exit;
- }
-
- if (IsValidSocket(sendingsocket))
- {
- n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
- err = translate_errno( n > 0, errno_compat(), kWriteErr );
-
- if ( err )
- {
- // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
-
- if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
- {
- err = mStatus_TransientErr;
- }
- else
- {
- require_noerr( err, exit );
- }
- }
- }
-
-exit:
- return( err );
-}
-
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( InterfaceID );
- }
-
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
- {
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( allowSleep );
- DEBUG_UNUSED( reason );
- }
-
-//===========================================================================================================================
-// mDNSPlatformSendRawPacket
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *ethaddr, char *ipaddr, int iteration)
-{
- unsigned char mac[ 6 ];
- unsigned char buf[ 102 ];
- char hex[ 3 ] = { 0 };
- unsigned char *bufPtr = buf;
- MulticastWakeupStruct *info;
- int i;
- mStatus err;
-
- (void) InterfaceID; // unused
- (void) ipaddr; // unused
- (void) iteration; // unused
-
- require_action( ethaddr, exit, err = mStatus_BadParamErr );
-
- for ( i = 0; i < 6; i++ )
- {
- memcpy( hex, ethaddr + ( i * 3 ), 2 );
- mac[ i ] = ( unsigned char ) strtoul( hex, NULL, 16 );
- }
-
- memset( buf, 0, sizeof( buf ) );
-
- for ( i = 0; i < 6; i++ )
- {
- *bufPtr++ = 0xff;
- }
-
- for ( i = 0; i < 16; i++ )
- {
- memcpy( bufPtr, mac, sizeof( mac ) );
- bufPtr += sizeof( mac );
- }
-
- info = ( MulticastWakeupStruct* ) malloc( sizeof( MulticastWakeupStruct ) );
- require_action( info, exit, err = mStatus_NoMemoryErr );
- info->inMDNS = m;
- memset( &info->addr, 0, sizeof( info->addr ) );
- info->addr.sin_family = AF_INET;
- info->addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- info->addr.sin_port = htons( 9 );
- info->addrLen = sizeof( info->addr );
- memcpy( info->data, buf, sizeof( buf ) );
- info->dataLen = sizeof( buf );
- info->numTries = kMulticastWakeupNumTries;
- info->msecSleep = kMulticastWakeupSleepBetweenTries;
-
- _beginthread( SendMulticastWakeupPacket, 0, ( void* ) info );
-
-exit:
-
- return;
-}
-
-mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
-{
- DEBUG_UNUSED( rr );
- DEBUG_UNUSED( InterfaceID );
-
- return mDNStrue;
-}
-
-mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
-{
- DEBUG_UNUSED( q );
- DEBUG_UNUSED( intf );
-
- return mDNStrue;
-}
-
-mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( msg );
- DEBUG_UNUSED( end );
- DEBUG_UNUSED( InterfaceID );
- }
-
-// Used for debugging purposes. For now, just set the buffer to zero
-mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
- {
- DEBUG_UNUSED( te );
- if (bufsize) buf[0] = 0;
- }
-
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( tpa );
- DEBUG_UNUSED( tha );
- DEBUG_UNUSED( InterfaceID );
- }
-
-mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
- {
- DEBUG_UNUSED( msg );
- DEBUG_UNUSED( end );
- DEBUG_UNUSED( InterfaceID );
- }
-
-mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID )
- {
- DEBUG_UNUSED( tpa );
- DEBUG_UNUSED( tha );
- DEBUG_UNUSED( InterfaceID );
- }
-
-mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
- {
- dlog( kDebugLevelInfo, "%s\n", msg );
- }
-
-mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
- {
- extern mDNS mDNSStorage;
- int type;
-
- DEBUG_UNUSED( ident );
-
- type = EVENTLOG_ERROR_TYPE;
-
- switch (loglevel)
- {
- case MDNS_LOG_MSG: type = EVENTLOG_ERROR_TYPE; break;
- case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE; break;
- case MDNS_LOG_SPS: type = EVENTLOG_INFORMATION_TYPE; break;
- case MDNS_LOG_INFO: type = EVENTLOG_INFORMATION_TYPE; break;
- case MDNS_LOG_DEBUG: type = EVENTLOG_INFORMATION_TYPE; break;
- default:
- fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
- fflush(stderr);
- }
-
- mDNSStorage.p->reportStatusFunc( type, msg );
- dlog( kDebugLevelInfo, "%s\n", msg );
- }
-
-mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
- {
- DEBUG_UNUSED( src );
- DEBUG_UNUSED( dst );
- }
-
-//===========================================================================================================================
-// mDNSPlatformTLSSetupCerts
-//===========================================================================================================================
-
-mDNSexport mStatus
-mDNSPlatformTLSSetupCerts(void)
-{
- return mStatus_UnsupportedErr;
-}
-
-//===========================================================================================================================
-// mDNSPlatformTLSTearDownCerts
-//===========================================================================================================================
-
-mDNSexport void
-mDNSPlatformTLSTearDownCerts(void)
-{
-}
-
-//===========================================================================================================================
-// mDNSPlatformSetDNSConfig
-//===========================================================================================================================
-
-mDNSlocal void SetDNSServers( mDNS *const m );
-mDNSlocal void SetSearchDomainList( void );
-
-mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains, mDNSBool ackConfig)
-{
- (void) ackConfig;
-
- if (setservers) SetDNSServers(m);
- if (setsearch) SetSearchDomainList();
-
- if ( fqdn )
- {
- GetDDNSFQDN( fqdn );
- }
-
- if ( browseDomains )
- {
- GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
- }
-
- if ( regDomains )
- {
- GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
- }
- return mDNStrue;
-}
-
-//===========================================================================================================================
-// mDNSPlatformDynDNSHostNameStatusChanged
-//===========================================================================================================================
-
-mDNSexport void
-mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
-{
- char uname[MAX_ESCAPED_DOMAIN_NAME];
- BYTE bStatus;
- LPCTSTR name;
- HKEY key = NULL;
- mStatus err;
- char * p;
-
- ConvertDomainNameToCString(dname, uname);
-
- p = uname;
-
- while (*p)
- {
- *p = (char) tolower(*p);
- if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
- p++;
- }
-
- check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
- name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
- err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
- require_noerr( err, exit );
-
- bStatus = ( status ) ? 0 : 1;
- err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
- require_noerr( err, exit );
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- return;
-}
-
-//===========================================================================================================================
-// SetDomainSecrets
-//===========================================================================================================================
-
-// This routine needs to be called whenever the system secrets database changes.
-// We call it from DynDNSConfigDidChange and mDNSPlatformInit
-
-void
-SetDomainSecrets( mDNS * const m )
-{
- DomainAuthInfo *ptr;
- domainname fqdn;
- DNameListElem * regDomains = NULL;
-
- // Rather than immediately deleting all keys now, we mark them for deletion in ten seconds.
- // In the case where the user simultaneously removes their DDNS host name and the key
- // for it, this gives mDNSResponder ten seconds to gracefully delete the name from the
- // server before it loses access to the necessary key. Otherwise, we'd leave orphaned
- // address records behind that we no longer have permission to delete.
-
- for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
- ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
-
- GetDDNSFQDN( &fqdn );
-
- if ( fqdn.c[ 0 ] )
- {
- SetDomainSecret( m, &fqdn );
- }
-
- GetDDNSDomains( ®Domains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
-
- while ( regDomains )
- {
- DNameListElem * current = regDomains;
- SetDomainSecret( m, ¤t->name );
- regDomains = regDomains->next;
- free( current );
- }
-}
-
-//===========================================================================================================================
-// SetSearchDomainList
-//===========================================================================================================================
-
-mDNSlocal void SetDomainFromDHCP( void );
-mDNSlocal void SetReverseMapSearchDomainList( void );
-
-mDNSlocal void
-SetSearchDomainList( void )
-{
- char * searchList = NULL;
- DWORD searchListLen;
- //DNameListElem * head = NULL;
- //DNameListElem * current = NULL;
- char * tok;
- HKEY key;
- mStatus err;
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
- require_noerr( err, exit );
-
- err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
- require_noerr( err, exit );
-
- // Windows separates the search domains with ','
-
- tok = strtok( searchList, "," );
- while ( tok )
- {
- if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
- mDNS_AddSearchDomain_CString(tok, mDNSNULL);
- tok = strtok( NULL, "," );
- }
-
-exit:
-
- if ( searchList )
- {
- free( searchList );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-
- SetDomainFromDHCP();
- SetReverseMapSearchDomainList();
-}
-
-//===========================================================================================================================
-// SetReverseMapSearchDomainList
-//===========================================================================================================================
-
-mDNSlocal void
-SetReverseMapSearchDomainList( void )
-{
- struct ifaddrs * ifa;
-
- ifa = myGetIfAddrs( 1 );
- while (ifa)
- {
- mDNSAddr addr;
-
- if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
- {
- mDNSAddr netmask;
- char buffer[256];
-
- if (!SetupAddr(&netmask, ifa->ifa_netmask))
- {
- _snprintf(buffer, sizeof( buffer ), "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
- addr.ip.v4.b[2] & netmask.ip.v4.b[2],
- addr.ip.v4.b[1] & netmask.ip.v4.b[1],
- addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
- mDNS_AddSearchDomain_CString(buffer, mDNSNULL);
- }
- }
-
- ifa = ifa->ifa_next;
- }
-
- return;
-}
-
-//===========================================================================================================================
-// SetDNSServers
-//===========================================================================================================================
-
-mDNSlocal void
-SetDNSServers( mDNS *const m )
-{
- PIP_PER_ADAPTER_INFO pAdapterInfo = NULL;
- FIXED_INFO * fixedInfo = NULL;
- ULONG bufLen = 0;
- IP_ADDR_STRING * dnsServerList;
- IP_ADDR_STRING * ipAddr;
- DWORD index;
- int i = 0;
- mStatus err = kUnknownErr;
-
- // Get the primary interface.
-
- index = GetPrimaryInterface();
-
- // This should have the interface index of the primary index. Fall back in cases where
- // it can't be determined.
-
- if ( index )
- {
- bufLen = 0;
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
-
- pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
- require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
- }
-
- require_noerr( err, exit );
-
- dnsServerList = &pAdapterInfo->DnsServerList;
- }
- else
- {
- bufLen = sizeof( FIXED_INFO );
-
- for ( i = 0; i < 100; i++ )
- {
- if ( fixedInfo )
- {
- GlobalFree( fixedInfo );
- fixedInfo = NULL;
- }
-
- fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
- require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
-
- err = GetNetworkParams( fixedInfo, &bufLen );
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
- }
-
- require_noerr( err, exit );
-
- dnsServerList = &fixedInfo->DnsServerList;
- }
-
- for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
- {
- mDNSAddr addr;
- err = StringToAddress( &addr, ipAddr->IpAddress.String );
- if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, 0, &addr, UnicastDNSPort, kScopeNone, DEFAULT_UDNS_TIMEOUT, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
- }
-
-exit:
-
- if ( pAdapterInfo )
- {
- free( pAdapterInfo );
- }
-
- if ( fixedInfo )
- {
- GlobalFree( fixedInfo );
- }
-}
-
-//===========================================================================================================================
-// SetDomainFromDHCP
-//===========================================================================================================================
-
-mDNSlocal void
-SetDomainFromDHCP( void )
-{
- int i = 0;
- IP_ADAPTER_INFO * pAdapterInfo;
- IP_ADAPTER_INFO * pAdapter;
- DWORD bufLen;
- DWORD index;
- HKEY key = NULL;
- LPSTR domain = NULL;
- DWORD dwSize;
- mStatus err = mStatus_NoError;
-
- pAdapterInfo = NULL;
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
-
- pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
- require_action( pAdapterInfo, exit, err = kNoMemoryErr );
- }
-
- require_noerr( err, exit );
-
- index = GetPrimaryInterface();
-
- for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
- {
- if ( pAdapter->IpAddressList.IpAddress.String &&
- pAdapter->IpAddressList.IpAddress.String[0] &&
- pAdapter->GatewayList.IpAddress.String &&
- pAdapter->GatewayList.IpAddress.String[0] &&
- ( !index || ( pAdapter->Index == index ) ) )
- {
- // Found one that will work
-
- char keyName[1024];
-
- _snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
-
- err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
- require_noerr( err, exit );
-
- err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
- check_noerr( err );
-
- if ( !domain || !domain[0] )
- {
- if ( domain )
- {
- free( domain );
- domain = NULL;
- }
-
- err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
- check_noerr( err );
- }
-
- if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain, mDNSNULL);
-
- break;
- }
- }
-
-exit:
-
- if ( pAdapterInfo )
- {
- free( pAdapterInfo );
- }
-
- if ( domain )
- {
- free( domain );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-//===========================================================================================================================
-// mDNSPlatformGetPrimaryInterface
-//===========================================================================================================================
-
-mDNSexport mStatus
-mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
-{
- IP_ADAPTER_INFO * pAdapterInfo;
- IP_ADAPTER_INFO * pAdapter;
- DWORD bufLen;
- int i;
- BOOL found;
- DWORD index;
- mStatus err = mStatus_NoError;
-
- DEBUG_UNUSED( m );
-
- *v6 = zeroAddr;
-
- pAdapterInfo = NULL;
- bufLen = 0;
- found = FALSE;
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
- if ( err != ERROR_BUFFER_OVERFLOW )
- {
- break;
- }
-
- pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
- require_action( pAdapterInfo, exit, err = kNoMemoryErr );
- }
-
- require_noerr( err, exit );
-
- index = GetPrimaryInterface();
-
- for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
- {
- if ( pAdapter->IpAddressList.IpAddress.String &&
- pAdapter->IpAddressList.IpAddress.String[0] &&
- pAdapter->GatewayList.IpAddress.String &&
- pAdapter->GatewayList.IpAddress.String[0] &&
- ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
- ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
- ( !index || ( pAdapter->Index == index ) ) )
- {
- // Found one that will work
-
- if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
- {
- memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
- }
-
- found = TRUE;
- break;
- }
- }
-
-exit:
-
- if ( pAdapterInfo )
- {
- free( pAdapterInfo );
- }
-
- return err;
-}
-
-mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
-{
- (void) sadd; // Unused
- (void) dadd; // Unused
- (void) lport; // Unused
- (void) rport; // Unused
- (void) seq; // Unused
- (void) ack; // Unused
- (void) win; // Unused
-}
-
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
-{
- (void) m; // Unused
- (void) raddr; // Unused
-
- return mStatus_UnsupportedErr;
-}
-
-mDNSexport mStatus mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
-{
- (void) spsaddr; // Unused
- (void) ifname; // Unused
-
- return mStatus_UnsupportedErr;
-}
-
-mDNSexport mStatus mDNSPlatformClearSPSData(void)
-{
- return mStatus_UnsupportedErr;
-}
-
-mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length)
-{
- (void) ifname; // Unused
- (void) msg; // Unused
- (void) length; // Unused
- return mStatus_UnsupportedErr;
-}
-
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
-{
- (void) m; // Unused
- (void) laddr; // Unused
- (void) raddr; // Unused
- (void) lport; // Unused
- (void) rport; // Unused
- (void) mti; // Unused
-
- return mStatus_UnsupportedErr;
-}
-
-mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
- {
- (void) sock;
- (void) transType;
- (void) addrType;
- (void) q;
- }
-
-mDNSexport mDNSs32 mDNSPlatformGetPID()
- {
- return 0;
- }
-
-mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
-{
- DEBUG_UNUSED( sock );
-
- return (mDNSu16)-1;
-}
-
-mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
-{
- DEBUG_UNUSED( InterfaceID );
-
- return mDNSfalse;
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// debugf_
-//===========================================================================================================================
-#if( MDNS_DEBUGMSGS )
-mDNSexport void debugf_( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, inFormat );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-// verbosedebugf_
-//===========================================================================================================================
-
-#if( MDNS_DEBUGMSGS > 1 )
-mDNSexport void verbosedebugf_( const char *inFormat, ... )
-{
- char buffer[ 512 ];
- va_list args;
- mDNSu32 length;
-
- va_start( args, inFormat );
- length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
- va_end( args );
-
- dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Internals ==
-#endif
-
-//===========================================================================================================================
-// SetupNiceName
-//===========================================================================================================================
-
-mStatus SetupNiceName( mDNS * const inMDNS )
-{
- HKEY descKey = NULL;
- char utf8[ 256 ];
- LPCTSTR s;
- LPWSTR joinName;
- NETSETUP_JOIN_STATUS joinStatus;
- mStatus err = 0;
- DWORD namelen;
- BOOL ok;
-
- check( inMDNS );
-
- // Set up the nice name.
- utf8[0] = '\0';
-
- // First try and open the registry key that contains the computer description value
- s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
- err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
- check_translated_errno( err == 0, errno_compat(), kNameErr );
-
- if ( !err )
- {
- TCHAR desc[256];
- DWORD descSize = sizeof( desc );
-
- // look for the computer description
- err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
-
- if ( !err )
- {
- err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
- }
-
- if ( err )
- {
- utf8[ 0 ] = '\0';
- }
- }
-
- // if we can't find it in the registry, then use the hostname of the machine
- if ( err || ( utf8[ 0 ] == '\0' ) )
- {
- TCHAR hostname[256];
-
- namelen = sizeof( hostname ) / sizeof( TCHAR );
-
- ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
- err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
- check_noerr( err );
-
- if( !err )
- {
- err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
- }
-
- if ( err )
- {
- utf8[ 0 ] = '\0';
- }
- }
-
- // if we can't get the hostname
- if ( err || ( utf8[ 0 ] == '\0' ) )
- {
- // Invalidate name so fall back to a default name.
-
- strcpy_s( utf8, sizeof( utf8 ), kMDNSDefaultName );
- }
-
- utf8[ sizeof( utf8 ) - 1 ] = '\0';
- inMDNS->nicelabel.c[ 0 ] = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
- memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
-
- if ( descKey )
- {
- RegCloseKey( descKey );
- }
-
- ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
- ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
-
- namelen = sizeof( inMDNS->p->nbname );
- ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
- check( ok );
- if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
-
- err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
- check ( err == NERR_Success );
- if ( err == NERR_Success )
- {
- if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
- {
- err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
- check( !err );
- if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
- }
-
- NetApiBufferFree( joinName );
- joinName = NULL;
- }
-
- err = 0;
-
- return( err );
-}
-
-//===========================================================================================================================
-// SetupHostName
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupHostName( mDNS * const inMDNS )
-{
- mStatus err = 0;
- char tempString[ 256 ];
- DWORD tempStringLen;
- domainlabel tempLabel;
- BOOL ok;
-
- check( inMDNS );
-
- // Set up the nice name.
- tempString[ 0 ] = '\0';
-
- // use the hostname of the machine
- tempStringLen = sizeof( tempString );
- ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
- err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
- check_noerr( err );
-
- // if we can't get the hostname
- if( err || ( tempString[ 0 ] == '\0' ) )
- {
- // Invalidate name so fall back to a default name.
-
- strcpy_s( tempString, sizeof( tempString ), kMDNSDefaultName );
- }
-
- tempString[ sizeof( tempString ) - 1 ] = '\0';
- tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
- memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
-
- // Set up the host name.
-
- ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
- if( inMDNS->hostlabel.c[ 0 ] == 0 )
- {
- // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
-
- MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
- }
-
- check( inMDNS->hostlabel.c[ 0 ] != 0 );
-
- mDNS_SetFQDN( inMDNS );
-
- dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
-
- return( err );
-}
-
-//===========================================================================================================================
-// SetupName
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupName( mDNS * const inMDNS )
-{
- mStatus err = 0;
-
- check( inMDNS );
-
- err = SetupNiceName( inMDNS );
- check_noerr( err );
-
- err = SetupHostName( inMDNS );
- check_noerr( err );
-
- return err;
-}
-
-//===========================================================================================================================
-// SetupInterfaceList
-//===========================================================================================================================
-
-mStatus SetupInterfaceList( mDNS * const inMDNS )
-{
- mStatus err;
- mDNSInterfaceData ** next;
- mDNSInterfaceData * ifd;
- struct ifaddrs * addrs;
- struct ifaddrs * p;
- struct ifaddrs * loopbackv4;
- struct ifaddrs * loopbackv6;
- u_int flagMask;
- u_int flagTest;
- mDNSBool foundv4;
- mDNSBool foundv6;
- mDNSBool foundUnicastSock4DestAddr;
- mDNSBool foundUnicastSock6DestAddr;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
- check( inMDNS );
- check( inMDNS->p );
-
- inMDNS->p->registeredLoopback4 = mDNSfalse;
- inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
- addrs = NULL;
- foundv4 = mDNSfalse;
- foundv6 = mDNSfalse;
- foundUnicastSock4DestAddr = mDNSfalse;
- foundUnicastSock6DestAddr = mDNSfalse;
-
- // Tear down any existing interfaces that may be set up.
-
- TearDownInterfaceList( inMDNS );
-
- // Set up the name of this machine.
-
- err = SetupName( inMDNS );
- check_noerr( err );
-
- // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
- // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
-
- err = getifaddrs( &addrs );
- require_noerr( err, exit );
-
- loopbackv4 = NULL;
- loopbackv6 = NULL;
- next = &inMDNS->p->interfaceList;
-
- flagMask = IFF_UP | IFF_MULTICAST;
- flagTest = IFF_UP | IFF_MULTICAST;
-
-#if( MDNS_WINDOWS_ENABLE_IPV4 )
- for( p = addrs; p; p = p->ifa_next )
- {
- if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
- {
- continue;
- }
- if( p->ifa_flags & IFF_LOOPBACK )
- {
- if( !loopbackv4 )
- {
- loopbackv4 = p;
- }
- continue;
- }
- dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
-
- err = SetupInterface( inMDNS, p, &ifd );
- require_noerr( err, exit );
-
- // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
- // register him, but we also want to note that we haven't found a v4 interface
- // so that we register loopback so same host operations work
-
- if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
- {
- foundv4 = mDNStrue;
- }
-
- if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
- {
- inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
- }
-
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock4DestAddr )
- {
- inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
- foundUnicastSock4DestAddr = TRUE;
- }
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
-#endif
-
- // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
-
-#if( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- for( p = addrs; p; p = p->ifa_next )
- {
- if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
- {
- continue;
- }
- if( p->ifa_flags & IFF_LOOPBACK )
- {
- if( !loopbackv6 )
- {
- loopbackv6 = p;
- }
- continue;
- }
- dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
-
- err = SetupInterface( inMDNS, p, &ifd );
- require_noerr( err, exit );
-
- // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
- // register him, but we also want to note that we haven't found a v4 interface
- // so that we register loopback so same host operations work
-
- if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
- {
- foundv6 = mDNStrue;
- }
-
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock6DestAddr )
- {
- inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
- foundUnicastSock6DestAddr = TRUE;
- }
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
- }
-
-#endif
-
- // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
-
-#if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
-
- flagMask |= IFF_LOOPBACK;
- flagTest |= IFF_LOOPBACK;
-
- for( p = addrs; p; p = p->ifa_next )
- {
- if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
- {
- continue;
- }
- if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
- {
- continue;
- }
-
- v4loopback = p;
- break;
- }
-
-#endif
-
- if ( !foundv4 && loopbackv4 )
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
-
- err = SetupInterface( inMDNS, loopbackv4, &ifd );
- require_noerr( err, exit );
-
- inMDNS->p->registeredLoopback4 = mDNStrue;
-
-#if( MDNS_WINDOWS_ENABLE_IPV4 )
-
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock4DestAddr )
- {
- inMDNS->p->unicastSock4.addr = ifd->sock.addr;
- foundUnicastSock4DestAddr = TRUE;
- }
-#endif
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
-
- if ( !foundv6 && loopbackv6 )
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n",
- loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
-
- err = SetupInterface( inMDNS, loopbackv6, &ifd );
- require_noerr( err, exit );
-
-#if( MDNS_WINDOWS_ENABLE_IPV6 )
-
- if ( gEnableIPv6 )
- {
- // If we're on a platform that doesn't have WSARecvMsg(), there's no way
- // of determing the destination address of a packet that is sent to us.
- // For multicast packets, that's easy to determine. But for the unicast
- // sockets, we'll fake it by taking the address of the first interface
- // that is successfully setup.
-
- if ( !foundUnicastSock6DestAddr )
- {
- inMDNS->p->unicastSock6.addr = ifd->sock.addr;
- foundUnicastSock6DestAddr = TRUE;
- }
- }
-
-#endif
-
- *next = ifd;
- next = &ifd->next;
- ++inMDNS->p->interfaceCount;
- }
-
- CheckFileShares( inMDNS );
-
-exit:
- if( err )
- {
- TearDownInterfaceList( inMDNS );
- }
- if( addrs )
- {
- freeifaddrs( addrs );
- }
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownInterfaceList
-//===========================================================================================================================
-
-mStatus TearDownInterfaceList( mDNS * const inMDNS )
-{
- mDNSInterfaceData ** p;
- mDNSInterfaceData * ifd;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
- check( inMDNS );
- check( inMDNS->p );
-
- // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
- // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
- // so that remove events that occur after an interface goes away can still report the correct interface.
-
- p = &inMDNS->p->inactiveInterfaceList;
- while( *p )
- {
- ifd = *p;
- if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
- {
- p = &ifd->next;
- continue;
- }
-
- dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
- *p = ifd->next;
-
- QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
- }
-
- // Tear down all the interfaces.
-
- while( inMDNS->p->interfaceList )
- {
- ifd = inMDNS->p->interfaceList;
- inMDNS->p->interfaceList = ifd->next;
-
- TearDownInterface( inMDNS, ifd );
- }
- inMDNS->p->interfaceCount = 0;
-
- dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
- return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-// SetupInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
-{
- mDNSInterfaceData * ifd;
- mDNSInterfaceData * p;
- mStatus err;
-
- ifd = NULL;
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
- check( inMDNS );
- check( inMDNS->p );
- check( inIFA );
- check( inIFA->ifa_addr );
- check( outIFD );
-
- // Allocate memory for the interface and initialize it.
-
- ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
- require_action( ifd, exit, err = mStatus_NoMemoryErr );
- ifd->sock.fd = kInvalidSocketRef;
- ifd->sock.ifd = ifd;
- ifd->sock.next = NULL;
- ifd->sock.m = inMDNS;
- ifd->index = inIFA->ifa_extra.index;
- ifd->scopeID = inIFA->ifa_extra.index;
- check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
- strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
- ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
-
- strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
- ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
-
- // We always send and receive using IPv4, but to reduce traffic, we send and receive using IPv6 only on interfaces
- // that have no routable IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being
- // on a large configured network, which means there's a good chance that most or all the other devices on that
- // network should also have v4. By doing this we lose the ability to talk to true v6-only devices on that link,
- // but we cut the packet rate in half. At this time, reducing the packet rate is more important than v6-only
- // devices on a large configured network, so we are willing to make that sacrifice.
-
- ifd->interfaceInfo.McastTxRx = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
- ifd->interfaceInfo.InterfaceID = NULL;
-
- for( p = inMDNS->p->interfaceList; p; p = p->next )
- {
- if ( strcmp( p->name, ifd->name ) == 0 )
- {
- if (!ifd->interfaceInfo.InterfaceID)
- {
- ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) p;
- }
-
- if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
- ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
- ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
- {
- ifd->interfaceInfo.McastTxRx = mDNSfalse;
- }
-
- break;
- }
- }
-
- if ( !ifd->interfaceInfo.InterfaceID )
- {
- ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
- }
-
- // Set up a socket for this interface (if needed).
-
- if( ifd->interfaceInfo.McastTxRx )
- {
- DWORD size;
-
- err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
- require_noerr( err, exit );
- ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
- ifd->sock.port = MulticastDNSPort;
-
- // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
-
- err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
-
- if ( err )
- {
- ifd->sock.recvMsgPtr = NULL;
- }
- }
-
- if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
- {
- inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
- }
-
- ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
-
- // Register this interface with mDNS.
-
- err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
- require_noerr( err, exit );
-
- err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
- require_noerr( err, exit );
-
- memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
-
- ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
-
- if ( ifd->sock.fd != kInvalidSocketRef )
- {
- err = mDNSPollRegisterSocket( ifd->sock.fd, FD_READ, UDPSocketNotification, &ifd->sock );
- require_noerr( err, exit );
- }
-
- // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
- // and skip the probe phase of the probe/announce packet sequence.
- ifd->interfaceInfo.DirectLink = mDNSfalse;
- ifd->interfaceInfo.SupportsUnicastMDNSResponse = mDNStrue;
-
- err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, NormalActivation );
- require_noerr( err, exit );
- ifd->hostRegistered = mDNStrue;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
-
- // Success!
-
- *outIFD = ifd;
- ifd = NULL;
-
-exit:
-
- if( ifd )
- {
- TearDownInterface( inMDNS, ifd );
- }
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
- return( err );
-}
-
-//===========================================================================================================================
-// TearDownInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
-{
- check( inMDNS );
- check( inIFD );
-
- // Deregister this interface with mDNS.
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
-
- if( inIFD->hostRegistered )
- {
- inIFD->hostRegistered = mDNSfalse;
- mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, NormalActivation );
- }
-
- // Tear down the multicast socket.
-
- UDPCloseSocket( &inIFD->sock );
-
- // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps
- // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
-
- if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
- {
- inIFD->next = inMDNS->p->inactiveInterfaceList;
- inMDNS->p->inactiveInterfaceList = inIFD;
- dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
- }
- else
- {
- dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
- QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
- }
-
- return( mStatus_NoError );
-}
-
-mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
-{
- free( inIFD );
-}
-
-//===========================================================================================================================
-// SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef )
-{
- mStatus err;
- SocketRef sock;
- int option;
- DWORD bytesReturned = 0;
- BOOL behavior = FALSE;
-
- DEBUG_UNUSED( inMDNS );
-
- dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
- check( inMDNS );
- check( outSocketRef );
-
- // Set up an IPv4 or IPv6 UDP socket.
-
- sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
- err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
- // if we're creating a multicast socket
-
- if ( !mDNSIPPortIsZero( port ) )
- {
- option = 1;
- err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
- //
- // Not sure why, but the default behavior for sockets is to behave incorrectly
- // when using them in Overlapped I/O mode on XP. According to MSDN:
- //
- // SIO_UDP_CONNRESET (opcode setting: I, T==3)
- // Windows XP: Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
- // Set to FALSE to disable reporting.
- //
- // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
- // messages were being sent to us after we sent out packets to a multicast address. This is clearly
- // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
- // will no longer receive any packets from that socket, which is not harmless. This behavior is only
- // seen on XP.
- //
- // So we turn off port unreachable reporting to make sure our sockets that are reading
- // multicast packets function correctly under all circumstances.
-
- err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- if( inAddr->sa_family == AF_INET )
- {
- mDNSv4Addr ipv4;
- struct sockaddr_in sa4;
- struct ip_mreq mreqv4;
-
- // Bind the socket to the desired port
-
- ipv4.NotAnInteger = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
- mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
- sa4.sin_family = AF_INET;
- sa4.sin_port = port.NotAnInteger;
- sa4.sin_addr.s_addr = ipv4.NotAnInteger;
-
- err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
- // Turn on option to receive destination addresses and receiving interface.
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- if ( !mDNSIPPortIsZero( port ) )
- {
- // Join the all-DNS multicast group so we receive Multicast DNS packets
-
- mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
- mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
- err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Specify the interface to send multicast packets on this socket.
-
- sa4.sin_addr.s_addr = ipv4.NotAnInteger;
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Send unicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Send multicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- }
- else if( inAddr->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 * sa6p;
- struct sockaddr_in6 sa6;
- struct ipv6_mreq mreqv6;
-
- sa6p = (struct sockaddr_in6 *) inAddr;
-
- // Bind the socket to the desired port
-
- mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
- sa6.sin6_family = AF_INET6;
- sa6.sin6_port = port.NotAnInteger;
- sa6.sin6_flowinfo = 0;
- sa6.sin6_addr = sa6p->sin6_addr;
- sa6.sin6_scope_id = sa6p->sin6_scope_id;
-
- err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
- check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
- // Turn on option to receive destination addresses and receiving interface.
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket
- // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
- // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
-
- #if( defined( IPV6_V6ONLY ) )
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- #endif
-
- if ( !mDNSIPPortIsZero( port ) )
- {
- // Join the all-DNS multicast group so we receive Multicast DNS packets.
-
- mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroup_v6.ip.v6 );
- mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Specify the interface to send multicast packets on this socket.
-
- option = (int) sa6p->sin6_scope_id;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-
- option = 1;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
-
- // Send unicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
- // Send multicast packets with TTL 255 (helps against spoofing).
-
- option = 255;
- err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
- check_translated_errno( err == 0, errno_compat(), kOptionErr );
- }
- else
- {
- dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
- err = kUnsupportedErr;
- goto exit;
- }
-
- // Success!
-
- *outSocketRef = sock;
- sock = kInvalidSocketRef;
- err = mStatus_NoError;
-
-exit:
- if( IsValidSocket( sock ) )
- {
- close_compat( sock );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
-{
- mStatus err;
-
- check( inSA );
- check( outIP );
-
- if( inSA->sa_family == AF_INET )
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) inSA;
- outIP->type = mDNSAddrType_IPv4;
- outIP->ip.v4.NotAnInteger = sa4->sin_addr.s_addr;
- if( outPort )
- {
- outPort->NotAnInteger = sa4->sin_port;
- }
- err = mStatus_NoError;
- }
- else if( inSA->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 * sa6;
-
- sa6 = (struct sockaddr_in6 *) inSA;
- outIP->type = mDNSAddrType_IPv6;
- outIP->ip.v6 = *( (mDNSv6Addr *) &sa6->sin6_addr );
- if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
- {
- outIP->ip.v6.w[ 1 ] = 0;
- }
- if( outPort )
- {
- outPort->NotAnInteger = sa6->sin6_port;
- }
- err = mStatus_NoError;
- }
- else
- {
- dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
- err = mStatus_BadParamErr;
- }
- return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// UDPSocketNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
- UDPSocket *udpSock = ( UDPSocket* ) context;
- WSAMSG wmsg;
- WSABUF wbuf;
- struct sockaddr_storage sockSrcAddr; // This is filled in by the WSARecv* function
- INT sockSrcAddrLen; // See above
- mDNSAddr srcAddr;
- mDNSInterfaceID iid;
- mDNSIPPort srcPort;
- mDNSAddr dstAddr;
- mDNSIPPort dstPort;
- uint8_t controlBuffer[ 128 ];
- mDNSu8 * end;
- int num;
- DWORD numTries;
- mStatus err;
-
- DEBUG_UNUSED( sock );
- DEBUG_UNUSED( event );
-
- require_action( udpSock != NULL, exit, err = mStatus_BadStateErr );
-
- dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, udpSock->fd );
-
- // Initialize the buffer structure
-
- wbuf.buf = (char *) &udpSock->packet;
- wbuf.len = (u_long) sizeof( udpSock->packet );
- sockSrcAddrLen = sizeof( sockSrcAddr );
-
- numTries = 0;
-
- do
- {
- if ( udpSock->recvMsgPtr )
- {
- DWORD size;
-
- wmsg.name = ( LPSOCKADDR ) &sockSrcAddr;
- wmsg.namelen = sockSrcAddrLen;
- wmsg.lpBuffers = &wbuf;
- wmsg.dwBufferCount = 1;
- wmsg.Control.buf = ( CHAR* ) controlBuffer;
- wmsg.Control.len = sizeof( controlBuffer );
- wmsg.dwFlags = 0;
-
- err = udpSock->recvMsgPtr( udpSock->fd, &wmsg, &size, NULL, NULL );
- err = translate_errno( ( err == 0 ), (OSStatus) WSAGetLastError(), kUnknownErr );
- num = ( int ) size;
-
- // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
- //
- // There seems to be a bug in some network device drivers that involves calling WSARecvMsg().
- // Although all the parameters to WSARecvMsg() are correct, it returns a
- // WSAEFAULT error code when there is no actual error. We have found experientially that falling
- // back to using WSARecvFrom() when this happens will work correctly.
-
- if ( err == WSAEFAULT ) udpSock->recvMsgPtr = NULL;
- }
- else
- {
- DWORD flags = 0;
-
- num = WSARecvFrom( udpSock->fd, &wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sockSrcAddr, &sockSrcAddrLen, NULL, NULL );
- err = translate_errno( ( num >= 0 ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
- }
-
- // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
- //
- // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
- // send operation resulted in an ICMP "Port Unreachable" message."
- //
- // Because this is the case, we want to ignore this error and try again. Just in case
- // this is some kind of pathological condition, we'll break out of the retry loop
- // after 100 iterations
-
- require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
- }
- while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
-
- require_noerr( err, exit );
-
- // Translate the source of this packet into mDNS data types
-
- SockAddrToMDNSAddr( (struct sockaddr* ) &sockSrcAddr, &srcAddr, &srcPort );
-
- // Initialize the destination of this packet. Just in case
- // we can't determine this info because we couldn't call
- // WSARecvMsg (recvMsgPtr)
-
- dstAddr = udpSock->addr;
- dstPort = udpSock->port;
-
- if ( udpSock->recvMsgPtr )
- {
- LPWSACMSGHDR header;
- LPWSACMSGHDR last = NULL;
- int count = 0;
-
- // Parse the control information. Reject packets received on the wrong interface.
-
- // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
- //
- // There seems to be an interaction between Bullguard and this next bit of code.
- // When a user's machine is running Bullguard, the control information that is
- // returned is corrupted, and the code would go into an infinite loop. We'll add
- // two bits of defensive coding here. The first will check that each pointer to
- // the LPWSACMSGHDR that is returned in the for loop is different than the last.
- // This fixes the problem with Bullguard. The second will break out of this loop
- // after 100 iterations, just in case the corruption isn't caught by the first
- // check.
-
- for ( header = WSA_CMSG_FIRSTHDR( &wmsg ); header; header = WSA_CMSG_NXTHDR( &wmsg, header ) )
- {
- if ( ( header != last ) && ( ++count < 100 ) )
- {
- last = header;
-
- if ( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
- {
- IN_PKTINFO * ipv4PacketInfo;
-
- ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
-
- if ( udpSock->ifd != NULL )
- {
- require_action( ipv4PacketInfo->ipi_ifindex == udpSock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
- }
-
- dstAddr.type = mDNSAddrType_IPv4;
- dstAddr.ip.v4.NotAnInteger = ipv4PacketInfo->ipi_addr.s_addr;
- }
- else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
- {
- IN6_PKTINFO * ipv6PacketInfo;
-
- ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
-
- if ( udpSock->ifd != NULL )
- {
- require_action( ipv6PacketInfo->ipi6_ifindex == ( udpSock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
- }
-
- dstAddr.type = mDNSAddrType_IPv6;
- dstAddr.ip.v6 = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
- }
- }
- else
- {
- static BOOL loggedMessage = FALSE;
-
- if ( !loggedMessage )
- {
- LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
- loggedMessage = TRUE;
- }
-
- break;
- }
- }
- }
-
- dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
- dlog( kDebugLevelChatty, DEBUG_NAME " size = %d\n", num );
- dlog( kDebugLevelChatty, DEBUG_NAME " src = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
- dlog( kDebugLevelChatty, DEBUG_NAME " dst = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
-
- if ( udpSock->ifd != NULL )
- {
- dlog( kDebugLevelChatty, DEBUG_NAME " interface = %#a (index=0x%08X)\n", &udpSock->ifd->interfaceInfo.ip, udpSock->ifd->index );
- }
-
- dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
-
- iid = udpSock->ifd ? udpSock->ifd->interfaceInfo.InterfaceID : NULL;
- end = ( (mDNSu8 *) &udpSock->packet ) + num;
-
- mDNSCoreReceive( udpSock->m, &udpSock->packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
-
-exit:
-
- return;
-}
-
-//===========================================================================================================================
-// InterfaceListDidChange
-//===========================================================================================================================
-void InterfaceListDidChange( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
- check( inMDNS );
-
- // Tear down the existing interfaces and set up new ones using the new IP info.
-
- err = TearDownInterfaceList( inMDNS );
- check_noerr( err );
-
- err = SetupInterfaceList( inMDNS );
- check_noerr( err );
-
- err = uDNS_SetupDNSConfig( inMDNS );
- check_noerr( err );
-
- // Inform clients of the change.
-
- mDNS_ConfigChanged(inMDNS);
-
- // Force mDNS to update.
-
- mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
-}
-
-//===========================================================================================================================
-// ComputerDescriptionDidChange
-//===========================================================================================================================
-void ComputerDescriptionDidChange( mDNS * const inMDNS )
-{
- dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
- check( inMDNS );
-
- // redo the names
- SetupNiceName( inMDNS );
-}
-
-//===========================================================================================================================
-// TCPIPConfigDidChange
-//===========================================================================================================================
-void TCPIPConfigDidChange( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
- check( inMDNS );
-
- err = uDNS_SetupDNSConfig( inMDNS );
- check_noerr( err );
-}
-
-//===========================================================================================================================
-// DynDNSConfigDidChange
-//===========================================================================================================================
-void DynDNSConfigDidChange( mDNS * const inMDNS )
-{
- mStatus err;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
- check( inMDNS );
-
- SetDomainSecrets( inMDNS );
-
- err = uDNS_SetupDNSConfig( inMDNS );
- check_noerr( err );
-}
-
-//===========================================================================================================================
-// FileSharingDidChange
-//===========================================================================================================================
-void FileSharingDidChange( mDNS * const inMDNS )
-{
- dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
- check( inMDNS );
-
- CheckFileShares( inMDNS );
-}
-
-//===========================================================================================================================
-// FilewallDidChange
-//===========================================================================================================================
-void FirewallDidChange( mDNS * const inMDNS )
-{
- dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
- check( inMDNS );
-
- CheckFileShares( inMDNS );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-// getifaddrs
-//===========================================================================================================================
-
-mDNSlocal int getifaddrs( struct ifaddrs **outAddrs )
-{
- int err;
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-
- // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
- // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
-
- if( !gIPHelperLibraryInstance )
- {
- gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
- if( gIPHelperLibraryInstance )
- {
- gGetAdaptersAddressesFunctionPtr =
- (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
- if( !gGetAdaptersAddressesFunctionPtr )
- {
- BOOL ok;
-
- ok = FreeLibrary( gIPHelperLibraryInstance );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- gIPHelperLibraryInstance = NULL;
- }
- }
- }
-
- // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
- // <rdar://problem/4278934> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
- // <rdar://problem/6145913> Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
-
- if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
- {
- err = getifaddrs_ipv4( outAddrs );
- require_noerr( err, exit );
- }
-
-#else
-
- err = getifaddrs_ipv4( outAddrs );
- require_noerr( err, exit );
-
-#endif
-
-exit:
- return( err );
-}
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-//===========================================================================================================================
-// getifaddrs_ipv6
-//===========================================================================================================================
-
-mDNSlocal int getifaddrs_ipv6( struct ifaddrs **outAddrs )
-{
- DWORD err;
- int i;
- DWORD flags;
- struct ifaddrs * head;
- struct ifaddrs ** next;
- IP_ADAPTER_ADDRESSES * iaaList;
- ULONG iaaListSize;
- IP_ADAPTER_ADDRESSES * iaa;
- size_t size;
- struct ifaddrs * ifa;
-
- check( gGetAdaptersAddressesFunctionPtr );
-
- head = NULL;
- next = &head;
- iaaList = NULL;
-
- // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
- // This loops to handle the case where the interface changes in the window after getting the size, but before the
- // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
-
- flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
- i = 0;
- for( ;; )
- {
- iaaListSize = 0;
- err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
- check( err == ERROR_BUFFER_OVERFLOW );
- check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
-
- iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
- require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
-
- err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
- if( err == ERROR_SUCCESS ) break;
-
- free( iaaList );
- iaaList = NULL;
- ++i;
- require( i < 100, exit );
- dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
- }
-
- for( iaa = iaaList; iaa; iaa = iaa->Next )
- {
- int addrIndex;
- IP_ADAPTER_UNICAST_ADDRESS * addr;
- DWORD ipv6IfIndex;
- IP_ADAPTER_PREFIX * firstPrefix;
-
- if( iaa->IfIndex > 0xFFFFFF )
- {
- dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
- }
- if( iaa->Ipv6IfIndex > 0xFF )
- {
- dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
- }
-
- // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
- // following code to crash when iterating through the prefix list. This seems
- // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
- // This shouldn't happen according to Microsoft docs which states:
- //
- // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
- //
- // So the data structure seems to be corrupted when we return from
- // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
- // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
- // modify iaa to have the correct values.
-
- if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
- {
- ipv6IfIndex = iaa->Ipv6IfIndex;
- firstPrefix = iaa->FirstPrefix;
- }
- else
- {
- ipv6IfIndex = 0;
- firstPrefix = NULL;
- }
-
- // Skip pseudo and tunnel interfaces.
-
- if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
- {
- continue;
- }
-
- // Add each address as a separate interface to emulate the way getifaddrs works.
-
- for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
- {
- int family;
- IP_ADAPTER_PREFIX * prefix;
- uint32_t ipv4Index;
- struct sockaddr_in ipv4Netmask;
-
- family = addr->Address.lpSockaddr->sa_family;
- if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
-
- // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
- // Seems as if the problem here is a buggy implementation of some network interface
- // driver. It is reporting that is has a link-local address when it is actually
- // disconnected. This was causing a problem in AddressToIndexAndMask.
- // The solution is to call AddressToIndexAndMask first, and if unable to lookup
- // the address, to ignore that address.
-
- ipv4Index = 0;
- memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
-
- if ( family == AF_INET )
- {
- err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
-
- if ( err )
- {
- err = 0;
- continue;
- }
- }
-
- ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
- require_action( ifa, exit, err = WSAENOBUFS );
-
- *next = ifa;
- next = &ifa->ifa_next;
-
- // Get the name.
-
- size = strlen( iaa->AdapterName ) + 1;
- ifa->ifa_name = (char *) malloc( size );
- require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
- memcpy( ifa->ifa_name, iaa->AdapterName, size );
-
- // Get interface flags.
-
- ifa->ifa_flags = 0;
- if( iaa->OperStatus == IfOperStatusUp ) ifa->ifa_flags |= IFF_UP;
- if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK ) ifa->ifa_flags |= IFF_LOOPBACK;
- else if ( IsPointToPoint( addr ) ) ifa->ifa_flags |= IFF_POINTTOPOINT;
- if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
-
-
- // <rdar://problem/4045657> Interface index being returned is 512
- //
- // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
- // This code used to shift the IPv4 index up to ensure uniqueness between
- // it and IPv6 indexes. Although this worked, it was somewhat confusing to developers, who
- // then see interface indexes passed back that don't correspond to anything
- // that is seen in Win32 APIs or command line tools like "route". As a relatively
- // small percentage of developers are actively using IPv6, it seems to
- // make sense to make our use of IPv4 as confusion free as possible.
- // So now, IPv6 interface indexes will be shifted up by a
- // constant value which will serve to uniquely identify them, and we will
- // leave IPv4 interface indexes unmodified.
-
- switch( family )
- {
- case AF_INET: ifa->ifa_extra.index = iaa->IfIndex; break;
- case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase; break;
- default: break;
- }
-
- // Get lease lifetime
-
- if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
- {
- ifa->ifa_dhcpEnabled = TRUE;
- ifa->ifa_dhcpLeaseExpires = time( NULL ) + addr->ValidLifetime;
- }
- else
- {
- ifa->ifa_dhcpEnabled = FALSE;
- ifa->ifa_dhcpLeaseExpires = 0;
- }
-
- if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
- {
- memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
- }
-
- // Because we don't get notified of womp changes, we're going to just assume
- // that all wired interfaces have it enabled. Before we go to sleep, we'll check
- // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
- // accordingly
-
- ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
-
- // Get address.
-
- switch( family )
- {
- case AF_INET:
- case AF_INET6:
- ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
- require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
- memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
- break;
-
- default:
- break;
- }
- check( ifa->ifa_addr );
-
- // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
-
- switch ( family )
- {
- case AF_INET:
- {
- struct sockaddr_in * sa4;
-
- sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
- require_action( sa4, exit, err = WSAENOBUFS );
- sa4->sin_family = AF_INET;
- sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
-
- dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
- ifa->ifa_netmask = (struct sockaddr *) sa4;
- break;
- }
-
- case AF_INET6:
- {
- struct sockaddr_in6 *sa6;
- char buf[ 256 ] = { 0 };
- DWORD buflen = sizeof( buf );
-
- sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
- require_action( sa6, exit, err = WSAENOBUFS );
- sa6->sin6_family = AF_INET6;
- memset( sa6->sin6_addr.s6_addr, 0xFF, sizeof( sa6->sin6_addr.s6_addr ) );
- ifa->ifa_netmask = (struct sockaddr *) sa6;
-
- for ( prefix = firstPrefix; prefix; prefix = prefix->Next )
- {
- IN6_ADDR mask;
- IN6_ADDR maskedAddr;
- int maskIndex;
- DWORD len;
-
- // According to MSDN:
- // "On Windows Vista and later, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
- // include three IP adapter prefixes for each IP address assigned to the adapter. These include the host IP address prefix,
- // the subnet IP address prefix, and the subnet broadcast IP address prefix.
- // In addition, for each adapter there is a multicast address prefix and a broadcast address prefix.
- // On Windows XP with SP1 and later prior to Windows Vista, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
- // include only a single IP adapter prefix for each IP address assigned to the adapter."
-
- // We're only interested in the subnet IP address prefix. We'll determine if the prefix is the
- // subnet prefix by masking our address with a mask (computed from the prefix length) and see if that is the same
- // as the prefix address.
-
- if ( ( prefix->PrefixLength == 0 ) ||
- ( prefix->PrefixLength > 128 ) ||
- ( addr->Address.iSockaddrLength != prefix->Address.iSockaddrLength ) ||
- ( memcmp( addr->Address.lpSockaddr, prefix->Address.lpSockaddr, addr->Address.iSockaddrLength ) == 0 ) )
- {
- continue;
- }
-
- // Compute the mask
-
- memset( mask.s6_addr, 0, sizeof( mask.s6_addr ) );
-
- for ( len = (int) prefix->PrefixLength, maskIndex = 0; len > 0; len -= 8 )
- {
- uint8_t maskByte = ( len >= 8 ) ? 0xFF : (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
- mask.s6_addr[ maskIndex++ ] = maskByte;
- }
-
- // Apply the mask
-
- for ( i = 0; i < 16; i++ )
- {
- maskedAddr.s6_addr[ i ] = ( ( struct sockaddr_in6* ) addr->Address.lpSockaddr )->sin6_addr.s6_addr[ i ] & mask.s6_addr[ i ];
- }
-
- // Compare
-
- if ( memcmp( ( ( struct sockaddr_in6* ) prefix->Address.lpSockaddr )->sin6_addr.s6_addr, maskedAddr.s6_addr, sizeof( maskedAddr.s6_addr ) ) == 0 )
- {
- memcpy( sa6->sin6_addr.s6_addr, mask.s6_addr, sizeof( mask.s6_addr ) );
- break;
- }
- }
-
- WSAAddressToStringA( ( LPSOCKADDR ) sa6, sizeof( struct sockaddr_in6 ), NULL, buf, &buflen );
- dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv6 mask = %s\n", __ROUTINE__, buf );
-
- break;
- }
-
- default:
- break;
- }
- }
- }
-
- // Success!
-
- if( outAddrs )
- {
- *outAddrs = head;
- head = NULL;
- }
- err = ERROR_SUCCESS;
-
-exit:
- if( head )
- {
- freeifaddrs( head );
- }
- if( iaaList )
- {
- free( iaaList );
- }
- return( (int) err );
-}
-
-#endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
-
-//===========================================================================================================================
-// getifaddrs_ipv4
-//===========================================================================================================================
-
-mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs )
-{
- int err;
- SOCKET sock;
- DWORD size;
- DWORD actualSize;
- INTERFACE_INFO * buffer;
- INTERFACE_INFO * tempBuffer;
- INTERFACE_INFO * ifInfo;
- int n;
- int i;
- struct ifaddrs * head;
- struct ifaddrs ** next;
- struct ifaddrs * ifa;
-
- sock = INVALID_SOCKET;
- buffer = NULL;
- head = NULL;
- next = &head;
-
- // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a
- // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
- // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
-
- sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
- err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- n = 0;
- size = 16 * sizeof( INTERFACE_INFO );
- for( ;; )
- {
- tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
- require_action( tempBuffer, exit, err = WSAENOBUFS );
- buffer = tempBuffer;
-
- err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
- if( err == 0 )
- {
- break;
- }
-
- ++n;
- require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
-
- size += ( 16 * sizeof( INTERFACE_INFO ) );
- }
- check( actualSize <= size );
- check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
- n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
-
- // Process the raw interface list and build a linked list of IPv4 interfaces.
-
- for( i = 0; i < n; ++i )
- {
- uint32_t ifIndex;
- struct sockaddr_in netmask;
-
- ifInfo = &buffer[ i ];
- if( ifInfo->iiAddress.Address.sa_family != AF_INET )
- {
- continue;
- }
-
- // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
- // See comment in getifaddrs_ipv6
-
- ifIndex = 0;
- memset( &netmask, 0, sizeof( netmask ) );
- err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
-
- if ( err )
- {
- continue;
- }
-
- ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
- require_action( ifa, exit, err = WSAENOBUFS );
-
- *next = ifa;
- next = &ifa->ifa_next;
-
- // Get the name.
-
- ifa->ifa_name = (char *) malloc( 16 );
- require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
- _snprintf( ifa->ifa_name, 16, "%d", i + 1 );
-
- // Get interface flags.
-
- ifa->ifa_flags = (u_int) ifInfo->iiFlags;
-
- // Get addresses.
-
- if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
- {
- struct sockaddr_in * sa4;
-
- sa4 = &ifInfo->iiAddress.AddressIn;
- ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
- require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
- memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
-
- ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
- require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-
- // <rdar://problem/4076478> Service won't start on Win2K. The address
- // family field was not being initialized.
-
- ifa->ifa_netmask->sa_family = AF_INET;
- ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
- ifa->ifa_extra.index = ifIndex;
- }
- else
- {
- // Emulate an interface index.
-
- ifa->ifa_extra.index = (uint32_t)( i + 1 );
- }
- }
-
- // Success!
-
- if( outAddrs )
- {
- *outAddrs = head;
- head = NULL;
- }
- err = 0;
-
-exit:
-
- if( head )
- {
- freeifaddrs( head );
- }
- if( buffer )
- {
- free( buffer );
- }
- if( sock != INVALID_SOCKET )
- {
- closesocket( sock );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// freeifaddrs
-//===========================================================================================================================
-
-mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
-{
- struct ifaddrs * p;
- struct ifaddrs * q;
-
- // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
-
- for( p = inIFAs; p; p = q )
- {
- q = p->ifa_next;
-
- if( p->ifa_name )
- {
- free( p->ifa_name );
- p->ifa_name = NULL;
- }
- if( p->ifa_addr )
- {
- free( p->ifa_addr );
- p->ifa_addr = NULL;
- }
- if( p->ifa_netmask )
- {
- free( p->ifa_netmask );
- p->ifa_netmask = NULL;
- }
- if( p->ifa_broadaddr )
- {
- free( p->ifa_broadaddr );
- p->ifa_broadaddr = NULL;
- }
- if( p->ifa_dstaddr )
- {
- free( p->ifa_dstaddr );
- p->ifa_dstaddr = NULL;
- }
- if( p->ifa_data )
- {
- free( p->ifa_data );
- p->ifa_data = NULL;
- }
- free( p );
- }
-}
-
-//===========================================================================================================================
-// GetPrimaryInterface
-//===========================================================================================================================
-
-mDNSlocal DWORD
-GetPrimaryInterface()
-{
- PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
- DWORD dwSize = 0;
- BOOL bOrder = FALSE;
- OSStatus err;
- DWORD index = 0;
- DWORD metric = 0;
- unsigned long int i;
-
- // Find out how big our buffer needs to be.
-
- err = GetIpForwardTable(NULL, &dwSize, bOrder);
- require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
-
- // Allocate the memory for the table
-
- pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
- require_action( pIpForwardTable, exit, err = kNoMemoryErr );
-
- // Now get the table.
-
- err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
- require_noerr( err, exit );
-
- // Search for the row in the table we want.
-
- for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
- {
- // Look for a default route
-
- if ( pIpForwardTable->table[i].dwForwardDest == 0 )
- {
- if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
- {
- continue;
- }
-
- index = pIpForwardTable->table[i].dwForwardIfIndex;
- metric = pIpForwardTable->table[i].dwForwardMetric1;
- }
- }
-
-exit:
-
- if ( pIpForwardTable != NULL )
- {
- free( pIpForwardTable );
- }
-
- return index;
-}
-
-//===========================================================================================================================
-// AddressToIndexAndMask
-//===========================================================================================================================
-
-mDNSlocal mStatus
-AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask )
-{
- // Before calling AddIPAddress we use GetIpAddrTable to get
- // an adapter to which we can add the IP.
-
- PMIB_IPADDRTABLE pIPAddrTable = NULL;
- DWORD dwSize = 0;
- mStatus err = mStatus_UnknownErr;
- DWORD i;
-
- // For now, this is only for IPv4 addresses. That is why we can safely cast
- // addr's to sockaddr_in.
-
- require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
-
- // Make an initial call to GetIpAddrTable to get the
- // necessary size into the dwSize variable
-
- for ( i = 0; i < 100; i++ )
- {
- err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
-
- if ( err != ERROR_INSUFFICIENT_BUFFER )
- {
- break;
- }
-
- pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
- require_action( pIPAddrTable, exit, err = WSAENOBUFS );
- }
-
- require_noerr( err, exit );
- err = mStatus_UnknownErr;
-
- for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
- {
- if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
- {
- *ifIndex = pIPAddrTable->table[i].dwIndex;
- ( ( struct sockaddr_in*) mask )->sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
- err = mStatus_NoError;
- break;
- }
- }
-
-exit:
-
- if ( pIPAddrTable )
- {
- free( pIPAddrTable );
- }
-
- return err;
-}
-
-//===========================================================================================================================
-// CanReceiveUnicast
-//===========================================================================================================================
-
-mDNSlocal mDNSBool CanReceiveUnicast( void )
-{
- mDNSBool ok;
- SocketRef sock;
- struct sockaddr_in addr;
-
- // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
-
- sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
- check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
- ok = IsValidSocket( sock );
- if( ok )
- {
- mDNSPlatformMemZero( &addr, sizeof( addr ) );
- addr.sin_family = AF_INET;
- addr.sin_port = MulticastDNSPort.NotAnInteger;
- addr.sin_addr.s_addr = htonl( INADDR_ANY );
-
- ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
- close_compat( sock );
- }
-
- dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
- return( ok );
-}
-
-//===========================================================================================================================
-// IsPointToPoint
-//===========================================================================================================================
-
-mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
-{
- struct ifaddrs * addrs = NULL;
- struct ifaddrs * p = NULL;
- OSStatus err;
- mDNSBool ret = mDNSfalse;
-
- // For now, only works for IPv4 interfaces
-
- if ( addr->Address.lpSockaddr->sa_family == AF_INET )
- {
- // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
-
- err = getifaddrs_ipv4( &addrs );
- require_noerr( err, exit );
-
- for ( p = addrs; p; p = p->ifa_next )
- {
- if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
- ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
- {
- ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
- break;
- }
- }
- }
-
-exit:
-
- if ( addrs )
- {
- freeifaddrs( addrs );
- }
-
- return ret;
-}
-
-//===========================================================================================================================
-// GetWindowsVersionString
-//===========================================================================================================================
-
-mDNSlocal OSStatus GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
-{
-#if( !defined( VER_PLATFORM_WIN32_CE ) )
- #define VER_PLATFORM_WIN32_CE 3
-#endif
-
- OSStatus err;
- OSVERSIONINFO osInfo;
- BOOL ok;
- const char * versionString;
- DWORD platformID;
- DWORD majorVersion;
- DWORD minorVersion;
- DWORD buildNumber;
-
- versionString = "unknown Windows version";
-
- osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
- ok = GetVersionEx( &osInfo );
- err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- platformID = osInfo.dwPlatformId;
- majorVersion = osInfo.dwMajorVersion;
- minorVersion = osInfo.dwMinorVersion;
- buildNumber = osInfo.dwBuildNumber & 0xFFFF;
-
- if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
- {
- if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
- {
- versionString = "Windows 95";
- }
- else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
- {
- versionString = "Windows 95 SP1";
- }
- else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
- {
- versionString = "Windows 95 OSR2";
- }
- else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
- {
- versionString = "Windows 98";
- }
- else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
- {
- versionString = "Windows 98 SP1";
- }
- else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
- {
- versionString = "Windows 98 SE";
- }
- else if( minorVersion == 90 )
- {
- versionString = "Windows ME";
- }
- }
- else if( platformID == VER_PLATFORM_WIN32_NT )
- {
- if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
- {
- versionString = "Windows NT 3.51";
- }
- else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
- {
- versionString = "Windows NT 4";
- }
- else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
- {
- versionString = "Windows 2000";
- }
- else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
- {
- versionString = "Windows XP";
- }
- else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
- {
- versionString = "Windows Server 2003";
- }
- }
- else if( platformID == VER_PLATFORM_WIN32_CE )
- {
- versionString = "Windows CE";
- }
-
-exit:
- if( inBuffer && ( inBufferSize > 0 ) )
- {
- inBufferSize -= 1;
- strncpy( inBuffer, versionString, inBufferSize );
- inBuffer[ inBufferSize ] = '\0';
- }
- return( err );
-}
-
-//===========================================================================================================================
-// RegQueryString
-//===========================================================================================================================
-
-mDNSlocal mStatus
-RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
-{
- DWORD type;
- int i;
- mStatus err;
-
- *stringLen = MAX_ESCAPED_DOMAIN_NAME;
- *string = NULL;
- i = 0;
-
- do
- {
- if ( *string )
- {
- free( *string );
- }
-
- *string = (char*) malloc( *stringLen );
- require_action( *string, exit, err = mStatus_NoMemoryErr );
-
- err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
-
- i++;
- }
- while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
-
- require_noerr_quiet( err, exit );
-
- if ( enabled )
- {
- DWORD dwSize = sizeof( DWORD );
-
- err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
- check_noerr( err );
-
- err = kNoErr;
- }
-
-exit:
-
- return err;
-}
-
-//===========================================================================================================================
-// StringToAddress
-//===========================================================================================================================
-
-mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
-{
- struct sockaddr_in6 sa6;
- struct sockaddr_in sa4;
- INT dwSize;
- mStatus err;
-
- sa6.sin6_family = AF_INET6;
- dwSize = sizeof( sa6 );
-
- err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
-
- if ( err == mStatus_NoError )
- {
- err = SetupAddr( ip, (struct sockaddr*) &sa6 );
- require_noerr( err, exit );
- }
- else
- {
- sa4.sin_family = AF_INET;
- dwSize = sizeof( sa4 );
-
- err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
- err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
- require_noerr( err, exit );
-
- err = SetupAddr( ip, (struct sockaddr*) &sa4 );
- require_noerr( err, exit );
- }
-
-exit:
-
- return err;
-}
-
-//===========================================================================================================================
-// myGetIfAddrs
-//===========================================================================================================================
-
-mDNSlocal struct ifaddrs*
-myGetIfAddrs(int refresh)
-{
- static struct ifaddrs *ifa = NULL;
-
- if (refresh && ifa)
- {
- freeifaddrs(ifa);
- ifa = NULL;
- }
-
- if (ifa == NULL)
- {
- getifaddrs(&ifa);
- }
-
- return ifa;
-}
-
-//===========================================================================================================================
-// TCHARtoUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
-{
-#if( defined( UNICODE ) || defined( _UNICODE ) )
- OSStatus err;
- int len;
-
- len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
- return( err );
-#else
- return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
-#endif
-}
-
-//===========================================================================================================================
-// WindowsLatin1toUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
-{
- OSStatus err;
- WCHAR * utf16;
- int len;
-
- utf16 = NULL;
-
- // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
-
- len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
- require_action( utf16, exit, err = kNoMemoryErr );
-
- len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- // Now convert the temporary UTF-16 to UTF-8.
-
- len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
- err = translate_errno( len > 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
-exit:
- if( utf16 ) free( utf16 );
- return( err );
-}
-
-//===========================================================================================================================
-// TCPCloseSocket
-//===========================================================================================================================
-
-mDNSlocal void
-TCPCloseSocket( TCPSocket * sock )
-{
- dlog( kDebugLevelChatty, DEBUG_NAME "closing TCPSocket 0x%x:%d\n", sock, sock->fd );
-
- if ( sock->fd != INVALID_SOCKET )
- {
- closesocket( sock->fd );
- sock->fd = INVALID_SOCKET;
- }
-}
-
-//===========================================================================================================================
-// UDPCloseSocket
-//===========================================================================================================================
-
-mDNSlocal void
-UDPCloseSocket( UDPSocket * sock )
-{
- dlog( kDebugLevelChatty, DEBUG_NAME "closing UDPSocket %d\n", sock->fd );
-
- if ( sock->fd != INVALID_SOCKET )
- {
- mDNSPollUnregisterSocket( sock->fd );
- closesocket( sock->fd );
- sock->fd = INVALID_SOCKET;
- }
-}
-
-//===========================================================================================================================
-// SetupAddr
-//===========================================================================================================================
-
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
- {
- if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
-
- if (sa->sa_family == AF_INET)
- {
- struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
- ip->type = mDNSAddrType_IPv4;
- ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
- return(mStatus_NoError);
- }
-
- if (sa->sa_family == AF_INET6)
- {
- struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
- ip->type = mDNSAddrType_IPv6;
- if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
- ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
- return(mStatus_NoError);
- }
-
- LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
- return(mStatus_Invalid);
- }
-
-mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
-{
- LPSTR name = NULL;
- DWORD dwSize;
- DWORD enabled;
- HKEY key = NULL;
- OSStatus err;
-
- check( fqdn );
-
- // Initialize
-
- fqdn->c[0] = '\0';
-
- // Get info from Bonjour registry key
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
- require_noerr( err, exit );
-
- err = RegQueryString( key, "", &name, &dwSize, &enabled );
- if ( !err && ( name[0] != '\0' ) && enabled )
- {
- if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
- {
- dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
- }
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- key = NULL;
- }
-
- if ( name )
- {
- free( name );
- name = NULL;
- }
-}
-
-#ifdef UNICODE
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
-#else
-mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
-#endif
-{
- char subKeyName[kRegistryMaxKeyLength + 1];
- DWORD cSubKeys = 0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- DWORD dwSize;
- HKEY key = NULL;
- HKEY subKey = NULL;
- domainname dname;
- DWORD i;
- OSStatus err;
-
- check( domains );
-
- // Initialize
-
- *domains = NULL;
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
- require_noerr( err, exit );
-
- // Get information about this node
-
- err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );
- require_noerr( err, exit );
-
- for ( i = 0; i < cSubKeys; i++)
- {
- DWORD enabled;
-
- dwSize = kRegistryMaxKeyLength;
-
- err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-
- if ( !err )
- {
- err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
- require_noerr( err, exit );
-
- dwSize = sizeof( DWORD );
- err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-
- if ( !err && ( subKeyName[0] != '\0' ) && enabled )
- {
- if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
- {
- dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
- }
- else
- {
- DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
- require_action( domain, exit, err = mStatus_NoMemoryErr );
-
- AssignDomainName(&domain->name, &dname);
- domain->next = *domains;
-
- *domains = domain;
- }
- }
-
- RegCloseKey( subKey );
- subKey = NULL;
- }
- }
-
-exit:
-
- if ( subKey )
- {
- RegCloseKey( subKey );
- }
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
-{
- char domainUTF8[ 256 ];
- DomainAuthInfo *foundInList;
- DomainAuthInfo *ptr;
- char outDomain[ 256 ];
- char outKey[ 256 ];
- char outSecret[ 256 ];
- OSStatus err;
-
- ConvertDomainNameToCString( inDomain, domainUTF8 );
-
- // If we're able to find a secret for this domain
-
- if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
- {
- domainname domain;
- domainname key;
-
- // Tell the core about this secret
-
- MakeDomainNameFromDNSNameString( &domain, outDomain );
- MakeDomainNameFromDNSNameString( &key, outKey );
-
- for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
- if (SameDomainName(&foundInList->domain, &domain ) ) break;
-
- ptr = foundInList;
-
- if (!ptr)
- {
- ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
- require_action( ptr, exit, err = mStatus_NoMemoryErr );
- }
-
- err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, NULL, NULL, FALSE );
- require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
-
- debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
- }
-
-exit:
-
- return;
-}
-
-mDNSlocal VOID CALLBACK
-CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
-{
- mDNS * const m = ( mDNS * const ) arg;
-
- ( void ) dwTimerLowValue;
- ( void ) dwTimerHighValue;
-
- CheckFileShares( m );
-}
-
-mDNSlocal unsigned __stdcall
-SMBRegistrationThread( void * arg )
-{
- mDNS * const m = ( mDNS * const ) arg;
- DNSServiceRef sref = NULL;
- HANDLE handles[ 3 ];
- mDNSu8 txtBuf[ 256 ];
- mDNSu8 * txtPtr;
- size_t keyLen;
- size_t valLen;
- mDNSIPPort port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
- DNSServiceErrorType err;
-
- DEBUG_UNUSED( arg );
-
- handles[ 0 ] = gSMBThreadStopEvent;
- handles[ 1 ] = gSMBThreadRegisterEvent;
- handles[ 2 ] = gSMBThreadDeregisterEvent;
-
- memset( txtBuf, 0, sizeof( txtBuf ) );
- txtPtr = txtBuf;
- keyLen = strlen( "netbios=" );
- valLen = strlen( m->p->nbname );
- require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
- *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
- memcpy( txtPtr, "netbios=", keyLen );
- txtPtr += keyLen;
- if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
- keyLen = strlen( "domain=" );
- valLen = strlen( m->p->nbdomain );
- require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
- *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
- memcpy( txtPtr, "domain=", keyLen );
- txtPtr += keyLen;
- if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
-
- for ( ;; )
- {
- DWORD ret;
-
- ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
-
- if ( ret != WAIT_FAILED )
- {
- if ( ret == kSMBStopEvent )
- {
- break;
- }
- else if ( ret == kSMBRegisterEvent )
- {
- err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
-
- if ( err )
- {
- LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
- sref = NULL;
- break;
- }
- }
- else if ( ret == kSMBDeregisterEvent )
- {
- if ( sref )
- {
- gDNSServiceRefDeallocate( sref );
- sref = NULL;
- }
- }
- }
- else
- {
- LogMsg( "SMBRegistrationThread: WaitForMultipleObjects returned %d\n", GetLastError() );
- break;
- }
- }
-
-exit:
-
- if ( sref != NULL )
- {
- gDNSServiceRefDeallocate( sref );
- sref = NULL;
- }
-
- SetEvent( gSMBThreadQuitEvent );
- _endthreadex( 0 );
- return 0;
-}
-
-mDNSlocal void
-CheckFileShares( mDNS * const m )
-{
- PSHARE_INFO_1 bufPtr = ( PSHARE_INFO_1 ) NULL;
- DWORD entriesRead = 0;
- DWORD totalEntries = 0;
- DWORD resume = 0;
- mDNSBool advertise = mDNSfalse;
- mDNSBool fileSharing = mDNSfalse;
- mDNSBool printSharing = mDNSfalse;
- HKEY key = NULL;
- BOOL retry = FALSE;
- NET_API_STATUS res;
- mStatus err;
-
- check( m );
-
- // Only do this if we're not shutting down
-
- require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
-
- err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
-
- if ( !err )
- {
- DWORD dwSize = sizeof( DWORD );
- RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
- }
-
- if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
- {
- dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
-
- res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
-
- if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
- {
- PSHARE_INFO_1 p = bufPtr;
- DWORD i;
-
- for( i = 0; i < entriesRead; i++ )
- {
- // We are only interested if the user is sharing anything other
- // than the built-in "print$" source
-
- if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
- {
- fileSharing = mDNStrue;
- }
- else if ( p->shi1_type == STYPE_PRINTQ )
- {
- printSharing = mDNStrue;
- }
-
- p++;
- }
-
- NetApiBufferFree( bufPtr );
- bufPtr = NULL;
- retry = FALSE;
- }
- else if ( res == NERR_ServerNotStarted )
- {
- retry = TRUE;
- }
- }
-
- if ( retry )
- {
- __int64 qwTimeout;
- LARGE_INTEGER liTimeout;
-
- qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
- liTimeout.LowPart = ( DWORD )( qwTimeout & 0xFFFFFFFF );
- liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
-
- SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
- }
-
- if ( !m->p->smbFileSharing && fileSharing )
- {
- if ( !gSMBThread )
- {
- if ( !gDNSSDLibrary )
- {
- gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
- require_action( gDNSSDLibrary, exit, err = GetLastError() );
- }
-
- if ( !gDNSServiceRegister )
- {
- gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
- require_action( gDNSServiceRegister, exit, err = GetLastError() );
- }
-
- if ( !gDNSServiceRefDeallocate )
- {
- gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
- require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadRegisterEvent )
- {
- gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadDeregisterEvent )
- {
- gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadStopEvent )
- {
- gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
- }
-
- if ( !gSMBThreadQuitEvent )
- {
- gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
- }
-
- gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
- require_action( gSMBThread != NULL, exit, err = GetLastError() );
- }
-
- SetEvent( gSMBThreadRegisterEvent );
-
- m->p->smbFileSharing = mDNStrue;
- }
- else if ( m->p->smbFileSharing && !fileSharing )
- {
- dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
-
- if ( gSMBThreadDeregisterEvent != NULL )
- {
- SetEvent( gSMBThreadDeregisterEvent );
- }
-
- m->p->smbFileSharing = mDNSfalse;
- }
-
-exit:
-
- if ( key )
- {
- RegCloseKey( key );
- }
-}
-
-BOOL
-IsWOMPEnabled( mDNS * const m )
-{
- BOOL enabled;
-
- mDNSInterfaceData * ifd;
-
- enabled = FALSE;
-
- for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
- {
- if ( IsWOMPEnabledForAdapter( ifd->name ) )
- {
- enabled = TRUE;
- break;
- }
- }
-
- return enabled;
-}
-
-mDNSlocal mDNSu8
-IsWOMPEnabledForAdapter( const char * adapterName )
-{
- char fileName[80];
- NDIS_OID oid;
- DWORD count;
- HANDLE handle = INVALID_HANDLE_VALUE;
- NDIS_PNP_CAPABILITIES * pNPC = NULL;
- int err;
- mDNSu8 ok = TRUE;
-
- require_action( adapterName != NULL, exit, ok = FALSE );
-
- dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
-
- // Construct a device name to pass to CreateFile
-
- strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
- strcat_s( fileName, sizeof( fileName ), adapterName );
- handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
- require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
-
- // We successfully opened the driver, format the IOCTL to pass the driver.
-
- oid = OID_PNP_CAPABILITIES;
- pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
- require_action( pNPC != NULL, exit, ok = FALSE );
- ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
- err = translate_errno( ok, GetLastError(), kUnknownErr );
- require_action( !err, exit, ok = FALSE );
- ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
-
-exit:
-
- if ( pNPC != NULL )
- {
- free( pNPC );
- }
-
- if ( handle != INVALID_HANDLE_VALUE )
- {
- CloseHandle( handle );
- }
-
- dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
-
- return ( mDNSu8 ) ok;
-}
-
-mDNSlocal void
-SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep )
-{
- mDNSBool repeat = ( numTries == 1 ) ? mDNStrue : mDNSfalse;
- SOCKET sock;
- int num;
- mStatus err;
-
- ( void ) inMDNS;
-
- sock = socket( addr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
- require_action( sock != INVALID_SOCKET, exit, err = mStatus_UnknownErr );
-
- while ( numTries-- )
- {
- num = sendto( sock, ( const char* ) buf, buflen, 0, addr, addrlen );
-
- if ( num != buflen )
- {
- LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
- }
-
- if ( repeat )
- {
- num = sendto( sock, buf, buflen, 0, addr, addrlen );
-
- if ( num != buflen )
- {
- LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
- }
- }
-
- if ( msecSleep )
- {
- Sleep( msecSleep );
- }
- }
-
-exit:
-
- if ( sock != INVALID_SOCKET )
- {
- closesocket( sock );
- }
-}
-
-mDNSlocal void _cdecl
-SendMulticastWakeupPacket( void *arg )
-{
- MulticastWakeupStruct *info = ( MulticastWakeupStruct* ) arg;
-
- if ( info )
- {
- SendWakeupPacket( info->inMDNS, ( LPSOCKADDR ) &info->addr, sizeof( info->addr ), ( const char* ) info->data, sizeof( info->data ), info->numTries, info->msecSleep );
- free( info );
- }
-
- _endthread();
-}
-
-mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
- DEBUG_UNUSED( m );
- DEBUG_UNUSED( rr );
- DEBUG_UNUSED( result );
-}
+++ /dev/null
-/* -*- 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.
- */
-
-#ifndef __MDNS_WIN32__
-#define __MDNS_WIN32__
-
-#include "CommonServices.h"
-
-#if( !defined( _WIN32_WCE ) )
- #include <mswsock.h>
-#endif
-
-#include "mDNSEmbeddedAPI.h"
-#include "uDNS.h"
-
-#ifdef __cplusplus
- extern "C" {
-#endif
-
-
-typedef void ( *TCPUserCallback )();
-
-struct TCPSocket_struct
-{
- TCPSocketFlags flags; // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
- SOCKET fd;
- BOOL connected;
- TCPUserCallback userCallback;
- void * userContext;
- BOOL closed;
- mDNS * m;
-};
-
-
-struct UDPSocket_struct
-{
- mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
- mDNSAddr addr; // This is initialized by our code. If we don't get the
- // dstAddr from WSARecvMsg we use this value instead.
- SOCKET fd;
- LPFN_WSARECVMSG recvMsgPtr;
- DNSMessage packet;
- struct mDNSInterfaceData *ifd;
- UDPSocket *next;
- mDNS *m;
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct mDNSInterfaceData
-
- @abstract Structure containing interface-specific data.
-*/
-
-typedef struct mDNSInterfaceData mDNSInterfaceData;
-struct mDNSInterfaceData
-{
- char name[ 128 ];
- uint32_t index;
- uint32_t scopeID;
- struct UDPSocket_struct sock;
- NetworkInterfaceInfo interfaceInfo;
- mDNSBool hostRegistered;
- mDNSInterfaceData * next;
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @typedef ReportStatusFunc
-*/
-typedef void (*ReportStatusFunc)(int inType, const char *inFormat, ...);
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct mDNS_PlatformSupport_struct
-
- @abstract Structure containing platform-specific data.
-*/
-
-struct mDNS_PlatformSupport_struct
-{
- HANDLE mainThread;
- HANDLE checkFileSharesTimer;
- mDNSs32 checkFileSharesTimeout;
- ReportStatusFunc reportStatusFunc;
- time_t nextDHCPLeaseExpires;
- char nbname[ 32 ];
- char nbdomain[ 32 ];
- mDNSBool smbFileSharing;
- mDNSBool smbPrintSharing;
- ServiceRecordSet smbSRS;
- AuthRecord smbSubTypes[ 2 ];
- mDNSBool registeredLoopback4;
- int interfaceCount;
- mDNSInterfaceData * interfaceList;
- mDNSInterfaceData * inactiveInterfaceList;
- struct UDPSocket_struct unicastSock4;
- struct UDPSocket_struct unicastSock6;
- DWORD osMajorVersion;
- DWORD osMinorVersion;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*! @struct ifaddrs
-
- @abstract Interface information
-*/
-
-struct ifaddrs
-{
- struct ifaddrs * ifa_next;
- char * ifa_name;
- u_int ifa_flags;
- struct sockaddr * ifa_addr;
- struct sockaddr * ifa_netmask;
- struct sockaddr * ifa_broadaddr;
- struct sockaddr * ifa_dstaddr;
- BYTE ifa_physaddr[6];
- BOOL ifa_dhcpEnabled;
- time_t ifa_dhcpLeaseExpires;
- mDNSu8 ifa_womp;
- void * ifa_data;
-
- struct
- {
- uint32_t index;
-
- } ifa_extra;
-};
-
-
-extern void InterfaceListDidChange( mDNS * const inMDNS );
-extern void ComputerDescriptionDidChange( mDNS * const inMDNS );
-extern void TCPIPConfigDidChange( mDNS * const inMDNS );
-extern void DynDNSConfigDidChange( mDNS * const inMDNS );
-extern void FileSharingDidChange( mDNS * const inMDNS );
-extern void FirewallDidChange( mDNS * const inMDNS );
-extern mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock );
-extern mStatus SetupInterfaceList( mDNS * const inMDNS );
-extern mStatus TearDownInterfaceList( mDNS * const inMDNS );
-extern BOOL IsWOMPEnabled();
-extern void DispatchSocketEvents( mDNS * const inMDNS );
-
-
-#ifdef __cplusplus
- }
-#endif
-
-#endif // __MDNS_WIN32__
+++ /dev/null
-The mdnsNSP is a NameSpace Provider. It hooks into the Windows name resolution infrastructure to allow any software using the standard Windows APIs for resolving names to work with DNS-SD. For example, when the mdnsNSP is installed, you can type "http://computer.local./" in Internet Explorer and it will resolve "computer.local." using DNS-SD and go to the web site (assuming you have a computer named "computer" on the local network and advertised via DNS-SD).
-
-NSP's are implemented DLLs and must be installed to work. NSP DLLs export an NSPStartup function, which is called when the NSP is used, and NSPStartup provides information about itself (e.g. version number, compatibility information, and a list of function pointers for each of the supported NSP routines).
-
-If you need to register the mdnsNSP, you can use the NSPTool (sources for it are provided along with the mdnsNSP) with the following line from the DOS command line prompt ("<path>" is the actual parent path of the DLL):
-
-NSPTool -install "mdnsNSP" "B600E6E9-553B-4a19-8696-335E5C896153" "<path>"
-
-You can remove remove the mdnsNSP with the following line:
-
-NSPTool -remove "B600E6E9-553B-4a19-8696-335E5C896153"
-
-For more information, check out the following URL:
-
-<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/name_space_service_providers_2.asp>
+++ /dev/null
-/* -*- 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.
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "ClientCommon.h"
-#include "CommonServices.h"
-#include "DebugServices.h"
-
-#include <iphlpapi.h>
-#include <guiddef.h>
-#include <ws2spi.h>
-#include <shlwapi.h>
-
-
-
-#include "dns_sd.h"
-
-#pragma comment(lib, "DelayImp.lib")
-
-#ifdef _MSC_VER
-#define swprintf _snwprintf
-#define snprintf _snprintf
-#endif
-
-#define MAX_LABELS 128
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-// Structures
-//===========================================================================================================================
-
-typedef struct Query * QueryRef;
-typedef struct Query Query;
-struct Query
-{
- QueryRef next;
- int refCount;
- DWORD querySetFlags;
- WSAQUERYSETW * querySet;
- size_t querySetSize;
- HANDLE data4Event;
- HANDLE data6Event;
- HANDLE cancelEvent;
- HANDLE waitHandles[ 3 ];
- DWORD waitCount;
- DNSServiceRef resolver4;
- DNSServiceRef resolver6;
- char name[ kDNSServiceMaxDomainName ];
- size_t nameSize;
- uint8_t numValidAddrs;
- uint32_t addr4;
- bool addr4Valid;
- uint8_t addr6[16];
- u_long addr6ScopeId;
- bool addr6Valid;
-};
-
-#define BUFFER_INITIAL_SIZE 4192
-#define ALIASES_INITIAL_SIZE 5
-
-typedef struct HostsFile
-{
- int m_bufferSize;
- char * m_buffer;
- FILE * m_fp;
-} HostsFile;
-
-
-typedef struct HostsFileInfo
-{
- struct hostent m_host;
- struct HostsFileInfo * m_next;
-} HostsFileInfo;
-
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-// Prototypes
-//===========================================================================================================================
-
-// DLL Exports
-
-BOOL WINAPI DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
-STDAPI DllRegisterServer( void );
-STDAPI DllRegisterServer( void );
-
-
-// NSP SPIs
-
-int WSPAPI NSPCleanup( LPGUID inProviderID );
-
-DEBUG_LOCAL int WSPAPI
- NSPLookupServiceBegin(
- LPGUID inProviderID,
- LPWSAQUERYSETW inQuerySet,
- LPWSASERVICECLASSINFOW inServiceClassInfo,
- DWORD inFlags,
- LPHANDLE outLookup );
-
-DEBUG_LOCAL int WSPAPI
- NSPLookupServiceNext(
- HANDLE inLookup,
- DWORD inFlags,
- LPDWORD ioBufferLength,
- LPWSAQUERYSETW outResults );
-
-DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup );
-
-DEBUG_LOCAL int WSPAPI
- NSPSetService(
- LPGUID inProviderID,
- LPWSASERVICECLASSINFOW inServiceClassInfo,
- LPWSAQUERYSETW inRegInfo,
- WSAESETSERVICEOP inOperation,
- DWORD inFlags );
-
-DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo );
-DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID );
-DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioBufSize, LPWSASERVICECLASSINFOW ioServiceClassInfo );
-
-// Private
-
-#define NSPLock() EnterCriticalSection( &gLock );
-#define NSPUnlock() LeaveCriticalSection( &gLock );
-
-DEBUG_LOCAL OSStatus QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef );
-DEBUG_LOCAL OSStatus QueryRetain( QueryRef inRef );
-DEBUG_LOCAL OSStatus QueryRelease( QueryRef inRef );
-
-DEBUG_LOCAL void CALLBACK_COMPAT
- QueryRecordCallback4(
- DNSServiceRef inRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inErrorCode,
- const char * inName,
- uint16_t inRRType,
- uint16_t inRRClass,
- uint16_t inRDataSize,
- const void * inRData,
- uint32_t inTTL,
- void * inContext );
-
-DEBUG_LOCAL void CALLBACK_COMPAT
- QueryRecordCallback6(
- DNSServiceRef inRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inErrorCode,
- const char * inName,
- uint16_t inRRType,
- uint16_t inRRClass,
- uint16_t inRDataSize,
- const void * inRData,
- uint32_t inTTL,
- void * inContext );
-
-DEBUG_LOCAL OSStatus
- QueryCopyQuerySet(
- QueryRef inRef,
- const WSAQUERYSETW * inQuerySet,
- DWORD inQuerySetFlags,
- WSAQUERYSETW ** outQuerySet,
- size_t * outSize );
-
-DEBUG_LOCAL void
- QueryCopyQuerySetTo(
- QueryRef inRef,
- const WSAQUERYSETW * inQuerySet,
- DWORD inQuerySetFlags,
- WSAQUERYSETW * outQuerySet );
-
-DEBUG_LOCAL size_t QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags );
-
-#if( DEBUG )
- void DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet );
-
- #define dlog_query_set( LEVEL, SET ) DebugDumpQuerySet( LEVEL, SET )
-#else
- #define dlog_query_set( LEVEL, SET )
-#endif
-
-DEBUG_LOCAL BOOL InHostsTable( const char * name );
-DEBUG_LOCAL BOOL IsLocalName( HostsFileInfo * node );
-DEBUG_LOCAL BOOL IsSameName( HostsFileInfo * node, const char * name );
-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 DWORD GetScopeId( DWORD ifIndex );
-
-#ifdef ENABLE_REVERSE_LOOKUP
-DEBUG_LOCAL OSStatus IsReverseLookup( LPCWSTR name, size_t size );
-#endif
-
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-// Globals
-//===========================================================================================================================
-
-// {B600E6E9-553B-4a19-8696-335E5C896153}
-DEBUG_LOCAL HINSTANCE gInstance = NULL;
-DEBUG_LOCAL wchar_t * gNSPName = L"mdnsNSP";
-DEBUG_LOCAL GUID gNSPGUID = { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
-DEBUG_LOCAL LONG gRefCount = 0;
-DEBUG_LOCAL CRITICAL_SECTION gLock;
-DEBUG_LOCAL bool gLockInitialized = false;
-DEBUG_LOCAL QueryRef gQueryList = NULL;
-DEBUG_LOCAL HostsFileInfo * gHostsFileInfo = NULL;
-typedef DWORD
- ( WINAPI * GetAdaptersAddressesFunctionPtr )(
- ULONG inFamily,
- DWORD inFlags,
- PVOID inReserved,
- PIP_ADAPTER_ADDRESSES inAdapter,
- PULONG outBufferSize );
-
-DEBUG_LOCAL HMODULE gIPHelperLibraryInstance = NULL;
-DEBUG_LOCAL GetAdaptersAddressesFunctionPtr gGetAdaptersAddressesFunctionPtr = NULL;
-
-
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// DllMain
-//===========================================================================================================================
-
-BOOL APIENTRY DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
-{
- DEBUG_USE_ONLY( inInstance );
- DEBUG_UNUSED( inReserved );
-
- switch( inReason )
- {
- case DLL_PROCESS_ATTACH:
- gInstance = inInstance;
- gHostsFileInfo = NULL;
- debug_initialize( kDebugOutputTypeWindowsEventLog, "mDNS NSP", inInstance );
- debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelNotice );
- dlog( kDebugLevelTrace, "\n" );
- dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
-
- break;
-
- case DLL_PROCESS_DETACH:
- HostsFileInfoFree( gHostsFileInfo );
- gHostsFileInfo = NULL;
- dlog( kDebugLevelVerbose, "%s: process detach\n", __ROUTINE__ );
- break;
-
- case DLL_THREAD_ATTACH:
- dlog( kDebugLevelVerbose, "%s: thread attach\n", __ROUTINE__ );
- break;
-
- case DLL_THREAD_DETACH:
- dlog( kDebugLevelVerbose, "%s: thread detach\n", __ROUTINE__ );
- break;
-
- default:
- dlog( kDebugLevelNotice, "%s: unknown reason code (%d)\n", __ROUTINE__, inReason );
- break;
- }
-
- return( TRUE );
-}
-
-
-//===========================================================================================================================
-// DllRegisterServer
-//===========================================================================================================================
-
-STDAPI DllRegisterServer( void )
-{
- WSADATA wsd;
- WCHAR path[ MAX_PATH ];
- HRESULT err;
-
- dlog( kDebugLevelTrace, "DllRegisterServer\n" );
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- // Unregister before registering to workaround an installer
- // problem during upgrade installs.
-
- WSCUnInstallNameSpace( &gNSPGUID );
-
- err = GetModuleFileNameW( gInstance, path, MAX_PATH );
- err = translate_errno( err != 0, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- err = WSCInstallNameSpace( gNSPName, path, NS_DNS, 1, &gNSPGUID );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
-exit:
-
- WSACleanup();
- return( err );
-}
-
-//===========================================================================================================================
-// DllUnregisterServer
-//===========================================================================================================================
-
-STDAPI DllUnregisterServer( void )
-{
- WSADATA wsd;
- HRESULT err;
-
- dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
-
- err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
- err = WSCUnInstallNameSpace( &gNSPGUID );
- err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
- require_noerr( err, exit );
-
-exit:
-
- WSACleanup();
- return err;
-}
-
-
-//===========================================================================================================================
-// NSPStartup
-//
-// This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
-//===========================================================================================================================
-
-int WSPAPI NSPStartup( LPGUID inProviderID, LPNSP_ROUTINE outRoutines )
-{
- OSStatus err;
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
-
- // Only initialize if this is the first time NSPStartup is called.
-
- if( InterlockedIncrement( &gRefCount ) != 1 )
- {
- err = NO_ERROR;
- goto exit;
- }
-
- // Initialize our internal state.
-
- InitializeCriticalSection( &gLock );
- gLockInitialized = true;
-
- // Set the size to exclude NSPIoctl because we don't implement it.
-
- outRoutines->cbSize = FIELD_OFFSET( NSP_ROUTINE, NSPIoctl );
- outRoutines->dwMajorVersion = 4;
- outRoutines->dwMinorVersion = 4;
- outRoutines->NSPCleanup = NSPCleanup;
- outRoutines->NSPLookupServiceBegin = NSPLookupServiceBegin;
- outRoutines->NSPLookupServiceNext = NSPLookupServiceNext;
- outRoutines->NSPLookupServiceEnd = NSPLookupServiceEnd;
- outRoutines->NSPSetService = NSPSetService;
- outRoutines->NSPInstallServiceClass = NSPInstallServiceClass;
- outRoutines->NSPRemoveServiceClass = NSPRemoveServiceClass;
- outRoutines->NSPGetServiceClassInfo = NSPGetServiceClassInfo;
-
- // See if we can get the address for the GetAdaptersAddresses() API. This is only in XP, but we want our
- // code to run on older versions of Windows
-
- if ( !gIPHelperLibraryInstance )
- {
- gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
- if( gIPHelperLibraryInstance )
- {
- gGetAdaptersAddressesFunctionPtr = (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
- }
- }
-
- err = NO_ERROR;
-
-exit:
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- if( err != NO_ERROR )
- {
- NSPCleanup( inProviderID );
- SetLastError( (DWORD) err );
- return( SOCKET_ERROR );
- }
- return( NO_ERROR );
-}
-
-//===========================================================================================================================
-// NSPCleanup
-//
-// This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
-//===========================================================================================================================
-
-int WSPAPI NSPCleanup( LPGUID inProviderID )
-{
- DEBUG_USE_ONLY( inProviderID );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
-
- // Only initialize if this is the first time NSPStartup is called.
-
- if( InterlockedDecrement( &gRefCount ) != 0 )
- {
- goto exit;
- }
-
- // Stop any outstanding queries.
-
- if( gLockInitialized )
- {
- NSPLock();
- }
- while( gQueryList )
- {
- check_string( gQueryList->refCount == 1, "NSPCleanup with outstanding queries!" );
- QueryRelease( gQueryList );
- }
- if( gLockInitialized )
- {
- NSPUnlock();
- }
-
- if( gLockInitialized )
- {
- gLockInitialized = false;
- DeleteCriticalSection( &gLock );
- }
-
- if( gIPHelperLibraryInstance )
- {
- BOOL ok;
-
- ok = FreeLibrary( gIPHelperLibraryInstance );
- check_translated_errno( ok, GetLastError(), kUnknownErr );
- gIPHelperLibraryInstance = NULL;
- }
-
-exit:
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- return( NO_ERROR );
-}
-
-//===========================================================================================================================
-// NSPLookupServiceBegin
-//
-// This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE
-// that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as
-// opposed to specifying the query parameters each time.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI
- NSPLookupServiceBegin(
- LPGUID inProviderID,
- LPWSAQUERYSETW inQuerySet,
- LPWSASERVICECLASSINFOW inServiceClassInfo,
- DWORD inFlags,
- LPHANDLE outLookup )
-{
- OSStatus err;
- QueryRef obj;
- LPCWSTR name;
- size_t size;
- LPCWSTR p;
- DWORD type;
- DWORD n;
- DWORD i;
- INT family;
- INT protocol;
-
- DEBUG_UNUSED( inProviderID );
- DEBUG_UNUSED( inServiceClassInfo );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-
- obj = NULL;
- require_action( inQuerySet, exit, err = WSAEINVAL );
- name = inQuerySet->lpszServiceInstanceName;
- require_action_quiet( name, exit, err = WSAEINVAL );
- require_action( outLookup, exit, err = WSAEINVAL );
-
- dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__, inFlags, name );
- dlog_query_set( kDebugLevelVerbose, inQuerySet );
-
- // Check if we can handle this type of request and if we support any of the protocols being requested.
- // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
-
- require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
-
- type = inQuerySet->dwNameSpace;
- require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
-
- n = inQuerySet->dwNumberOfProtocols;
- if( n > 0 )
- {
- require_action( inQuerySet->lpafpProtocols, exit, err = WSAEINVAL );
- for( i = 0; i < n; ++i )
- {
- family = inQuerySet->lpafpProtocols[ i ].iAddressFamily;
- protocol = inQuerySet->lpafpProtocols[ i ].iProtocol;
- if( ( family == AF_INET ) && ( ( protocol == IPPROTO_UDP ) || ( protocol == IPPROTO_TCP ) ) )
- {
- break;
- }
- }
- require_action_quiet( i < n, exit, err = WSASERVICE_NOT_FOUND );
- }
-
- // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
- // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case
- // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
- // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the
- // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
-
- for( p = name; *p; ++p ) {} // Find end of string
- size = (size_t)( p - name );
- require_action_quiet( size > sizeof_string( ".local" ), exit, err = WSASERVICE_NOT_FOUND );
-
- p = name + ( size - 1 );
- p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
- if ( ( ( p[ 0 ] != '.' ) ||
- ( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) ) ||
- ( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) ) ||
- ( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) ) ||
- ( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) ) ||
- ( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
- {
-#ifdef ENABLE_REVERSE_LOOKUP
-
- err = IsReverseLookup( name, size );
-
-#else
-
- err = WSASERVICE_NOT_FOUND;
-
-#endif
-
- require_noerr( err, exit );
- }
- else
- {
- const char * replyDomain;
- char translated[ kDNSServiceMaxDomainName ];
- int n;
- int labels = 0;
- const char * label[MAX_LABELS];
- char text[64];
-
- n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL );
- require_action( n > 0, exit, err = WSASERVICE_NOT_FOUND );
-
- // <rdar://problem/4050633>
-
- // Don't resolve multi-label name
-
- // <rdar://problem/5914160> 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 && *replyDomain && labels < MAX_LABELS)
- {
- label[labels++] = replyDomain;
- replyDomain = GetNextLabel(replyDomain, text);
- }
-
- require_action( labels == 2, exit, err = WSASERVICE_NOT_FOUND );
-
- // <rdar://problem/3936771>
- //
- // Check to see if the name of this host is in the hosts table. If so,
- // don't try and resolve it
-
- require_action( InHostsTable( translated ) == FALSE, exit, err = WSASERVICE_NOT_FOUND );
- }
-
- // 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();
-
- err = QueryCreate( inQuerySet, inFlags, &obj );
- NSPUnlock();
- require_noerr( err, exit );
-
- *outLookup = (HANDLE) obj;
-
-exit:
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- if( err != NO_ERROR )
- {
- SetLastError( (DWORD) err );
- return( SOCKET_ERROR );
- }
- return( NO_ERROR );
-}
-
-//===========================================================================================================================
-// NSPLookupServiceNext
-//
-// This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined
-// query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned
-// in the lpqsResults parameter.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI
- NSPLookupServiceNext(
- HANDLE inLookup,
- DWORD inFlags,
- LPDWORD ioSize,
- LPWSAQUERYSETW outResults )
-{
- BOOL data4;
- BOOL data6;
- OSStatus err;
- QueryRef obj;
- DWORD waitResult;
- size_t size;
-
- DEBUG_USE_ONLY( inFlags );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-
- data4 = FALSE;
- data6 = FALSE;
- obj = NULL;
- NSPLock();
- err = QueryRetain( (QueryRef) inLookup );
- require_noerr( err, exit );
- obj = (QueryRef) inLookup;
- require_action( ioSize, exit, err = WSAEINVAL );
- require_action( outResults, exit, err = WSAEINVAL );
-
- dlog( kDebugLevelTrace, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__, inLookup, inFlags, *ioSize );
-
- // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
-
- NSPUnlock();
- waitResult = WaitForMultipleObjects( obj->waitCount, obj->waitHandles, FALSE, 2 * 1000 );
- NSPLock();
- require_action_quiet( waitResult != ( WAIT_OBJECT_0 ), exit, err = WSA_E_CANCELLED );
- err = translate_errno( ( waitResult == WAIT_OBJECT_0 + 1 ) || ( waitResult == WAIT_OBJECT_0 + 2 ), (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
- require_noerr_quiet( err, exit );
-
- // If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
-
- if ( waitResult == WAIT_OBJECT_0 + 1 )
- {
- data4 = TRUE;
- data6 = WaitForSingleObject( obj->data6Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
- }
-
- // Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
-
- else if ( waitResult == WAIT_OBJECT_0 + 2 )
- {
- data4 = WaitForSingleObject( obj->data4Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
- data6 = TRUE;
- }
-
- if ( data4 )
- {
- __try
- {
- err = DNSServiceProcessResult(obj->resolver4);
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- err = kUnknownErr;
- }
-
- require_noerr( err, exit );
- }
-
- if ( data6 )
- {
- __try
- {
- err = DNSServiceProcessResult( obj->resolver6 );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- err = kUnknownErr;
- }
-
- require_noerr( err, exit );
- }
-
- require_action_quiet( obj->addr4Valid || obj->addr6Valid, exit, err = WSA_E_NO_MORE );
-
- // Copy the externalized query results to the callers buffer (if it fits).
-
- size = QueryCopyQuerySetSize( obj, obj->querySet, obj->querySetFlags );
- require_action( size <= (size_t) *ioSize, exit, err = WSAEFAULT );
-
- QueryCopyQuerySetTo( obj, obj->querySet, obj->querySetFlags, outResults );
- outResults->dwOutputFlags = RESULT_IS_ADDED;
- obj->addr4Valid = false;
- obj->addr6Valid = false;
-
-exit:
- if( obj )
- {
- QueryRelease( obj );
- }
- NSPUnlock();
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- if( err != NO_ERROR )
- {
- SetLastError( (DWORD) err );
- return( SOCKET_ERROR );
- }
- return( NO_ERROR );
-}
-
-//===========================================================================================================================
-// NSPLookupServiceEnd
-//
-// This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually
-// indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any
-// allocated resources associated with the query.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup )
-{
- OSStatus err;
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-
- dlog( kDebugLevelTrace, "%s (lookup=%#p)\n", __ROUTINE__, inLookup );
-
- NSPLock();
- err = QueryRelease( (QueryRef) inLookup );
- NSPUnlock();
- require_noerr( err, exit );
-
-exit:
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- if( err != NO_ERROR )
- {
- SetLastError( (DWORD) err );
- return( SOCKET_ERROR );
- }
- return( NO_ERROR );
-}
-
-//===========================================================================================================================
-// NSPSetService
-//
-// This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or
-// deregister an instance of a server with our service. For registration, the user needs to associate the server with a
-// service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter
-// contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI
- NSPSetService(
- LPGUID inProviderID,
- LPWSASERVICECLASSINFOW inServiceClassInfo,
- LPWSAQUERYSETW inRegInfo,
- WSAESETSERVICEOP inOperation,
- DWORD inFlags )
-{
- DEBUG_UNUSED( inProviderID );
- DEBUG_UNUSED( inServiceClassInfo );
- DEBUG_UNUSED( inRegInfo );
- DEBUG_UNUSED( inOperation );
- DEBUG_UNUSED( inFlags );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-
- // We don't allow services to be registered so always return an error.
-
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- return( WSAEINVAL );
-}
-
-//===========================================================================================================================
-// NSPInstallServiceClass
-//
-// This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which
-// is used to define certain characteristics for a group of services. After a service class is registered, an actual
-// instance of a server may be registered.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo )
-{
- DEBUG_UNUSED( inProviderID );
- DEBUG_UNUSED( inServiceClassInfo );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-
- // We don't allow service classes to be installed so always return an error.
-
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- return( WSA_INVALID_PARAMETER );
-}
-
-//===========================================================================================================================
-// NSPRemoveServiceClass
-//
-// This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service
-// class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given
-// service class.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID )
-{
- DEBUG_UNUSED( inProviderID );
- DEBUG_UNUSED( inServiceClassID );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-
- // We don't allow service classes to be installed so always return an error.
-
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- return( WSATYPE_NOT_FOUND );
-}
-
-//===========================================================================================================================
-// NSPGetServiceClassInfo
-//
-// This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with
-// a given service class.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioSize, LPWSASERVICECLASSINFOW ioServiceClassInfo )
-{
- DEBUG_UNUSED( inProviderID );
- DEBUG_UNUSED( ioSize );
- DEBUG_UNUSED( ioServiceClassInfo );
-
- dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-
- // We don't allow service classes to be installed so always return an error.
-
- dlog( kDebugLevelTrace, "%s end (ticks=%d)\n", __ROUTINE__, GetTickCount() );
- return( WSATYPE_NOT_FOUND );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-// QueryCreate
-//
-// Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef )
-{
- OSStatus err;
- QueryRef obj;
- char name[ kDNSServiceMaxDomainName ];
- int n;
- QueryRef * p;
- SOCKET s4;
- SOCKET s6;
-
- obj = NULL;
- check( inQuerySet );
- check( inQuerySet->lpszServiceInstanceName );
- check( outRef );
-
- // Convert the wchar_t name to UTF-8.
-
- n = WideCharToMultiByte( CP_UTF8, 0, inQuerySet->lpszServiceInstanceName, -1, name, sizeof( name ), NULL, NULL );
- err = translate_errno( n > 0, (OSStatus) GetLastError(), WSAEINVAL );
- require_noerr( err, exit );
-
- // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
-
- obj = (QueryRef) calloc( 1, sizeof( *obj ) );
- require_action( obj, exit, err = WSA_NOT_ENOUGH_MEMORY );
-
- obj->refCount = 1;
-
- for( p = &gQueryList; *p; p = &( *p )->next ) {} // Find the end of the list.
- *p = obj;
-
- // Set up cancel event
-
- obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
- require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
-
- // Set up events to signal when A record data is ready
-
- obj->data4Event = CreateEvent( NULL, TRUE, FALSE, NULL );
- require_action( obj->data4Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
-
- // Start the query. Handle delay loaded DLL errors.
-
- __try
- {
- err = DNSServiceQueryRecord( &obj->resolver4, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordCallback4, obj );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- err = kUnknownErr;
- }
-
- require_noerr( err, exit );
-
- // Attach the socket to the event
-
- __try
- {
- s4 = DNSServiceRefSockFD(obj->resolver4);
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- s4 = INVALID_SOCKET;
- }
-
- err = translate_errno( s4 != INVALID_SOCKET, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- WSAEventSelect(s4, obj->data4Event, FD_READ|FD_CLOSE);
-
- // Set up events to signal when AAAA record data is ready
-
- obj->data6Event = CreateEvent( NULL, TRUE, FALSE, NULL );
- require_action( obj->data6Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
-
- // Start the query. Handle delay loaded DLL errors.
-
- __try
- {
- err = DNSServiceQueryRecord( &obj->resolver6, 0, 0, name, kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordCallback6, obj );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- err = kUnknownErr;
- }
-
- require_noerr( err, exit );
-
- // Attach the socket to the event
-
- __try
- {
- s6 = DNSServiceRefSockFD(obj->resolver6);
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- s6 = INVALID_SOCKET;
- }
-
- err = translate_errno( s6 != INVALID_SOCKET, errno_compat(), kUnknownErr );
- require_noerr( err, exit );
-
- WSAEventSelect(s6, obj->data6Event, FD_READ|FD_CLOSE);
-
- obj->waitCount = 0;
- obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
- obj->waitHandles[ obj->waitCount++ ] = obj->data4Event;
- obj->waitHandles[ obj->waitCount++ ] = obj->data6Event;
-
- check( obj->waitCount == sizeof_array( obj->waitHandles ) );
-
- // Copy the QuerySet so it can be returned later.
-
- obj->querySetFlags = inQuerySetFlags;
- inQuerySetFlags = ( inQuerySetFlags & ~( LUP_RETURN_ADDR | LUP_RETURN_BLOB ) ) | LUP_RETURN_NAME;
- err = QueryCopyQuerySet( obj, inQuerySet, inQuerySetFlags, &obj->querySet, &obj->querySetSize );
- require_noerr( err, exit );
-
- // Success!
-
- *outRef = obj;
- obj = NULL;
- err = NO_ERROR;
-
-exit:
- if( obj )
- {
- QueryRelease( obj );
- }
- return( err );
-}
-
-//===========================================================================================================================
-// QueryRetain
-//
-// Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus QueryRetain( QueryRef inRef )
-{
- OSStatus err;
- QueryRef obj;
-
- for( obj = gQueryList; obj; obj = obj->next )
- {
- if( obj == inRef )
- {
- break;
- }
- }
- require_action( obj, exit, err = WSA_INVALID_HANDLE );
-
- ++inRef->refCount;
- err = NO_ERROR;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// QueryRelease
-//
-// Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus QueryRelease( QueryRef inRef )
-{
- OSStatus err;
- QueryRef * p;
- BOOL ok;
-
- // Find the item in the list.
-
- for( p = &gQueryList; *p; p = &( *p )->next )
- {
- if( *p == inRef )
- {
- break;
- }
- }
- require_action( *p, exit, err = WSA_INVALID_HANDLE );
-
- // Signal a cancel to unblock any threads waiting for results.
-
- if( inRef->cancelEvent )
- {
- ok = SetEvent( inRef->cancelEvent );
- check_translated_errno( ok, GetLastError(), WSAEINVAL );
- }
-
- // Stop the query.
-
- if( inRef->resolver4 )
- {
- __try
- {
- DNSServiceRefDeallocate( inRef->resolver4 );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- }
-
- inRef->resolver4 = NULL;
- }
-
- if ( inRef->resolver6 )
- {
- __try
- {
- DNSServiceRefDeallocate( inRef->resolver6 );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- }
-
- inRef->resolver6 = NULL;
- }
-
- // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
-
- if( --inRef->refCount != 0 )
- {
- err = NO_ERROR;
- goto exit;
- }
- *p = inRef->next;
-
- // Release resources.
-
- if( inRef->cancelEvent )
- {
- ok = CloseHandle( inRef->cancelEvent );
- check_translated_errno( ok, GetLastError(), WSAEINVAL );
- }
- if( inRef->data4Event )
- {
- ok = CloseHandle( inRef->data4Event );
- check_translated_errno( ok, GetLastError(), WSAEINVAL );
- }
- if( inRef->data6Event )
- {
- ok = CloseHandle( inRef->data6Event );
- check_translated_errno( ok, GetLastError(), WSAEINVAL );
- }
- if( inRef->querySet )
- {
- free( inRef->querySet );
- }
- free( inRef );
- err = NO_ERROR;
-
-exit:
- return( err );
-}
-
-//===========================================================================================================================
-// QueryRecordCallback4
-//===========================================================================================================================
-
-DEBUG_LOCAL void CALLBACK_COMPAT
- QueryRecordCallback4(
- DNSServiceRef inRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inErrorCode,
- const char * inName,
- uint16_t inRRType,
- uint16_t inRRClass,
- uint16_t inRDataSize,
- const void * inRData,
- uint32_t inTTL,
- void * inContext )
-{
- QueryRef obj;
- const char * src;
- char * dst;
- BOOL ok;
-
- DEBUG_UNUSED( inFlags );
- DEBUG_UNUSED( inInterfaceIndex );
- DEBUG_UNUSED( inTTL );
-
- NSPLock();
- obj = (QueryRef) inContext;
- check( obj );
- require_noerr( inErrorCode, exit );
- require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
- require( inRRClass == kDNSServiceClass_IN, exit );
- require( inRRType == kDNSServiceType_A, exit );
- require( inRDataSize == 4, exit );
-
- dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
- __ROUTINE__, inFlags, inName, inRRType, inRDataSize );
-
- // Copy the name if needed.
-
- if( obj->name[ 0 ] == '\0' )
- {
- src = inName;
- dst = obj->name;
- while( *src != '\0' )
- {
- *dst++ = *src++;
- }
- *dst = '\0';
- obj->nameSize = (size_t)( dst - obj->name );
- check( obj->nameSize < sizeof( obj->name ) );
- }
-
- // Copy the data.
-
- memcpy( &obj->addr4, inRData, inRDataSize );
- obj->addr4Valid = true;
- obj->numValidAddrs++;
-
- // Signal that a result is ready.
-
- check( obj->data4Event );
- ok = SetEvent( obj->data4Event );
- check_translated_errno( ok, GetLastError(), WSAEINVAL );
-
- // Stop the resolver after the first response.
-
- __try
- {
- DNSServiceRefDeallocate( inRef );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- }
-
- obj->resolver4 = NULL;
-
-exit:
- NSPUnlock();
-}
-
-#if 0
-#pragma mark -
-#endif
-
-
-//===========================================================================================================================
-// QueryRecordCallback6
-//===========================================================================================================================
-
-DEBUG_LOCAL void CALLBACK_COMPAT
- QueryRecordCallback6(
- DNSServiceRef inRef,
- DNSServiceFlags inFlags,
- uint32_t inInterfaceIndex,
- DNSServiceErrorType inErrorCode,
- const char * inName,
- uint16_t inRRType,
- uint16_t inRRClass,
- uint16_t inRDataSize,
- const void * inRData,
- uint32_t inTTL,
- void * inContext )
-{
- QueryRef obj;
- const char * src;
- char * dst;
- BOOL ok;
-
- DEBUG_UNUSED( inFlags );
- DEBUG_UNUSED( inInterfaceIndex );
- DEBUG_UNUSED( inTTL );
-
- NSPLock();
- obj = (QueryRef) inContext;
- check( obj );
- require_noerr( inErrorCode, exit );
- require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
- require( inRRClass == kDNSServiceClass_IN, exit );
- require( inRRType == kDNSServiceType_AAAA, exit );
- require( inRDataSize == 16, exit );
-
- dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n",
- __ROUTINE__, inFlags, inName, inRRType, inRDataSize );
-
- // Copy the name if needed.
-
- if( obj->name[ 0 ] == '\0' )
- {
- src = inName;
- dst = obj->name;
- while( *src != '\0' )
- {
- *dst++ = *src++;
- }
- *dst = '\0';
- obj->nameSize = (size_t)( dst - obj->name );
- check( obj->nameSize < sizeof( obj->name ) );
- }
-
- // Copy the data.
-
- memcpy( &obj->addr6, inRData, inRDataSize );
-
- obj->addr6ScopeId = GetScopeId( inInterfaceIndex );
- require( obj->addr6ScopeId, exit );
- obj->addr6Valid = true;
- obj->numValidAddrs++;
-
- // Signal that we're done
-
- check( obj->data6Event );
- ok = SetEvent( obj->data6Event );
- check_translated_errno( ok, GetLastError(), WSAEINVAL );
-
- // Stop the resolver after the first response.
-
- __try
- {
- DNSServiceRefDeallocate( inRef );
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- }
-
- obj->resolver6 = NULL;
-
-exit:
-
-
-
- NSPUnlock();
-}
-
-
-//===========================================================================================================================
-// QueryCopyQuerySet
-//
-// Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
- QueryCopyQuerySet(
- QueryRef inRef,
- const WSAQUERYSETW * inQuerySet,
- DWORD inQuerySetFlags,
- WSAQUERYSETW ** outQuerySet,
- size_t * outSize )
-{
- OSStatus err;
- size_t size;
- WSAQUERYSETW * qs;
-
- check( inQuerySet );
- check( outQuerySet );
-
- size = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
- qs = (WSAQUERYSETW *) calloc( 1, size );
- require_action( qs, exit, err = WSA_NOT_ENOUGH_MEMORY );
-
- QueryCopyQuerySetTo( inRef, inQuerySet, inQuerySetFlags, qs );
-
- *outQuerySet = qs;
- if( outSize )
- {
- *outSize = size;
- }
- qs = NULL;
- err = NO_ERROR;
-
-exit:
- if( qs )
- {
- free( qs );
- }
- return( err );
-}
-
-
-
-//===========================================================================================================================
-// QueryCopyQuerySetTo
-//
-// Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL void
- QueryCopyQuerySetTo(
- QueryRef inRef,
- const WSAQUERYSETW * inQuerySet,
- DWORD inQuerySetFlags,
- WSAQUERYSETW * outQuerySet )
-{
- uint8_t * dst;
- LPCWSTR s;
- LPWSTR q;
- DWORD n;
- DWORD i;
-
-#if( DEBUG )
- size_t debugSize;
-
- debugSize = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
-#endif
-
- check( inQuerySet );
- check( outQuerySet );
-
- dst = (uint8_t *) outQuerySet;
-
- // Copy the static portion of the results.
-
- *outQuerySet = *inQuerySet;
- dst += sizeof( *inQuerySet );
-
- if( inQuerySetFlags & LUP_RETURN_NAME )
- {
- s = inQuerySet->lpszServiceInstanceName;
- if( s )
- {
- outQuerySet->lpszServiceInstanceName = (LPWSTR) dst;
- q = (LPWSTR) dst;
- while( ( *q++ = *s++ ) != 0 ) {}
- dst = (uint8_t *) q;
- }
- }
- else
- {
- outQuerySet->lpszServiceInstanceName = NULL;
- }
-
- if( inQuerySet->lpServiceClassId )
- {
- outQuerySet->lpServiceClassId = (LPGUID) dst;
- *outQuerySet->lpServiceClassId = *inQuerySet->lpServiceClassId;
- dst += sizeof( *inQuerySet->lpServiceClassId );
- }
-
- if( inQuerySet->lpVersion )
- {
- outQuerySet->lpVersion = (LPWSAVERSION) dst;
- *outQuerySet->lpVersion = *inQuerySet->lpVersion;
- dst += sizeof( *inQuerySet->lpVersion );
- }
-
- s = inQuerySet->lpszComment;
- if( s )
- {
- outQuerySet->lpszComment = (LPWSTR) dst;
- q = (LPWSTR) dst;
- while( ( *q++ = *s++ ) != 0 ) {}
- dst = (uint8_t *) q;
- }
-
- if( inQuerySet->lpNSProviderId )
- {
- outQuerySet->lpNSProviderId = (LPGUID) dst;
- *outQuerySet->lpNSProviderId = *inQuerySet->lpNSProviderId;
- dst += sizeof( *inQuerySet->lpNSProviderId );
- }
-
- s = inQuerySet->lpszContext;
- if( s )
- {
- outQuerySet->lpszContext = (LPWSTR) dst;
- q = (LPWSTR) dst;
- while( ( *q++ = *s++ ) != 0 ) {}
- dst = (uint8_t *) q;
- }
-
- n = inQuerySet->dwNumberOfProtocols;
-
- if( n > 0 )
- {
- check( inQuerySet->lpafpProtocols );
-
- outQuerySet->lpafpProtocols = (LPAFPROTOCOLS) dst;
- for( i = 0; i < n; ++i )
- {
- outQuerySet->lpafpProtocols[ i ] = inQuerySet->lpafpProtocols[ i ];
- dst += sizeof( *inQuerySet->lpafpProtocols );
- }
- }
-
- s = inQuerySet->lpszQueryString;
- if( s )
- {
- outQuerySet->lpszQueryString = (LPWSTR) dst;
- q = (LPWSTR) dst;
- while( ( *q++ = *s++ ) != 0 ) {}
- dst = (uint8_t *) q;
- }
-
- // Copy the address(es).
-
- if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && ( inRef->numValidAddrs > 0 ) )
- {
- struct sockaddr_in * addr4;
- struct sockaddr_in6 * addr6;
- int index;
-
- outQuerySet->dwNumberOfCsAddrs = inRef->numValidAddrs;
- outQuerySet->lpcsaBuffer = (LPCSADDR_INFO) dst;
- dst += ( sizeof( *outQuerySet->lpcsaBuffer ) ) * ( inRef->numValidAddrs ) ;
- index = 0;
-
- if ( inRef->addr4Valid )
- {
- outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr = NULL;
- outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength = 0;
-
- outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr = (LPSOCKADDR) dst;
- outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength = sizeof( struct sockaddr_in );
-
- addr4 = (struct sockaddr_in *) dst;
- memset( addr4, 0, sizeof( *addr4 ) );
- addr4->sin_family = AF_INET;
- memcpy( &addr4->sin_addr, &inRef->addr4, 4 );
- dst += sizeof( *addr4 );
-
- outQuerySet->lpcsaBuffer[ index ].iSocketType = AF_INET; // Emulate Tcpip NSP
- outQuerySet->lpcsaBuffer[ index ].iProtocol = IPPROTO_UDP; // Emulate Tcpip NSP
-
- index++;
- }
-
- if ( inRef->addr6Valid )
- {
- outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr = NULL;
- outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength = 0;
-
- outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr = (LPSOCKADDR) dst;
- outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength = sizeof( struct sockaddr_in6 );
-
- addr6 = (struct sockaddr_in6 *) dst;
- memset( addr6, 0, sizeof( *addr6 ) );
- addr6->sin6_family = AF_INET6;
- addr6->sin6_scope_id = inRef->addr6ScopeId;
- memcpy( &addr6->sin6_addr, &inRef->addr6, 16 );
- dst += sizeof( *addr6 );
-
- outQuerySet->lpcsaBuffer[ index ].iSocketType = AF_INET6; // Emulate Tcpip NSP
- outQuerySet->lpcsaBuffer[ index ].iProtocol = IPPROTO_UDP; // Emulate Tcpip NSP
- }
- }
- else
- {
- outQuerySet->dwNumberOfCsAddrs = 0;
- outQuerySet->lpcsaBuffer = NULL;
- }
-
- // Copy the hostent blob.
-
- if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
- {
- uint8_t * base;
- struct hostent * he;
- uintptr_t * p;
-
- outQuerySet->lpBlob = (LPBLOB) dst;
- dst += sizeof( *outQuerySet->lpBlob );
-
- base = dst;
- he = (struct hostent *) dst;
- dst += sizeof( *he );
-
- he->h_name = (char *)( dst - base );
- memcpy( dst, inRef->name, inRef->nameSize + 1 );
- dst += ( inRef->nameSize + 1 );
-
- he->h_aliases = (char **)( dst - base );
- p = (uintptr_t *) dst;
- *p++ = 0;
- dst = (uint8_t *) p;
-
- he->h_addrtype = AF_INET;
- he->h_length = 4;
-
- he->h_addr_list = (char **)( dst - base );
- p = (uintptr_t *) dst;
- dst += ( 2 * sizeof( *p ) );
- *p++ = (uintptr_t)( dst - base );
- *p++ = 0;
- p = (uintptr_t *) dst;
- *p++ = (uintptr_t) inRef->addr4;
- dst = (uint8_t *) p;
-
- outQuerySet->lpBlob->cbSize = (ULONG)( dst - base );
- outQuerySet->lpBlob->pBlobData = (BYTE *) base;
- }
- dlog_query_set( kDebugLevelVerbose, outQuerySet );
-
- check( (size_t)( dst - ( (uint8_t *) outQuerySet ) ) == debugSize );
-}
-
-//===========================================================================================================================
-// QueryCopyQuerySetSize
-//
-// Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL size_t QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags )
-{
- size_t size;
- LPCWSTR s;
- LPCWSTR p;
-
- check( inRef );
- check( inQuerySet );
-
- // Calculate the size of the static portion of the results.
-
- size = sizeof( *inQuerySet );
-
- if( inQuerySetFlags & LUP_RETURN_NAME )
- {
- s = inQuerySet->lpszServiceInstanceName;
- if( s )
- {
- for( p = s; *p; ++p ) {}
- size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
- }
- }
-
- if( inQuerySet->lpServiceClassId )
- {
- size += sizeof( *inQuerySet->lpServiceClassId );
- }
-
- if( inQuerySet->lpVersion )
- {
- size += sizeof( *inQuerySet->lpVersion );
- }
-
- s = inQuerySet->lpszComment;
- if( s )
- {
- for( p = s; *p; ++p ) {}
- size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
- }
-
- if( inQuerySet->lpNSProviderId )
- {
- size += sizeof( *inQuerySet->lpNSProviderId );
- }
-
- s = inQuerySet->lpszContext;
- if( s )
- {
- for( p = s; *p; ++p ) {}
- size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
- }
-
- size += ( inQuerySet->dwNumberOfProtocols * sizeof( *inQuerySet->lpafpProtocols ) );
-
- s = inQuerySet->lpszQueryString;
- if( s )
- {
- for( p = s; *p; ++p ) {}
- size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
- }
-
- // Calculate the size of the address(es).
-
- if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr4Valid )
- {
- size += sizeof( *inQuerySet->lpcsaBuffer );
- size += sizeof( struct sockaddr_in );
- }
-
- if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr6Valid )
- {
- size += sizeof( *inQuerySet->lpcsaBuffer );
- size += sizeof( struct sockaddr_in6 );
- }
-
- // Calculate the size of the hostent blob.
-
- if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
- {
- size += sizeof( *inQuerySet->lpBlob ); // Blob ptr/size structure
- size += sizeof( struct hostent ); // Old-style hostent structure
- size += ( inRef->nameSize + 1 ); // Name and null terminator
- size += 4; // Alias list terminator (0 offset)
- size += 4; // Offset to address.
- size += 4; // Address list terminator (0 offset)
- size += 4; // IPv4 address
- }
- return( size );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-#if( DEBUG )
-//===========================================================================================================================
-// DebugDumpQuerySet
-//===========================================================================================================================
-
-#define DebugSocketFamilyToString( FAM ) ( ( FAM ) == AF_INET ) ? "AF_INET" : \
- ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
-
-#define DebugSocketProtocolToString( PROTO ) ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
- ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
-
-#define DebugNameSpaceToString( NS ) ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
-
-void DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet )
-{
- DWORD i;
-
- check( inQuerySet );
-
- // Fixed portion of the QuerySet.
-
- dlog( inLevel, "QuerySet:\n" );
- dlog( inLevel, " dwSize: %d (expected %d)\n", inQuerySet->dwSize, sizeof( *inQuerySet ) );
- if( inQuerySet->lpszServiceInstanceName )
- {
- dlog( inLevel, " lpszServiceInstanceName: %S\n", inQuerySet->lpszServiceInstanceName );
- }
- else
- {
- dlog( inLevel, " lpszServiceInstanceName: <null>\n" );
- }
- if( inQuerySet->lpServiceClassId )
- {
- dlog( inLevel, " lpServiceClassId: %U\n", inQuerySet->lpServiceClassId );
- }
- else
- {
- dlog( inLevel, " lpServiceClassId: <null>\n" );
- }
- if( inQuerySet->lpVersion )
- {
- dlog( inLevel, " lpVersion:\n" );
- dlog( inLevel, " dwVersion: %d\n", inQuerySet->lpVersion->dwVersion );
- dlog( inLevel, " dwVersion: %d\n", inQuerySet->lpVersion->ecHow );
- }
- else
- {
- dlog( inLevel, " lpVersion: <null>\n" );
- }
- if( inQuerySet->lpszComment )
- {
- dlog( inLevel, " lpszComment: %S\n", inQuerySet->lpszComment );
- }
- else
- {
- dlog( inLevel, " lpszComment: <null>\n" );
- }
- dlog( inLevel, " dwNameSpace: %d %s\n", inQuerySet->dwNameSpace,
- DebugNameSpaceToString( inQuerySet->dwNameSpace ) );
- if( inQuerySet->lpNSProviderId )
- {
- dlog( inLevel, " lpNSProviderId: %U\n", inQuerySet->lpNSProviderId );
- }
- else
- {
- dlog( inLevel, " lpNSProviderId: <null>\n" );
- }
- if( inQuerySet->lpszContext )
- {
- dlog( inLevel, " lpszContext: %S\n", inQuerySet->lpszContext );
- }
- else
- {
- dlog( inLevel, " lpszContext: <null>\n" );
- }
- dlog( inLevel, " dwNumberOfProtocols: %d\n", inQuerySet->dwNumberOfProtocols );
- dlog( inLevel, " lpafpProtocols: %s\n", inQuerySet->lpafpProtocols ? "" : "<null>" );
- for( i = 0; i < inQuerySet->dwNumberOfProtocols; ++i )
- {
- if( i != 0 )
- {
- dlog( inLevel, "\n" );
- }
- dlog( inLevel, " iAddressFamily: %d %s\n", inQuerySet->lpafpProtocols[ i ].iAddressFamily,
- DebugSocketFamilyToString( inQuerySet->lpafpProtocols[ i ].iAddressFamily ) );
- dlog( inLevel, " iProtocol: %d %s\n", inQuerySet->lpafpProtocols[ i ].iProtocol,
- DebugSocketProtocolToString( inQuerySet->lpafpProtocols[ i ].iProtocol ) );
- }
- if( inQuerySet->lpszQueryString )
- {
- dlog( inLevel, " lpszQueryString: %S\n", inQuerySet->lpszQueryString );
- }
- else
- {
- dlog( inLevel, " lpszQueryString: <null>\n" );
- }
- dlog( inLevel, " dwNumberOfCsAddrs: %d\n", inQuerySet->dwNumberOfCsAddrs );
- dlog( inLevel, " lpcsaBuffer: %s\n", inQuerySet->lpcsaBuffer ? "" : "<null>" );
- for( i = 0; i < inQuerySet->dwNumberOfCsAddrs; ++i )
- {
- if( i != 0 )
- {
- dlog( inLevel, "\n" );
- }
- if( inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr &&
- ( inQuerySet->lpcsaBuffer[ i ].LocalAddr.iSockaddrLength > 0 ) )
- {
- dlog( inLevel, " LocalAddr: %##a\n",
- inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr );
- }
- else
- {
- dlog( inLevel, " LocalAddr: <null/empty>\n" );
- }
- if( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr &&
- ( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.iSockaddrLength > 0 ) )
- {
- dlog( inLevel, " RemoteAddr: %##a\n",
- inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr );
- }
- else
- {
- dlog( inLevel, " RemoteAddr: <null/empty>\n" );
- }
- dlog( inLevel, " iSocketType: %d\n", inQuerySet->lpcsaBuffer[ i ].iSocketType );
- dlog( inLevel, " iProtocol: %d\n", inQuerySet->lpcsaBuffer[ i ].iProtocol );
- }
- dlog( inLevel, " dwOutputFlags: %d\n", inQuerySet->dwOutputFlags );
-
- // Blob portion of the QuerySet.
-
- if( inQuerySet->lpBlob )
- {
- dlog( inLevel, " lpBlob:\n" );
- dlog( inLevel, " cbSize: %ld\n", inQuerySet->lpBlob->cbSize );
- dlog( inLevel, " pBlobData: %#p\n", inQuerySet->lpBlob->pBlobData );
- dloghex( inLevel, 12, NULL, 0, 0, NULL, 0,
- inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->cbSize,
- kDebugFlagsNone, NULL, 0 );
- }
- else
- {
- dlog( inLevel, " lpBlob: <null>\n" );
- }
-}
-#endif
-
-
-//===========================================================================================================================
-// InHostsTable
-//===========================================================================================================================
-
-DEBUG_LOCAL BOOL
-InHostsTable( const char * name )
-{
- HostsFileInfo * node;
- BOOL ret = FALSE;
- OSStatus err;
-
- check( name );
-
- if ( gHostsFileInfo == NULL )
- {
- TCHAR systemDirectory[MAX_PATH];
- TCHAR hFileName[MAX_PATH];
- HostsFile * hFile;
-
- GetSystemDirectory( systemDirectory, sizeof( systemDirectory ) );
- snprintf( hFileName, sizeof( hFileName ), "%s\\drivers\\etc\\hosts", systemDirectory );
- err = HostsFileOpen( &hFile, hFileName );
- require_noerr( err, exit );
-
- while ( HostsFileNext( hFile, &node ) == 0 )
- {
- if ( IsLocalName( node ) )
- {
- node->m_next = gHostsFileInfo;
- gHostsFileInfo = node;
- }
- else
- {
- HostsFileInfoFree( node );
- }
- }
-
- HostsFileClose( hFile );
- }
-
- for ( node = gHostsFileInfo; node; node = node->m_next )
- {
- if ( IsSameName( node, name ) )
- {
- ret = TRUE;
- break;
- }
- }
-
-exit:
-
- return ret;
-}
-
-
-//===========================================================================================================================
-// IsLocalName
-//===========================================================================================================================
-
-DEBUG_LOCAL BOOL
-IsLocalName( HostsFileInfo * node )
-{
- BOOL ret = TRUE;
-
- check( node );
-
- if ( strstr( node->m_host.h_name, ".local" ) == NULL )
- {
- int i;
-
- for ( i = 0; node->m_host.h_aliases[i]; i++ )
- {
- if ( strstr( node->m_host.h_aliases[i], ".local" ) )
- {
- goto exit;
- }
- }
-
- ret = FALSE;
- }
-
-exit:
-
- return ret;
-}
-
-
-//===========================================================================================================================
-// IsSameName
-//===========================================================================================================================
-
-DEBUG_LOCAL BOOL
-IsSameName( HostsFileInfo * node, const char * name )
-{
- BOOL ret = TRUE;
-
- check( node );
- check( name );
-
- if ( strcmp( node->m_host.h_name, name ) != 0 )
- {
- int i;
-
- for ( i = 0; node->m_host.h_aliases[i]; i++ )
- {
- if ( strcmp( node->m_host.h_aliases[i], name ) == 0 )
- {
- goto exit;
- }
- }
-
- ret = FALSE;
- }
-
-exit:
-
- return ret;
-}
-
-
-//===========================================================================================================================
-// HostsFileOpen
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-HostsFileOpen( HostsFile ** self, const char * fname )
-{
- OSStatus err = kNoErr;
-
- *self = (HostsFile*) malloc( sizeof( HostsFile ) );
- require_action( *self, exit, err = kNoMemoryErr );
- memset( *self, 0, sizeof( HostsFile ) );
-
- (*self)->m_bufferSize = BUFFER_INITIAL_SIZE;
- (*self)->m_buffer = (char*) malloc( (*self)->m_bufferSize );
- require_action( (*self)->m_buffer, exit, err = kNoMemoryErr );
-
- // check malloc
-
- (*self)->m_fp = fopen( fname, "r" );
- require_action( (*self)->m_fp, exit, err = kUnknownErr );
-
-exit:
-
- if ( err && *self )
- {
- HostsFileClose( *self );
- *self = NULL;
- }
-
- return err;
-}
-
-
-//===========================================================================================================================
-// HostsFileClose
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-HostsFileClose( HostsFile * self )
-{
- check( self );
-
- if ( self->m_buffer )
- {
- free( self->m_buffer );
- self->m_buffer = NULL;
- }
-
- if ( self->m_fp )
- {
- fclose( self->m_fp );
- self->m_fp = NULL;
- }
-
- free( self );
-
- return kNoErr;
-}
-
-
-//===========================================================================================================================
-// HostsFileInfoFree
-//===========================================================================================================================
-
-DEBUG_LOCAL void
-HostsFileInfoFree( HostsFileInfo * info )
-{
- while ( info )
- {
- HostsFileInfo * next = info->m_next;
-
- if ( info->m_host.h_addr_list )
- {
- if ( info->m_host.h_addr_list[0] )
- {
- free( info->m_host.h_addr_list[0] );
- info->m_host.h_addr_list[0] = NULL;
- }
-
- free( info->m_host.h_addr_list );
- info->m_host.h_addr_list = NULL;
- }
-
- if ( info->m_host.h_aliases )
- {
- int i;
-
- for ( i = 0; info->m_host.h_aliases[i]; i++ )
- {
- free( info->m_host.h_aliases[i] );
- }
-
- free( info->m_host.h_aliases );
- }
-
- if ( info->m_host.h_name )
- {
- free( info->m_host.h_name );
- info->m_host.h_name = NULL;
- }
-
- free( info );
-
- info = next;
- }
-}
-
-
-//===========================================================================================================================
-// HostsFileNext
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo )
-{
- struct sockaddr_in6 addr_6;
- struct sockaddr_in addr_4;
- int numAliases = ALIASES_INITIAL_SIZE;
- char * line;
- char * tok;
- int dwSize;
- int idx;
- int i;
- short family;
- size_t len;
- OSStatus err = kNoErr;
-
- check( self );
- check( self->m_fp );
- check( hInfo );
-
- idx = 0;
-
- *hInfo = (HostsFileInfo*) malloc( sizeof( HostsFileInfo ) );
- require_action( *hInfo, exit, err = kNoMemoryErr );
- memset( *hInfo, 0, sizeof( HostsFileInfo ) );
-
- for ( ; ; )
- {
- line = fgets( self->m_buffer + idx, self->m_bufferSize - idx, self->m_fp );
-
- if ( line == NULL )
- {
- err = 1;
- goto exit;
- }
-
- // If there's no eol and no eof, then we didn't get the whole line
-
- if ( !strchr( line, '\n' ) && !feof( self->m_fp ) )
- {
- int bufferSize;
- char * buffer;
-
- /* Try and allocate space for longer line */
-
- bufferSize = self->m_bufferSize * 2;
- buffer = (char*) realloc( self->m_buffer, bufferSize );
- require_action( buffer, exit, err = kNoMemoryErr );
- self->m_bufferSize = bufferSize;
- self->m_buffer = buffer;
- idx = (int) strlen( self->m_buffer );
-
- continue;
- }
-
- line = self->m_buffer;
- idx = 0;
-
- if (*line == '#')
- {
- continue;
- }
-
- // Get rid of either comments or eol characters
-
- if (( tok = strpbrk(line, "#\n")) != NULL )
- {
- *tok = '\0';
- }
-
- // Make sure there is some whitespace on this line
-
- if (( tok = strpbrk(line, " \t")) == NULL )
- {
- continue;
- }
-
- // Create two strings, where p == the IP Address and tok is the name list
-
- *tok++ = '\0';
-
- while ( *tok == ' ' || *tok == '\t')
- {
- tok++;
- }
-
- // Now we have the name
-
- len = strlen( tok ) + 1;
- (*hInfo)->m_host.h_name = (char*) malloc( len );
- require_action( (*hInfo)->m_host.h_name, exit, err = kNoMemoryErr );
- strcpy_s( (*hInfo)->m_host.h_name, len, tok );
-
- // Now create the address (IPv6/IPv4)
-
- addr_6.sin6_family = family = AF_INET6;
- dwSize = sizeof( addr_6 );
-
- if ( WSAStringToAddress( line, AF_INET6, NULL, ( struct sockaddr*) &addr_6, &dwSize ) != 0 )
- {
- addr_4.sin_family = family = AF_INET;
- dwSize = sizeof( addr_4 );
-
- if (WSAStringToAddress( line, AF_INET, NULL, ( struct sockaddr*) &addr_4, &dwSize ) != 0 )
- {
- continue;
- }
- }
-
- (*hInfo)->m_host.h_addr_list = (char**) malloc( sizeof( char**) * 2 );
- require_action( (*hInfo)->m_host.h_addr_list, exit, err = kNoMemoryErr );
-
- if ( family == AF_INET6 )
- {
- (*hInfo)->m_host.h_length = (short) sizeof( addr_6.sin6_addr );
- (*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
- require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
- memmove( (*hInfo)->m_host.h_addr_list[0], &addr_6.sin6_addr, sizeof( addr_6.sin6_addr ) );
-
- }
- else
- {
- (*hInfo)->m_host.h_length = (short) sizeof( addr_4.sin_addr );
- (*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
- require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
- memmove( (*hInfo)->m_host.h_addr_list[0], &addr_4.sin_addr, sizeof( addr_4.sin_addr ) );
- }
-
- (*hInfo)->m_host.h_addr_list[1] = NULL;
- (*hInfo)->m_host.h_addrtype = family;
-
- // Now get the aliases
-
- if ((tok = strpbrk(tok, " \t")) != NULL)
- {
- *tok++ = '\0';
- }
-
- i = 0;
-
- (*hInfo)->m_host.h_aliases = (char**) malloc( sizeof(char**) * numAliases );
- require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
- (*hInfo)->m_host.h_aliases[0] = NULL;
-
- while ( tok && *tok )
- {
- // Skip over the whitespace, waiting for the start of the next alias name
-
- if (*tok == ' ' || *tok == '\t')
- {
- tok++;
- continue;
- }
-
- // Check to make sure we don't exhaust the alias buffer
-
- if ( i >= ( numAliases - 1 ) )
- {
- numAliases = numAliases * 2;
- (*hInfo)->m_host.h_aliases = (char**) realloc( (*hInfo)->m_host.h_aliases, numAliases * sizeof( char** ) );
- require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
- }
-
- len = strlen( tok ) + 1;
- (*hInfo)->m_host.h_aliases[i] = (char*) malloc( len );
- require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr );
-
- strcpy_s( (*hInfo)->m_host.h_aliases[i], len, tok );
-
- if (( tok = strpbrk( tok, " \t")) != NULL )
- {
- *tok++ = '\0';
- }
-
- (*hInfo)->m_host.h_aliases[++i] = NULL;
- }
-
- break;
- }
-
-exit:
-
- if ( err && ( *hInfo ) )
- {
- HostsFileInfoFree( *hInfo );
- *hInfo = NULL;
- }
-
- return err;
-}
-
-
-#ifdef ENABLE_REVERSE_LOOKUP
-//===========================================================================================================================
-// IsReverseLookup
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-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 );
- p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
-
- if ( ( ( p[ 0 ] != '.' ) ||
- ( ( p[ 1 ] != '0' ) ) ||
- ( ( p[ 2 ] != '.' ) ) ||
- ( ( p[ 3 ] != '8' ) ) ||
- ( ( p[ 4 ] != '.' ) ) ||
- ( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) ) ||
- ( ( p[ 6 ] != '.' ) ) ||
- ( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) ) ||
- ( ( p[ 8 ] != '.' ) ) ||
- ( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) ) ||
- ( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) ) ||
- ( ( p[ 11 ] != '6' ) ) ||
- ( ( p[ 12 ] != '.' ) ) ||
- ( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) ) ||
- ( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) ) ||
- ( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) ) ||
- ( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) )
- {
- require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
-
- p = name + ( size - 1 );
- p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
-
- require_action_quiet( ( ( p[ 0 ] == '.' ) &&
- ( ( p[ 1 ] == '2' ) ) &&
- ( ( p[ 2 ] == '5' ) ) &&
- ( ( p[ 3 ] == '4' ) ) &&
- ( ( p[ 4 ] == '.' ) ) &&
- ( ( p[ 5 ] == '1' ) ) &&
- ( ( p[ 6 ] == '6' ) ) &&
- ( ( p[ 7 ] == '9' ) ) &&
- ( ( p[ 8 ] == '.' ) ) &&
- ( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) ) &&
- ( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) ) &&
- ( ( p[ 11 ] == '-' ) ) &&
- ( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) ) &&
- ( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) ) &&
- ( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) ) &&
- ( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) ) &&
- ( ( p[ 16 ] == '.' ) ) &&
- ( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) ) &&
- ( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) ) &&
- ( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) ) &&
- ( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ),
- exit, err = WSASERVICE_NOT_FOUND );
- }
-
- // It's a reverse lookup
-
- check( err == kNoErr );
-
-exit:
-
- return err;
-}
-#endif
-
-//===========================================================================================================================
-// GetScopeId
-//===========================================================================================================================
-
-DEBUG_LOCAL DWORD
-GetScopeId( DWORD ifIndex )
-{
- DWORD err;
- int i;
- DWORD flags;
- struct ifaddrs * head;
- struct ifaddrs ** next;
- IP_ADAPTER_ADDRESSES * iaaList;
- ULONG iaaListSize;
- IP_ADAPTER_ADDRESSES * iaa;
- DWORD scopeId = 0;
-
- head = NULL;
- next = &head;
- iaaList = NULL;
-
- require( gGetAdaptersAddressesFunctionPtr, exit );
-
- // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
- // This loops to handle the case where the interface changes in the window after getting the size, but before the
- // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
-
- flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
- i = 0;
- for( ;; )
- {
- iaaListSize = 0;
- err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
- check( err == ERROR_BUFFER_OVERFLOW );
- check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
-
- iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
- require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
-
- err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
- if( err == ERROR_SUCCESS ) break;
-
- free( iaaList );
- iaaList = NULL;
- ++i;
- require( i < 100, exit );
- dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
- }
-
- for( iaa = iaaList; iaa; iaa = iaa->Next )
- {
- DWORD ipv6IfIndex;
-
- if ( iaa->IfIndex > 0xFFFFFF )
- {
- continue;
- }
- if ( iaa->Ipv6IfIndex > 0xFF )
- {
- continue;
- }
-
- // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the
- // following code to crash when iterating through the prefix list. This seems
- // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
- // This shouldn't happen according to Microsoft docs which states:
- //
- // "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
- //
- // So the data structure seems to be corrupted when we return from
- // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
- // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
- // modify iaa to have the correct values.
-
- if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
- {
- ipv6IfIndex = iaa->Ipv6IfIndex;
- }
- else
- {
- ipv6IfIndex = 0;
- }
-
- // Skip psuedo and tunnel interfaces.
-
- if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
- {
- continue;
- }
-
- if ( iaa->IfIndex == ifIndex )
- {
- scopeId = iaa->Ipv6IfIndex;
- break;
- }
- }
-
-exit:
-
- if( iaaList )
- {
- free( iaaList );
- }
-
- return scopeId;
-}
+++ /dev/null
-; -*- 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.
-;
-
-LIBRARY mdnsNSP
-
-EXPORTS
- NSPStartup
- NSPCleanup
- DllRegisterServer PRIVATE
- DllUnregisterServer PRIVATE
+++ /dev/null
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.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 ""afxres.h""\r\n"
- "#include ""WinVersRes.h""\r\n"
- "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904b0"
- BEGIN
- VALUE "CompanyName", MASTER_COMPANY_NAME
- VALUE "FileDescription", "Bonjour Namespace Provider"
- VALUE "FileVersion", MASTER_PROD_VERS_STR
- VALUE "InternalName", "mdnsNSP.dll"
- VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
- VALUE "OriginalFilename", "mdnsNSP.dll"
- VALUE "ProductName", MASTER_PROD_NAME
- VALUE "ProductVersion", MASTER_PROD_VERS_STR
- END
- END
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
-
-#endif // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+++ /dev/null
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
- ProjectType="Visual C++"\r
- Version="8.00"\r
- Name="mdnsNSP"\r
- ProjectGUID="{F4F15529-F0EB-402F-8662-73C5797EE557}"\r
- Keyword="Win32Proj"\r
- >\r
- <Platforms>\r
- <Platform\r
- Name="Win32"\r
- />\r
- <Platform\r
- Name="x64"\r
- />\r
- </Platforms>\r
- <ToolFiles>\r
- </ToolFiles>\r
- <Configurations>\r
- <Configuration\r
- Name="Debug|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
- OutputFile="$(OutDir)/mdnsNSP.dll"\r
- LinkIncremental="2"\r
- ModuleDefinitionFile="mdnsNSP.def"\r
- DelayLoadDLLs="dnssd.dll"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"\r
- SubSystem="2"\r
- BaseAddress="0x64000000"\r
- ImportLibrary="$(OutDir)/mdnsNSP.lib"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Debug|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- Optimization="0"\r
- AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="3"\r
- SmallerTypeCheck="true"\r
- RuntimeLibrary="1"\r
- BufferSecurityCheck="true"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
- OutputFile="$(OutDir)/mdnsNSP.dll"\r
- LinkIncremental="2"\r
- ModuleDefinitionFile="mdnsNSP.def"\r
- DelayLoadDLLs="dnssd.dll"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"\r
- SubSystem="2"\r
- BaseAddress="0x64000000"\r
- ImportLibrary="$(OutDir)/mdnsNSP.lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|Win32"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="0"\r
- SmallerTypeCheck="false"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
- OutputFile="$(OutDir)/mdnsNSP.dll"\r
- LinkIncremental="1"\r
- ModuleDefinitionFile="mdnsNSP.def"\r
- DelayLoadDLLs="dnssd.dll"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- BaseAddress="0x64000000"\r
- ImportLibrary="$(IntDir)/mdnsNSP.lib"\r
- TargetMachine="1"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- 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
"\r
- />\r
- </Configuration>\r
- <Configuration\r
- Name="Release|x64"\r
- OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
- IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
- ConfigurationType="2"\r
- InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
- CharacterSet="2"\r
- >\r
- <Tool\r
- Name="VCPreBuildEventTool"\r
- />\r
- <Tool\r
- Name="VCCustomBuildTool"\r
- />\r
- <Tool\r
- Name="VCXMLDataGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCWebServiceProxyGeneratorTool"\r
- />\r
- <Tool\r
- Name="VCMIDLTool"\r
- TargetEnvironment="3"\r
- />\r
- <Tool\r
- Name="VCCLCompilerTool"\r
- AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
- PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
- StringPooling="true"\r
- MinimalRebuild="true"\r
- ExceptionHandling="0"\r
- BasicRuntimeChecks="0"\r
- SmallerTypeCheck="false"\r
- RuntimeLibrary="0"\r
- UsePrecompiledHeader="0"\r
- AssemblerListingLocation="$(IntDir)\"\r
- WarningLevel="4"\r
- Detect64BitPortabilityProblems="true"\r
- DebugInformationFormat="3"\r
- CallingConvention="2"\r
- />\r
- <Tool\r
- Name="VCManagedResourceCompilerTool"\r
- />\r
- <Tool\r
- Name="VCResourceCompilerTool"\r
- AdditionalIncludeDirectories="../"\r
- />\r
- <Tool\r
- Name="VCPreLinkEventTool"\r
- />\r
- <Tool\r
- Name="VCLinkerTool"\r
- AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
- AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
- OutputFile="$(OutDir)/mdnsNSP.dll"\r
- LinkIncremental="1"\r
- ModuleDefinitionFile="mdnsNSP.def"\r
- DelayLoadDLLs="dnssd.dll"\r
- GenerateDebugInformation="true"\r
- ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
- SubSystem="2"\r
- OptimizeReferences="0"\r
- EnableCOMDATFolding="0"\r
- BaseAddress="0x64000000"\r
- ImportLibrary="$(IntDir)/mdnsNSP.lib"\r
- TargetMachine="17"\r
- />\r
- <Tool\r
- Name="VCALinkTool"\r
- />\r
- <Tool\r
- Name="VCManifestTool"\r
- />\r
- <Tool\r
- Name="VCXDCMakeTool"\r
- />\r
- <Tool\r
- Name="VCBscMakeTool"\r
- />\r
- <Tool\r
- Name="VCFxCopTool"\r
- />\r
- <Tool\r
- Name="VCAppVerifierTool"\r
- />\r
- <Tool\r
- Name="VCWebDeploymentTool"\r
- />\r
- <Tool\r
- Name="VCPostBuildEventTool"\r
- 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
"\r
- />\r
- </Configuration>\r
- </Configurations>\r
- <References>\r
- </References>\r
- <Files>\r
- <Filter\r
- Name="Source Files"\r
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
- >\r
- <File\r
- RelativePath="..\..\Clients\ClientCommon.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\mdnsNSP.c"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\mdnsNSP.def"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Header Files"\r
- Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
- >\r
- <File\r
- RelativePath="..\..\Clients\ClientCommon.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\CommonServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\mDNSShared\DebugServices.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath="..\..\..\mDNSShared\dns_sd.h"\r
- >\r
- </File>\r
- <File\r
- RelativePath=".\resource.h"\r
- >\r
- </File>\r
- </Filter>\r
- <Filter\r
- Name="Resource Files"\r
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
- >\r
- <File\r
- RelativePath=".\mdnsNSP.rc"\r
- >\r
- </File>\r
- </Filter>\r
- </Files>\r
- <Globals>\r
- </Globals>\r
-</VisualStudioProject>\r
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup Label="ProjectConfigurations">\r
- <ProjectConfiguration Include="Debug|Win32">\r
- <Configuration>Debug</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Debug|x64">\r
- <Configuration>Debug</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|Win32">\r
- <Configuration>Release</Configuration>\r
- <Platform>Win32</Platform>\r
- </ProjectConfiguration>\r
- <ProjectConfiguration Include="Release|x64">\r
- <Configuration>Release</Configuration>\r
- <Platform>x64</Platform>\r
- </ProjectConfiguration>\r
- </ItemGroup>\r
- <PropertyGroup Label="Globals">\r
- <ProjectGuid>{F4F15529-F0EB-402F-8662-73C5797EE557}</ProjectGuid>\r
- <Keyword>Win32Proj</Keyword>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
- <ConfigurationType>DynamicLibrary</ConfigurationType>\r
- <CharacterSet>MultiByte</CharacterSet>\r
- </PropertyGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
- <ImportGroup Label="ExtensionSettings">\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
- <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
- </ImportGroup>\r
- <PropertyGroup Label="UserMacros" />\r
- <PropertyGroup>\r
- <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
- <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
- <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
- <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
- </PropertyGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
- <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
- <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)mdnsNSP.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <BaseAddress>0x64000000</BaseAddress>\r
- <ImportLibrary>$(OutDir)mdnsNSP.lib</ImportLibrary>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <Optimization>Disabled</Optimization>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
- <SmallerTypeCheck>true</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
- <BufferSecurityCheck>true</BufferSecurityCheck>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
- <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
- <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(OutDir)mdnsNSP.pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <BaseAddress>0x64000000</BaseAddress>\r
- <ImportLibrary>$(OutDir)mdnsNSP.lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
- <SmallerTypeCheck>false</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
- <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
- <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <BaseAddress>0x64000000</BaseAddress>\r
- <ImportLibrary>$(IntDir)mdnsNSP.lib</ImportLibrary>\r
- <TargetMachine>MachineX86</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
- <Midl>\r
- <TargetEnvironment>X64</TargetEnvironment>\r
- </Midl>\r
- <ClCompile>\r
- <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- <PreprocessorDefinitions>WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
- <StringPooling>true</StringPooling>\r
- <MinimalRebuild>true</MinimalRebuild>\r
- <ExceptionHandling>\r
- </ExceptionHandling>\r
- <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
- <SmallerTypeCheck>false</SmallerTypeCheck>\r
- <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
- <PrecompiledHeader>\r
- </PrecompiledHeader>\r
- <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
- <WarningLevel>Level4</WarningLevel>\r
- <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
- <CallingConvention>StdCall</CallingConvention>\r
- </ClCompile>\r
- <ResourceCompile>\r
- <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
- </ResourceCompile>\r
- <Link>\r
- <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
- <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
- <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
- <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
- <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
- <GenerateDebugInformation>true</GenerateDebugInformation>\r
- <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
- <SubSystem>Windows</SubSystem>\r
- <OptimizeReferences>\r
- </OptimizeReferences>\r
- <EnableCOMDATFolding>\r
- </EnableCOMDATFolding>\r
- <BaseAddress>0x64000000</BaseAddress>\r
- <ImportLibrary>$(IntDir)mdnsNSP.lib</ImportLibrary>\r
- <TargetMachine>MachineX64</TargetMachine>\r
- </Link>\r
- <PostBuildEvent>\r
- <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)" "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-:END\r
-</Command>\r
- </PostBuildEvent>\r
- </ItemDefinitionGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\Clients\ClientCommon.c" />\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
- <ClCompile Include="mdnsNSP.c" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="mdnsNSP.def" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\Clients\ClientCommon.h" />\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
- <ClInclude Include="..\..\..\mDNSShared\dns_sd.h" />\r
- <ClInclude Include="resource.h" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="mdnsNSP.rc" />\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
- <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
- <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
- </ProjectReference>\r
- </ItemGroup>\r
- <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
- <ImportGroup Label="ExtensionTargets">\r
- </ImportGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
- <ItemGroup>\r
- <Filter Include="Source Files">\r
- <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
- <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
- </Filter>\r
- <Filter Include="Header Files">\r
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
- <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
- </Filter>\r
- <Filter Include="Resource Files">\r
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
- </Filter>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClCompile Include="..\..\Clients\ClientCommon.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- <ClCompile Include="mdnsNSP.c">\r
- <Filter>Source Files</Filter>\r
- </ClCompile>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <None Include="mdnsNSP.def">\r
- <Filter>Source Files</Filter>\r
- </None>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ClInclude Include="..\..\Clients\ClientCommon.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="..\..\..\mDNSShared\dns_sd.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- <ClInclude Include="resource.h">\r
- <Filter>Header Files</Filter>\r
- </ClInclude>\r
- </ItemGroup>\r
- <ItemGroup>\r
- <ResourceCompile Include="mdnsNSP.rc">\r
- <Filter>Resource Files</Filter>\r
- </ResourceCompile>\r
- </ItemGroup>\r
-</Project>
\ No newline at end of file
+++ /dev/null
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by mdnsNSP.rc
-//
-#define IDS_PROJNAME 100
-#define IDR_WMDMLOGGER 101
-#define IDS_LOG_SEV_INFO 201
-#define IDS_LOG_SEV_WARN 202
-#define IDS_LOG_SEV_ERROR 203
-#define IDS_LOG_DATETIME 204
-#define IDS_LOG_SRCNAME 205
-#define IDS_DEF_LOGFILE 301
-#define IDS_DEF_MAXSIZE 302
-#define IDS_DEF_SHRINKTOSIZE 303
-#define IDS_DEF_LOGENABLED 304
-#define IDS_MUTEX_TIMEOUT 401
-
-// 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 101
-#endif
-#endif
+++ /dev/null
-#include "CNameRecordTests.h"
-#include "unittest_common.h"
-
-mDNSlocal int InitThisUnitTest(void);
-mDNSlocal int StartClientQueryRequest(void);
-mDNSlocal int PopulateCacheWithClientResponseRecords(void);
-mDNSlocal int SimulateNetworkChangeAndVerifyTest(void);
-mDNSlocal int FinalizeUnitTest(void);
-mDNSlocal mStatus AddDNSServer(void);
-
-// This unit test's variables
-static UDPSocket* local_socket;
-static request_state* client_request_message;
-
-struct UDPSocket_struct
-{
- mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
-};
-typedef struct UDPSocket_struct UDPSocket;
-
-// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
-uint8_t query_client_msgbuf[35] = {
- 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
- 0x01, 0x00, 0x01
-};
-
-// This uDNS message is a canned response that was originally captured by wireshark.
-uint8_t query_response_msgbuf[108] = {
- 0x69, 0x41, // transaction id
- 0x85, 0x80, // flags
- 0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
- 0x00, 0x02, // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
- 0x00, 0x01, // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
- 0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
- 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
- 0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
- 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
- 0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
-};
-
-// Variables associated with contents of the above uDNS message
-#define uDNS_TargetQID 16745
-char udns_original_domainname_cstr[] = "123server.dotbennu.com.";
-char udns_cname_domainname_cstr[] = "test212.dotbennu.com.";
-static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }};
-
-UNITTEST_HEADER(CNameRecordTests)
- UNITTEST_TEST(InitThisUnitTest)
- UNITTEST_TEST(StartClientQueryRequest)
- UNITTEST_TEST(PopulateCacheWithClientResponseRecords)
- UNITTEST_TEST(SimulateNetworkChangeAndVerifyTest)
- UNITTEST_TEST(FinalizeUnitTest)
-UNITTEST_FOOTER
-
-// The InitThisUnitTest() initializes the mDNSResponder environment as well as
-// a DNSServer. It also allocates memory for a local_socket and client request.
-// Note: This unit test does not send packets on the wire and it does not open sockets.
-UNITTEST_HEADER(InitThisUnitTest)
- // Init unit test environment and verify no error occurred.
- mStatus result = init_mdns_environment(mDNStrue);
- UNITTEST_ASSERT(result == mStatus_NoError);
-
- // Add one DNS server and verify it was added.
- AddDNSServer();
- UNITTEST_ASSERT(NumUnicastDNSServers == 1);
-
- // Create memory for a socket that is never used or opened.
- local_socket = mDNSPlatformMemAllocate(sizeof(UDPSocket));
- mDNSPlatformMemZero(local_socket, sizeof(UDPSocket));
-
- // Create memory for a request that is used to make this unit test's client request.
- client_request_message = calloc(1, sizeof(request_state));
-UNITTEST_FOOTER
-
-// This test simulates a uds client request by setting up a client request and then
-// calling mDNSResponder's handle_client_request. The handle_client_request function
-// processes the request and starts a query. This unit test verifies
-// the client request and query were setup as expected. This unit test also calls
-// mDNS_execute which determines the cache does not contain the new question's
-// answer.
-UNITTEST_HEADER(StartClientQueryRequest)
- mDNS *const m = &mDNSStorage;
- request_state* req = client_request_message;
- char *msgptr = (char *)query_client_msgbuf;
- size_t msgsz = sizeof(query_client_msgbuf);
- mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
- DNSQuestion *q;
- mStatus err = mStatus_NoError;
- char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
- // Process the unit test's client request
- start_client_request(req, msgptr, msgsz, query_request, local_socket);
- UNITTEST_ASSERT(err == mStatus_NoError);
-
- // Verify the request fields were set as expected
- UNITTEST_ASSERT(req->next == mDNSNULL);
- UNITTEST_ASSERT(req->primary == mDNSNULL);
- UNITTEST_ASSERT(req->sd == client_req_sd);
- UNITTEST_ASSERT(req->process_id == client_req_process_id);
- UNITTEST_ASSERT(!strcmp(req->pid_name, client_req_pid_name));
- UNITTEST_ASSERT(req->validUUID == mDNSfalse);
- UNITTEST_ASSERT(req->errsd == 0);
- UNITTEST_ASSERT(req->uid == client_req_uid);
- UNITTEST_ASSERT(req->ts == t_complete);
- UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
- UNITTEST_ASSERT(req->msgend == msgptr+msgsz);
- UNITTEST_ASSERT(req->msgbuf == mDNSNULL);
- UNITTEST_ASSERT(req->hdr.version == VERSION);
- UNITTEST_ASSERT(req->replies == mDNSNULL);
- UNITTEST_ASSERT(req->terminate != mDNSNULL);
- UNITTEST_ASSERT(req->flags == kDNSServiceFlagsReturnIntermediates);
- UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexAny);
-
- // Verify the query fields were set as expected
- q = &req->u.queryrecord.q;
- UNITTEST_ASSERT(q != mDNSNULL);
- UNITTEST_ASSERT(q == m->Questions);
- UNITTEST_ASSERT(q == m->NewQuestions);
- UNITTEST_ASSERT(q->SuppressUnusable == mDNSfalse);
- UNITTEST_ASSERT(q->ReturnIntermed == mDNStrue);
- UNITTEST_ASSERT(q->SuppressQuery == mDNSfalse);
-
- UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
- ConvertDomainNameToCString(&q->qname, qname_cstr);
- UNITTEST_ASSERT(!strcmp(qname_cstr, udns_original_domainname_cstr));
- UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
-
- UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_Any);
- UNITTEST_ASSERT(q->flags == req->flags);
- UNITTEST_ASSERT(q->qtype == 1);
- UNITTEST_ASSERT(q->qclass == 1);
- UNITTEST_ASSERT(q->LongLived == 0);
- UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
- UNITTEST_ASSERT(q->ForceMCast == 0);
- UNITTEST_ASSERT(q->TimeoutQuestion == 0);
- UNITTEST_ASSERT(q->WakeOnResolve == 0);
- UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
- UNITTEST_ASSERT(q->ValidationRequired == 0);
- UNITTEST_ASSERT(q->ValidatingResponse == 0);
- UNITTEST_ASSERT(q->ProxyQuestion == 0);
- UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
- UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
- UNITTEST_ASSERT(q->QuestionContext == req);
- UNITTEST_ASSERT(q->SearchListIndex == 0);
- UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
- UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
- UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
- UNITTEST_ASSERT(q->AppendSearchDomains == 0);
- UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
- UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
-
- // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
- // It won't be yet because the cache is empty.
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m);
-
- // Verify mDNS_Execute processed the new question.
- UNITTEST_ASSERT(m->NewQuestions == mDNSNULL);
-
- // Verify the cache is empty and the request got no reply.
- UNITTEST_ASSERT(m->rrcache_totalused == 0);
- UNITTEST_ASSERT(req->replies == mDNSNULL);
-
-UNITTEST_FOOTER
-
-// This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function.
-// It then verifies cache entries were added for the CNAME and A records that were contained in the
-// answers of the canned response, query_response_msgbuf. This unit test also verifies that
-// 2 add events were generated for the client.
-UNITTEST_HEADER(PopulateCacheWithClientResponseRecords)
- mDNS *const m = &mDNSStorage;
- DNSMessage *msgptr = (DNSMessage *)query_response_msgbuf;
- size_t msgsz = sizeof(query_response_msgbuf);
- struct reply_state *reply;
- request_state* req = client_request_message;
- DNSQuestion *q = &req->u.queryrecord.q;
- const char *data;
- const char *end;
- char name[kDNSServiceMaxDomainName];
- uint16_t rrtype, rrclass, rdlen;
- const char *rdata;
- size_t len;
- char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
- // Receive and populate the cache with canned response
- receive_response(req, msgptr, msgsz);
-
- // Verify 2 cache entries for CName and A record are present
- mDNSu32 CacheUsed =0, notUsed =0;
- LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used);
- UNITTEST_ASSERT(CacheUsed == m->rrcache_totalused);
- UNITTEST_ASSERT(CacheUsed == 4); // 2 for the CacheGroup object plus 2 for the A and CNAME records
- UNITTEST_ASSERT(m->PktNum == 1); // one packet was received
-
- // Verify question's qname is now set with the A record's domainname
- UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
- ConvertDomainNameToCString(&q->qname, domainname_cstr);
- UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
- UNITTEST_ASSERT(!strcmp(domainname_cstr, udns_cname_domainname_cstr));
-
- // Verify client's add event for CNAME is properly formed
- reply = req->replies;
- UNITTEST_ASSERT(reply != mDNSNULL);
- UNITTEST_ASSERT(reply->next == mDNSNULL);
-
- data = (char *)&reply->rhdr[1];
- end = data+reply->totallen;
- get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
- rrtype = get_uint16(&data, end);
- rrclass = get_uint16(&data, end);
- rdlen = get_uint16(&data, end);
- rdata = get_rdata(&data, end, rdlen);
- len = get_reply_len(name, rdlen);
-
- UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
- UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
- UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
- UNITTEST_ASSERT(rrtype == kDNSType_CNAME);
- UNITTEST_ASSERT(rrclass == kDNSClass_IN);
- ConvertDomainNameToCString((const domainname *const)rdata, domainname_cstr);
- UNITTEST_ASSERT(!strcmp(domainname_cstr, "test212.dotbennu.com."));
-
- // The mDNS_Execute call generates an add event for the A record
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m);
-
- // Verify the client's reply contains a properly formed add event for the A record.
- reply = req->replies;
- UNITTEST_ASSERT(reply != mDNSNULL);
- UNITTEST_ASSERT(reply->next != mDNSNULL);
- reply = reply->next;
-
- data = (char *)&reply->rhdr[1];
- end = data+reply->totallen;
- get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
- rrtype = get_uint16(&data, end);
- rrclass = get_uint16(&data, end);
- rdlen = get_uint16(&data, end);
- rdata = get_rdata(&data, end, rdlen);
- len = get_reply_len(name, rdlen);
-
- UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
-
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
- UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
- UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
- UNITTEST_ASSERT(rrtype == kDNSType_A);
- UNITTEST_ASSERT(rrclass == kDNSClass_IN);
- UNITTEST_ASSERT(rdata[0] == dns_response_ipv4.b[0]);
- UNITTEST_ASSERT(rdata[1] == dns_response_ipv4.b[1]);
- UNITTEST_ASSERT(rdata[2] == dns_response_ipv4.b[2]);
- UNITTEST_ASSERT(rdata[3] == dns_response_ipv4.b[3]);
-
-UNITTEST_FOOTER
-
-// This function verifies the cache and event handling occurred as expected when a network change happened.
-// The uDNS_SetupDNSConfig is called to simulate a network change and two outcomes occur. First the A record
-// query is restarted and sent to a new DNS server. Second the cache records are purged. Then mDNS_Execute
-// is called and it removes the purged cache records and generates a remove event for the A record.
-// The following are verified:
-// 1.) The restart of query for A record.
-// 2.) The cache is empty after mDNS_Execute removes the cache entres.
-// 3.) The remove event is verified by examining the request's reply data.
-UNITTEST_HEADER(SimulateNetworkChangeAndVerifyTest)
- mDNS *const m = &mDNSStorage;
- request_state* req = client_request_message;
- DNSQuestion* q = &req->u.queryrecord.q;
- mDNSu32 CacheUsed =0, notUsed =0;
- const char *data; const char *end;
- char name[kDNSServiceMaxDomainName];
- uint16_t rrtype, rrclass, rdlen;
- const char *rdata;
- size_t len;
-
- // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and
- // both the CNAME and A record are purged.
- uDNS_SetupDNSConfig(m);
-
- // Verify the A record query was restarted. This is done indirectly by noticing the transaction id and interval have changed.
- UNITTEST_ASSERT(q->ThisQInterval == InitialQuestionInterval);
- UNITTEST_ASSERT(q->TargetQID.NotAnInteger != uDNS_TargetQID);
-
- // Then mDNS_Execute removes both records from the cache and calls the client back with a remove event for A record.
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m);
-
- // Verify the cache entries are removed
- LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, ¬Used);
- UNITTEST_ASSERT(CacheUsed == m->rrcache_totalused);
- UNITTEST_ASSERT(CacheUsed == 0);
-
- // Verify the A record's remove event is setup as expected in the reply data
- struct reply_state *reply;
- reply = req->replies;
- UNITTEST_ASSERT(reply != mDNSNULL);
-
- UNITTEST_ASSERT(reply != mDNSNULL);
- UNITTEST_ASSERT(reply->next != mDNSNULL);
- UNITTEST_ASSERT(reply->next->next != mDNSNULL);
-
- reply = reply->next->next; // Get to last event to verify remove event
- data = (char *)&reply->rhdr[1];
- end = data+reply->totallen;
- get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
- rrtype = get_uint16(&data, end);
- rrclass = get_uint16(&data, end);
- rdlen = get_uint16(&data, end);
- rdata = get_rdata(&data, end, rdlen);
- len = get_reply_len(name, rdlen);
-
- UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
- UNITTEST_ASSERT(reply->rhdr->flags != htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
- UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
- UNITTEST_ASSERT(rrtype == kDNSType_A);
- UNITTEST_ASSERT(rrclass == kDNSClass_IN);
- UNITTEST_ASSERT(rdata[0] == dns_response_ipv4.b[0]);
- UNITTEST_ASSERT(rdata[1] == dns_response_ipv4.b[1]);
- UNITTEST_ASSERT(rdata[2] == dns_response_ipv4.b[2]);
- UNITTEST_ASSERT(rdata[3] == dns_response_ipv4.b[3]);
-
-UNITTEST_FOOTER
-
-// This function does memory cleanup and no verification.
-UNITTEST_HEADER(FinalizeUnitTest)
- mDNS *m = &mDNSStorage;
- request_state* req = client_request_message;
- DNSServer *ptr, **p = &m->DNSServers;
-
- while (req->replies)
- {
- reply_state *reply = req->replies;
- req->replies = req->replies->next;
- mDNSPlatformMemFree(reply);
- }
- mDNSPlatformMemFree(req);
-
- mDNSPlatformMemFree(local_socket);
-
- while (*p)
- {
- ptr = *p;
- *p = (*p)->next;
- LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
- mDNSPlatformMemFree(ptr);
- }
-UNITTEST_FOOTER
-
-// The mDNS_AddDNSServer function adds a dns server to mDNSResponder's list.
-mDNSlocal mStatus AddDNSServer(void)
-{
- mDNS *m = &mDNSStorage;
- m->timenow = 0;
- mDNS_Lock(m);
- domainname d;
- mDNSAddr addr;
- mDNSIPPort port;
- mDNSs32 serviceID = 0;
- mDNSu32 scoped = 0;
- mDNSu32 timeout = dns_server_timeout;
- mDNSBool cellIntf = 0;
- mDNSBool isExpensive = 0;
- mDNSBool isCLAT46 = mDNSfalse;
- mDNSu16 resGroupID = dns_server_resGroupID;
- mDNSBool reqA = mDNStrue;
- mDNSBool reqAAAA = mDNStrue;
- mDNSBool reqDO = mDNSfalse;
- d.c[0] = 0;
- addr.type = mDNSAddrType_IPv4;
- addr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger;
- port.NotAnInteger = client_resp_src_port;
- mDNS_AddDNSServer(m, &d, primary_interfaceID, serviceID, &addr, port, scoped, timeout,
- cellIntf, isExpensive, isCLAT46, resGroupID,
- reqA, reqAAAA, reqDO);
- mDNS_Unlock(m);
- return mStatus_NoError;
-}
-
-
+++ /dev/null
-
-#ifndef ReconfirmRecordTests_h
-#define ReconfirmRecordTests_h
-
-#include "unittest.h"
-
-int CNameRecordTests(void);
-
-#endif /* ReconfirmRecordTests_h */
+++ /dev/null
-#include "mDNSEmbeddedAPI.h"
-#include "DNSMessageTest.h"
-#include "../mDNSCore/DNSCommon.h"
-
-int SizeTest(void);
-int InitializeTest(void);
-int PutDomainNameAsLabels(void);
-int PutRData(void);
-int Finalize(void);
-
-
-DNSMessage *msg;
-
-
-UNITTEST_HEADER(DNSMessageTest)
- UNITTEST_TEST(SizeTest)
- UNITTEST_TEST(InitializeTest)
- UNITTEST_TEST(Finalize)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(SizeTest)
- msg = (DNSMessage *)malloc (sizeof(DNSMessage));
- UNITTEST_ASSERT_RETURN(msg != NULL);
-
- // message header should be 12 bytes
- UNITTEST_ASSERT(sizeof(msg->h) == 12);
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(InitializeTest)
- // Initialize the message
- InitializeDNSMessage(&msg->h, onesID, QueryFlags);
-
- // Check that the message is initialized properly
- UNITTEST_ASSERT(msg->h.numAdditionals == 0);
- UNITTEST_ASSERT(msg->h.numAnswers == 0);
- UNITTEST_ASSERT(msg->h.numQuestions == 0);
- UNITTEST_ASSERT(msg->h.numAuthorities == 0);
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(PutDomainNameAsLabels)
-
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(Finalize)
- UNITTEST_ASSERT_RETURN(msg != NULL)
- free(msg);
-UNITTEST_FOOTER
\ No newline at end of file
+++ /dev/null
-#ifndef DNSMessageTest_h
-#define DNSMessageTest_h
-
-#include "unittest.h"
-
-int DNSMessageTest(void);
-
-#endif /* DNSMessageTest_h */
\ No newline at end of file
+++ /dev/null
-#include "DomainNameTest.h"
-#include "mDNSEmbeddedAPI.h"
-#include "../mDNSCore/DNSCommon.h"
-
-int SameDomainNameTest(void);
-int SameDomainLabelTest(void);
-int LocalDomainTest(void);
-
-
-UNITTEST_HEADER(DomainNameTest)
- UNITTEST_TEST(SameDomainLabelTest)
- UNITTEST_TEST(SameDomainNameTest)
- UNITTEST_TEST(LocalDomainTest)
-UNITTEST_FOOTER
-
-
-
-
-UNITTEST_HEADER(SameDomainLabelTest)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(SameDomainNameTest)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(LocalDomainTest)
-UNITTEST_FOOTER
\ No newline at end of file
+++ /dev/null
-#ifndef DomainNameTest_h
-#define DomainNameTest_h
-
-#include "unittest.h"
-int DomainNameTest(void);
-
-#endif /* DomainNameTest_h */
+++ /dev/null
-#include "InterfaceTest.h"
-#include "mDNSEmbeddedAPI.h"
-
-
-NetworkInterfaceInfo *intf;
-mDNS *m;
-
-int LocalSubnetTest(void);
-
-UNITTEST_HEADER(InterfaceTest)
- UNITTEST_TEST(LocalSubnetTest)
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(LocalSubnetTest)
- // need a way to initialize m before we call into the class of APIs that use a ptr to mDNS
- // should that pointer be common to all tests?
- // mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
- // TEST_ASSERT_RETURN (for IPv4/IPv6 local subnet)
-UNITTEST_FOOTER
+++ /dev/null
-
-#ifndef InterfaceTest_h
-#define InterfaceTest_h
-
-#include "unittest.h"
-
-int InterfaceTest(void);
-
-#endif /* InterfaceTest_h */
+++ /dev/null
-#include "LocalOnlyTimeoutTests.h"
-#include "unittest_common.h"
-
-mDNSlocal int InitUnitTest(void);
-mDNSlocal int StartLocalOnlyClientQueryRequest(void);
-mDNSlocal int PopulateCacheWithClientLOResponseRecords(void);
-mDNSlocal int RestartLocalOnlyClientQueryRequest(void);
-mDNSlocal int FinalizeUnitTest(void);
-mDNSlocal mStatus InitEtcHostsRecords();
-
-// This unit test's variables
-static request_state* client_request_message;
-static UDPSocket* local_socket;
-static char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
-// This query request message was generated from the following command: "dns-sd -lo -timeout -Q cardinal2.apple.com. A"
-char query_req_msgbuf[33]= {
- 0x00, 0x01, 0x90, 0x00,
- // DNSServiceFlags.L = (kDNSServiceFlagsReturnIntermediates |kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout)
- 0xff, 0xff, 0xff, 0xff,
- // interfaceIndex = mDNSInterface_LocalOnly
- 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,
- 0x32, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x00, 0x00, 0x01, 0x00,
- 0x01
-};
-
-UNITTEST_HEADER(LocalOnlyTimeoutTests)
- UNITTEST_TEST(InitUnitTest)
- UNITTEST_TEST(StartLocalOnlyClientQueryRequest)
- UNITTEST_TEST(PopulateCacheWithClientLOResponseRecords)
- UNITTEST_TEST(RestartLocalOnlyClientQueryRequest)
- UNITTEST_TEST(FinalizeUnitTest)
-UNITTEST_FOOTER
-
-// The InitUnitTest() initializes a minimal mDNSResponder environment as
-// well as allocates memory for a local_socket and client request.
-// It also sets the domainname_cstr specified in the client's query request.
-// Note: This unit test does not send packets on the wire and it does not open sockets.
-UNITTEST_HEADER(InitUnitTest)
-
- // Init mDNSStorage
- mStatus result = init_mdns_storage();
- if (result != mStatus_NoError)
- return result;
-
- // Allocate a client request
- local_socket = calloc(1, sizeof(request_state));
-
- // Allocate memory for a request that is used to make client requests.
- client_request_message = calloc(1, sizeof(request_state));
-
- // Init domainname that is used by unit tests
- strlcpy(domainname_cstr, "cardinal2.apple.com.", sizeof(domainname_cstr));
-
-UNITTEST_FOOTER
-
-// This unit test starts a local only request for "cardinal2.apple.com.". It first
-// calls start_client_request to start a query, it then verifies the
-// req and query data structures are set as expected. Next, the cache is verified to
-// be empty by AnswerNewLocalOnlyQuestion() and so results in GenerateNegativeResponse()
-// getting called which sets up a reply with a negative answer in it for the client.
-// On return from mDNS_Execute, the client's reply structure is verified to be set as
-// expected. Lastly the timeout is simulated and mDNS_Execute is called. This results
-// in a call to TimeoutQuestions(). And again, the GenerateNegativeResponse() is called
-// which returns a negative response to the client. This time the client reply is verified
-// to be setup with a timeout result.
-UNITTEST_HEADER(StartLocalOnlyClientQueryRequest)
-
- mDNS *const m = &mDNSStorage;
- request_state* req = client_request_message;
- char *msgptr = (char *)query_req_msgbuf;
- size_t msgsz = sizeof(query_req_msgbuf);
- DNSQuestion *q;
- mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
- mStatus err = mStatus_NoError;
- char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
- struct reply_state *reply;
- size_t len;
-
- // Process the unit test's client request
- start_client_request(req, msgptr, msgsz, query_request, local_socket);
- UNITTEST_ASSERT(err == mStatus_NoError);
-
- // Verify the query initialized and request fields were set as expected
- UNITTEST_ASSERT(err == mStatus_NoError);
- UNITTEST_ASSERT(req->hdr.version == VERSION);
- UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
- UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
- UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
- UNITTEST_ASSERT(req->terminate != mDNSNULL);
-
- q = &req->u.queryrecord.q;
- UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
- UNITTEST_ASSERT(m->Questions == NULL);
- UNITTEST_ASSERT(m->NewQuestions == NULL);
- UNITTEST_ASSERT(q->SuppressUnusable == 1);
- UNITTEST_ASSERT(q->ReturnIntermed == 1);
- UNITTEST_ASSERT(q->SuppressQuery == 0); // Regress <rdar://problem/27571734>
-
- UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
- ConvertDomainNameToCString(&q->qname, qname_cstr);
- UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
- UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
-
- UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
- UNITTEST_ASSERT(q->flags == req->flags);
- UNITTEST_ASSERT(q->qtype == 1);
- UNITTEST_ASSERT(q->qclass == 1);
- UNITTEST_ASSERT(q->LongLived == 0);
- UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
- UNITTEST_ASSERT(q->ForceMCast == 0);
- UNITTEST_ASSERT(q->TimeoutQuestion == 1);
- UNITTEST_ASSERT(q->WakeOnResolve == 0);
- UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
- UNITTEST_ASSERT(q->ValidationRequired == 0);
- UNITTEST_ASSERT(q->ValidatingResponse == 0);
- UNITTEST_ASSERT(q->ProxyQuestion == 0);
- UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
- UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
- UNITTEST_ASSERT(q->QuestionContext == req);
- UNITTEST_ASSERT(q->SearchListIndex == 0);
- UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
- UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
- UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
- UNITTEST_ASSERT(q->StopTime != 0);
- UNITTEST_ASSERT(q->AppendSearchDomains == 0);
- UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
- UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
-
- // At this point the the cache is empty. Calling mDNS_Execute will answer the local-only
- // question with a negative response.
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m); // Regress <rdar://problem/28721294>
-
- // Verify reply is a negative response and error code is set to kDNSServiceErr_NoSuchRecord error.
- reply = req->replies;
- UNITTEST_ASSERT(reply != mDNSNULL);
-
- UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
- UNITTEST_ASSERT(q->LOAddressAnswers == 0);
-
- len = get_reply_len(qname_cstr, 0);
-
- UNITTEST_ASSERT(reply->next == mDNSNULL);
- UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
- UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
- UNITTEST_ASSERT(reply->rhdr->error ==
- (DNSServiceErrorType)htonl(kDNSServiceErr_NoSuchRecord)); // Regress <rdar://problem/24827555>
-
- // Simulate what udsserver_idle normally does for clean up
- freeL("StartLocalOnlyClientQueryRequest:reply", reply);
- req->replies = NULL;
-
- // Simulate the query time out of the local-only question.
- // The expected behavior is a negative answer with time out error
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- q->StopTime = mDNS_TimeNow_NoLock(m);
- m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
- mDNS_Execute(m);
-
- // Verify the reply is a negative response with timeout error.
- reply = req->replies;
- UNITTEST_ASSERT(reply != NULL);
- UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
- UNITTEST_ASSERT(q->LOAddressAnswers == 0);
-
- len = get_reply_len(qname_cstr, 0);
-
- UNITTEST_ASSERT(reply->next == mDNSNULL);
- UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
- UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
- UNITTEST_ASSERT(reply->rhdr->error ==
- (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
-
- // Free request and reallocate to use when query is restarted
- free_req(req);
- client_request_message = calloc(1, sizeof(request_state));
-
-UNITTEST_FOOTER
-
-// This unit test populates the cache with four /etc/hosts records and then
-// verifies there are four entries in the cache.
-UNITTEST_HEADER(PopulateCacheWithClientLOResponseRecords)
-
- mDNS *const m = &mDNSStorage;
-
- // Verify cache is empty
- int count = LogEtcHosts_ut(m);
- UNITTEST_ASSERT(count == 0);
-
- // Populate /etc/hosts
- mStatus result = InitEtcHostsRecords();
- UNITTEST_ASSERT(result == mStatus_NoError);
-
- // mDNS_Execute is called to populate the /etc/hosts cache.
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m);
-
- count = LogEtcHosts_ut(m);
- UNITTEST_ASSERT(count == 4);
-
-UNITTEST_FOOTER
-
-// This unit test starts a local only request for "cardinal2.apple.com.". It first
-// calls start_client_request to start a query, it then verifies the
-// req and query data structures are set as expected. Next, the cache is verified to
-// contain the answer by AnswerNewLocalOnlyQuestion() and so results in setting up an
-// answer reply to the client. On return from mDNS_Execute, the client's reply structure
-// is verified to be set as expected. Lastly the timeout is simulated and mDNS_Execute is
-// called. This results in a call to TimeoutQuestions(). And this time, the
-// GenerateNegativeResponse() is called which returns a negative response to the client
-// which specifies the timeout occurred. Again, the answer reply is verified to
-// to specify a timeout.
-UNITTEST_HEADER(RestartLocalOnlyClientQueryRequest)
-
- mDNS *const m = &mDNSStorage;
- request_state* req = client_request_message;
- char *msgptr = (char *)query_req_msgbuf;
- size_t msgsz = sizeof(query_req_msgbuf); DNSQuestion *q;
- mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
- mStatus err = mStatus_NoError;
- char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
- struct reply_state *reply;
- size_t len;
-
- // Process the unit test's client request
- start_client_request(req, msgptr, msgsz, query_request, local_socket);
- UNITTEST_ASSERT(err == mStatus_NoError);
-
- UNITTEST_ASSERT(err == mStatus_NoError);
- UNITTEST_ASSERT(req->hdr.version == VERSION);
- UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
- UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
- UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
- UNITTEST_ASSERT(req->terminate != mDNSNULL);
- UNITTEST_ASSERT(m->Questions == NULL);
-
- q = &req->u.queryrecord.q;
- UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
- UNITTEST_ASSERT(q->SuppressUnusable == 1);
- UNITTEST_ASSERT(q->ReturnIntermed == 1);
- UNITTEST_ASSERT(q->SuppressQuery == 0); // Regress <rdar://problem/27571734>
- UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
- UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
- UNITTEST_ASSERT(q->flags == req->flags);
- UNITTEST_ASSERT(q->qtype == 1);
- UNITTEST_ASSERT(q->qclass == 1);
- UNITTEST_ASSERT(q->LongLived == 0);
- UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
- UNITTEST_ASSERT(q->ForceMCast == 0);
- UNITTEST_ASSERT(q->TimeoutQuestion == 1);
- UNITTEST_ASSERT(q->WakeOnResolve == 0);
- UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
- UNITTEST_ASSERT(q->ValidationRequired == 0);
- UNITTEST_ASSERT(q->ValidatingResponse == 0);
- UNITTEST_ASSERT(q->ProxyQuestion == 0);
- UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
- UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
- UNITTEST_ASSERT(q->QuestionContext == req);
- UNITTEST_ASSERT(q->SearchListIndex == 0);
- UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
- UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
- UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
- UNITTEST_ASSERT(q->StopTime != 0);
- UNITTEST_ASSERT(q->AppendSearchDomains == 0);
- UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
- UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
- ConvertDomainNameToCString(&q->qname, qname_cstr);
- UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
-
- // Answer local-only question with found cache entry
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m); // Regress <rdar://problem/28721294>
- UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
- UNITTEST_ASSERT(req->u.queryrecord.ans == 1);
- UNITTEST_ASSERT(q->LOAddressAnswers == 1);
- UNITTEST_ASSERT(q == m->LocalOnlyQuestions);
-
- reply = req->replies;
- len = get_reply_len(qname_cstr, 4);
-
- UNITTEST_ASSERT(reply->next == mDNSNULL);
- UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
- UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
- UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
- // Simulate the query time out of the local-only question.
- // The expected behavior is a negative answer with time out error
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- q->StopTime = mDNS_TimeNow_NoLock(m);
- m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
- mDNS_Execute(m);
-
- reply = req->replies->next;
- UNITTEST_ASSERT(reply != NULL);
- UNITTEST_ASSERT(reply->next == NULL);
- UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
- UNITTEST_ASSERT(q->LOAddressAnswers == 0);
- len = get_reply_len(qname_cstr, 0);
-
- UNITTEST_ASSERT(reply->next == mDNSNULL);
- UNITTEST_ASSERT(reply->totallen == len + + sizeof(ipc_msg_hdr));
- UNITTEST_ASSERT(reply->mhdr->version == VERSION);
- UNITTEST_ASSERT(reply->mhdr->datalen == len);
- UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
- UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
- UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
- UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly); // Regress <rdar://problem/27340874>
- UNITTEST_ASSERT(reply->rhdr->error ==
- (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout)); // Regress <rdar://problem/27562965>
-
- free_req(req);
-UNITTEST_FOOTER
-
-// This function does memory cleanup and no verification.
-UNITTEST_HEADER(FinalizeUnitTest)
- mDNSPlatformMemFree(local_socket);
-UNITTEST_FOOTER
-
-mDNSlocal mStatus InitEtcHostsRecords(void)
-{
- mDNS *m = &mDNSStorage;
- struct sockaddr_storage hostaddr;
-
- AuthHash newhosts;
- mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
-
- memset(&hostaddr, 0, sizeof(hostaddr));
- get_ip("127.0.0.1", &hostaddr);
-
- domainname domain;
- MakeDomainNameFromDNSNameString(&domain, "localhost");
-
- mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-
- memset(&hostaddr, 0, sizeof(hostaddr));
- get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr);
-
- MakeDomainNameFromDNSNameString(&domain, "localhost");
-
- mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-
- memset(&hostaddr, 0, sizeof(hostaddr));
- get_ip("255.255.255.255", &hostaddr);
-
- MakeDomainNameFromDNSNameString(&domain, "broadcasthost");
-
- mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-
- memset(&hostaddr, 0, sizeof(hostaddr));
- get_ip("17.226.40.200", &hostaddr);
-
- MakeDomainNameFromDNSNameString(&domain, "cardinal2.apple.com");
-
- mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
- UpdateEtcHosts_ut(&newhosts);
-
- m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
- mDNS_Execute(m);
-
- return mStatus_NoError;
-}
+++ /dev/null
-
-#ifndef LocalOnlyTimeoutTests_h
-#define LocalOnlyTimeoutTests_h
-
-#include "unittest.h"
-
-int LocalOnlyTimeoutTests(void);
-
-#endif /* LocalOnlyTimeoutTests_h */
+++ /dev/null
-#include "mDNSEmbeddedAPI.h"
-#include "../mDNSCore/DNSCommon.h"
-#include "ResourceRecordTest.h"
-
-int TXTSetupTest(void);
-int ASetupTest(void);
-int OPTSetupTest(void);
-
-
-UNITTEST_HEADER(ResourceRecordTest)
- UNITTEST_TEST(TXTSetupTest)
- UNITTEST_TEST(ASetupTest)
- UNITTEST_TEST(OPTSetupTest)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(TXTSetupTest)
-
- AuthRecord authRec;
- mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeShared, AuthRecordAny,mDNSNULL, mDNSNULL);
- // This fails >> UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_TXT);
- UNITTEST_ASSERT_RETURN(authRec.resrec.rdata->MaxRDLength == sizeof(RDataBody));
-
- // Retest with a RDataStorage set to a a buffer
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(ASetupTest)
- AuthRecord authRec;
- mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
-
- // This fails >> UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_A);
- // Add more verifications
-
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(OPTSetupTest)
- AuthRecord opt;
- mDNSu32 updatelease = 7200;
-/* mDNSu8 data[AbsoluteMaxDNSMessageData];
- mDNSu8 *p = data;
- mDNSu16 numAdditionals;
-*/
- // Setup the OPT Record
- mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
-
- // Verify the basic initialization is all ok
-
- 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;
-
- // Put the resource record in and verify everything is fine
- // p = PutResourceRecordTTLWithLimit(&data, p, &numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, data + AbsoluteMaxDNSMessageData);
-
-
- // Repeat with bad data to make sure it bails out cleanly
-UNITTEST_FOOTER
\ No newline at end of file
+++ /dev/null
-
-
-#ifndef ResourceRecordTest_h
-#define ResourceRecordTest_h
-
-#include "unittest.h"
-
-int ResourceRecordTest(void);
-
-#endif /* ResourceRecordTest_h */
#include "DNSCommon.h"
+#include "unittest_common.h"
mDNSexport void init_logging_ut(void)
{
+++ /dev/null
-#include "mDNSCoreReceiveTest.h"
-#include "unittest_common.h"
-
-int InitmDNSCoreReceiveTest(void);
-int ValidQueryReqTest(void);
-int NullDstQueryReqTest(void);
-void InitmDNSStorage(mDNS *const m);
-
-// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
-uint8_t udns_query_request_message[28] = { // contains 1 question for www.f5.com
- 0x31, 0xca, // transaction id
- 0x01, 0x00, // flags
- 0x00, 0x01, // 1 question
- 0x00, 0x00, // no anwsers
- 0x00, 0x00, // no authoritative answers
- 0x00, 0x00, // no additionals
- 0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
-};
-
-// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
-// Then the header id (more specifically, the msg->h.id) was deliberately cleared to force code
-// path to traverse regression case, <rdar://problem/28556513>.
-uint8_t udns_query_request_message_with_invalid_id[28] = { // contains 1 question for www.f5.com, msg->h.id = 0
- 0x00, 0x00, // transaction id
- 0x01, 0x00, // flags
- 0x00, 0x01, // 1 question
- 0x00, 0x00, // no anwsers
- 0x00, 0x00, // no authoritative answers
- 0x00, 0x00, // no additionals
- 0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
-};
-
-uint8_t arp_request_packet[28] = { // contains 1 question for www.f5.com, msg->h.id = 0
- 0x00, 0x01, // hardware type: enet
- 0x08, 0x00, // protocol type: IP
- 0x06, // hardware size
- 0x04, // Protcol size
- 0x00, 0x01, // opcode request
- 0x24, 0x01, 0xc7, 0x24, 0x35, 0x00, // Sender mac addr
- 0x11, 0xe2, 0x14, 0x01, // Sender ip addr
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // target mac addr
- 0x11, 0xe2, 0x17, 0xbe // target ip addr
-};
-UNITTEST_HEADER(mDNSCoreReceiveTest)
- UNITTEST_TEST(InitmDNSCoreReceiveTest)
- UNITTEST_TEST(ValidQueryReqTest)
- UNITTEST_TEST(NullDstQueryReqTest)
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(InitmDNSCoreReceiveTest)
- mDNSPlatformTimeInit();
- init_logging_ut();
- mDNS_LoggingEnabled = 0;
- mDNS_PacketLoggingEnabled = 0;
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(ValidQueryReqTest)
- mDNS *const m = &mDNSStorage;
- mDNSAddr srcaddr, dstaddr;
- mDNSIPPort srcport, dstport;
- DNSMessage * msg;
- const mDNSu8 * end;
-
- // Init unit test environment and verify no error occurred.
- mStatus result = init_mdns_environment(mDNStrue);
- UNITTEST_ASSERT(result == mStatus_NoError);
-
- // Used random values for srcaddr and srcport
- srcaddr.type = mDNSAddrType_IPv4;
- srcaddr.ip.v4.b[0] = 192;
- srcaddr.ip.v4.b[1] = 168;
- srcaddr.ip.v4.b[2] = 1;
- srcaddr.ip.v4.b[3] = 10;
- srcport.NotAnInteger = swap16((mDNSu16)53);
-
- // Used random values for dstaddr and dstport
- dstaddr.type = mDNSAddrType_IPv4;
- dstaddr.ip.v4.b[0] = 192;
- dstaddr.ip.v4.b[1] = 168;
- dstaddr.ip.v4.b[2] = 1;
- dstaddr.ip.v4.b[3] = 20;
- dstport.NotAnInteger = swap16((mDNSu16)49339);
-
- // Set message to a DNS message (copied from a WireShark packet)
- msg = (DNSMessage *)udns_query_request_message;
- end = udns_query_request_message + sizeof(udns_query_request_message);
-
- // Execute mDNSCoreReceive using a valid DNS message
- mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &dstaddr, dstport, if_nametoindex("en0"));
-
- // Verify that mDNSCoreReceiveQuery traversed the normal code path
- UNITTEST_ASSERT(m->mDNSStats.NormalQueries == 1);
-
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(NullDstQueryReqTest)
-
- mDNS *const m = &mDNSStorage;
- mDNSAddr srcaddr;
- mDNSIPPort srcport, dstport;
- DNSMessage * msg;
- const mDNSu8 * end;
-
- // This test case does not require setup of interfaces, the record's cache, or pending questions
- // so m is initialized to all zeros.
- InitmDNSStorage(m);
-
- // Used random values for srcaddr and srcport
- srcaddr.type = mDNSAddrType_IPv4;
- srcaddr.ip.v4.b[0] = 192;
- srcaddr.ip.v4.b[1] = 168;
- srcaddr.ip.v4.b[2] = 1;
- srcaddr.ip.v4.b[3] = 10;
- srcport.NotAnInteger = swap16((mDNSu16)53);
-
- // Used random value for dstport
- dstport.NotAnInteger = swap16((mDNSu16)49339);
-
- // Set message to a DNS message (copied from a WireShark packet)
- msg = (DNSMessage *)udns_query_request_message_with_invalid_id;
- end = udns_query_request_message_with_invalid_id + sizeof(udns_query_request_message_with_invalid_id);
-
- // Execute mDNSCoreReceive to regress <rdar://problem/28556513>
- mDNSCoreReceive(m, msg, end, &srcaddr, srcport, NULL, dstport, if_nametoindex("en0"));
-
- // Verify that mDNSCoreReceiveQuery was NOT traversed through the normal code path
- UNITTEST_ASSERT(m->mDNSStats.NormalQueries == 0);
-
- // Verify code path that previously crashed, in <rdar://problem/28556513>, now traverses successfully
- // by checking a counter that was incremented on code path that crashed.
- UNITTEST_ASSERT(m->MPktNum == 1);
-
-UNITTEST_FOOTER
-
-void InitmDNSStorage(mDNS *const m)
-{
- memset(m, 0, sizeof(mDNS));
-}
-
+++ /dev/null
-
-#ifndef mDNSCoreReceiveTest_h
-#define mDNSCoreReceiveTest_h
-
-#include "unittest.h"
-
-int mDNSCoreReceiveTest(void);
-
-#endif /* mDNSCoreReceiveTest_h */
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "unittest.h"
-#include "DNSMessageTest.h"
-#include "ResourceRecordTest.h"
-#include "mDNSCoreReceiveTest.h"
-#include "CNameRecordTests.h"
-#include "LocalOnlyTimeoutTests.h"
-
-const char *HWVersionString = "unittestMac1,1";
-const char *OSVersionString = "unittest 1.1.1 (1A111)";
-const char *BinaryNameString = "unittest";
-const char *VersionString = "unittest mDNSResponer-00 (Jan 1 1970 00:00:00)";
-
-
-
-UNITTEST_HEADER(run_tests)
-UNITTEST_GROUP(DNSMessageTest)
-UNITTEST_GROUP(ResourceRecordTest)
-UNITTEST_GROUP(mDNSCoreReceiveTest)
-//UNITTEST_GROUP(CNameRecordTests) // Commenting out until issue reported in <rdar://problem/30589360> is debugged.
-UNITTEST_GROUP(LocalOnlyTimeoutTests)
-UNITTEST_FOOTER
-
-// UNITTEST_MAIN is run in daemon.c
-
#include "DNSCommon.h" // Defines general DNS utility routines
+#include "unittest_common.h"
// To match *either* a v4 or v6 instance of this interface
mDNSlocal mDNSInterfaceID SearchForInterfaceByAddr(mDNSAddr* addr)
UpdateEtcHosts(&mDNSStorage, context);
mDNS_Unlock(&mDNSStorage);
}
+
+mDNSexport void mDNSDomainLabelFromCFString_ut(CFStringRef cfs, domainlabel *const namelabel)
+{
+ mDNSDomainLabelFromCFString(cfs, namelabel);
+}
#include "DNSCommon.h" // Defines general DNS utility routines
+#include "unittest_common.h"
mDNSexport mStatus mDNS_InitStorage_ut(mDNS *const m, mDNS_PlatformSupport *const p,
CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
#include "DNSCommon.h" // Defines general DNS utility routines
+#include "unittest_common.h"
mDNSexport mStatus handle_client_request_ut(void *req)
{
InterfaceID = cr->resrec.rDNSServer->interface;
ifname = InterfaceNameForID(&mDNSStorage, InterfaceID);
if (cr->CRActiveQuestion) CacheActive++;
- PrintOneCacheRecord(cr, slot, remain, ifname, &CacheUsed);
- PrintCachedRecords(cr, slot, remain, ifname, &CacheUsed);
+ PrintOneCacheRecordToFD(STDOUT_FILENO, cr, slot, remain, ifname, &CacheUsed);
+ PrintCachedRecordsToFD(STDOUT_FILENO, cr, slot, remain, ifname, &CacheUsed);
}
}
}
mDNSexport int LogEtcHosts_ut(mDNS *const m)
{
- return LogEtcHosts(m);
+ return LogEtcHostsToFD(STDOUT_FILENO, m);
}
+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 Apple Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <stdlib.h>
-#include "unittest.h"
-
-int _unittest_assert_i(const int condition, const int i, const char * const conditionStr,
- const char * const filename, const unsigned int linenum,
- const char * const functionname, __test_item ** __i, int * const __success)
-{
- if (!condition)
- {
- __test_item* tba = malloc(sizeof(__test_item));
- tba->next = *__i;
- tba->file = filename;
- tba->line = linenum;
- tba->func = functionname;
- tba->s = conditionStr;
- tba->iter_count = i;
- *__i = tba;
- *__success = 0;
- printf("F");
- }
- else
- {
- printf(".");
- }
-
- fflush(NULL);
- return condition;
-}
-
-void _unittest_print_list(__test_item* __i)
-{
- __test_item* __tmp = NULL;
- while (__i)
- {
- __test_item* __o = __i->next;
- __i->next = __tmp;
- __tmp = __i;
- __i = __o;
- }
- __i = __tmp;
-
- while(__i)
- {
- printf("%s: In function `%s':\n%s:%d: error: failed UNITTEST_ASSERT", __i->file, __i->func, __i->file, __i->line);
- if (__i->iter_count != -1) printf(" at iteration %d", __i->iter_count);
- printf(": %s\n", __i->s);
- __test_item* tbd = __i;
- __i = __i->next;
- free(tbd);
- }
-}
-
-// test by building like:
-// gcc -g -Wall -Werror -DTEST_UNITTEST_SCAFFOLD unittest.c
-// #define TEST_UNITTEST_SCAFFOLD 1
-#if TEST_UNITTEST_SCAFFOLD
-
-// modify this test as necessary to test the scaffold
-UNITTEST_HEADER(test1)
- int i = 0;
- int j = 1;
- int k = 2;
-
- UNITTEST_ASSERT(i==j);
- UNITTEST_ASSERTI(j==i, k);
- UNITTEST_ASSERT(i==i);
- UNITTEST_ASSERTI(j==j, k);
- UNITTEST_ASSERT_RETURN(j==j);
- UNITTEST_ASSERTI_RETURN(j==j, k);
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(test2)
- UNITTEST_ASSERT(1);
- UNITTEST_ASSERT(0);
- UNITTEST_ASSERT(1);
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(unittest_tests)
-UNITTEST_TEST(test1)
-UNITTEST_TEST(test2)
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(run_tests)
-UNITTEST_GROUP(unittest_tests)
-UNITTEST_FOOTER
-
-UNITTEST_MAIN
-
-#endif // TEST_UNITTEST_SCAFFOLD
#include "unittest_common.h"
#include <MacTypes.h>
+
#ifndef _UNITTEST_H_
#define _UNITTEST_H_
extern "C" {
#endif
-typedef struct __test_item_
-{
- struct __test_item_* next;
- const char* file;
- unsigned int line;
- const char* func;
- const char* s;
- int iter_count;
-} __test_item;
-
-int run_tests(void);
-
-#define UNITTEST_HEADER(X) int X() { int __success = 1; __test_item* __i = NULL;
-
-#define UNITTEST_GROUP(X) { printf("== %s ==\n", #X); __success = X() && __success; }
-#define UNITTEST_TEST(X) { printf("%s: ", #X); fflush(NULL); __success = X() && __success; }
-
-int _unittest_assert_i(const int condition, const int i, const char * const conditionStr,
- const char * const filename, const unsigned int linenum,
- const char * const functionname, __test_item ** __i, int * const __success);
-#define UNITTEST_ASSERTI(X,I) (_unittest_assert_i((X)!=0, (I), #X, __FILE__, __LINE__, __func__, &__i, &__success))
-#define UNITTEST_ASSERT(X) UNITTEST_ASSERTI(X, -1)
-#define UNITTEST_ASSERTI_RETURN(X,I) { if (!UNITTEST_ASSERTI(X,I)) goto __unittest_footer__; }
-#define UNITTEST_ASSERT_RETURN(X) UNITTEST_ASSERTI_RETURN(X, -1)
-
-void _unittest_print_list(__test_item* __i);
-#define UNITTEST_FOOTER goto __unittest_footer__; __unittest_footer__: printf("\n"); fflush(NULL); _unittest_print_list(__i); return __success; }
-
-#define UNITTEST_MAIN int main (int argc, char** argv) \
- { \
- (void)(argv); \
- signal(SIGPIPE, SIG_IGN); \
- FILE* fp; \
- unlink("unittest_success"); \
- if (!run_tests()) \
- { \
- printf("unit test FAILED\n"); \
- return -1; \
- } \
- fp = fopen("unittest_success", "w"); \
- if (!fp) return -2; \
- fprintf(fp, "unit test %s\n", "SUCCEEDED"); \
- fclose(fp); \
- printf("unit test SUCCESS\n"); \
- if (argc != 1) \
- { \
- char c; \
- printf("run leaks now\n"); \
- read(STDIN_FILENO, &c, 1); \
- } \
- return 0; \
- }
-#define UNITTEST_SENDDNSMESSAGE mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end, \
- mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, \
- mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo, \
- mDNSBool useBackgroundTrafficClass) \
- { \
- (void)(m); \
- (void)(msg); \
- (void)(end); \
- (void)(InterfaceID); \
- (void)(src); \
- (void)(dst); \
- (void)(dstport); \
- (void)(sock); \
- (void)(authInfo); \
- (void)(useBackgroundTrafficClass); \
- return 0; \
- }
-
#define UNITTEST_SETSOCKOPT void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, \
mDNSAddr_Type addrType, const DNSQuestion *q) \
{ \
(void)(sock); \
}
-#define UNITTEST_FAIL_ASSERT { assert(((void*)__func__) == 0); }
-
#ifdef __cplusplus
}
#endif
init_client_request(req, msgbuf, msgsz, op);
mStatus result = handle_client_request_ut((void*)req);
- DNSQuestion* q = &req->u.queryrecord.q;
+ DNSQuestion* q = &req->u.queryrecord.op.q;
q->LocalSocket = socket;
return result;
}
mDNSAddr srcaddr;
mDNSIPPort srcport, dstport;
const mDNSu8 * end;
- DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.q;
+ DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.op.q;
UInt8* data = (UInt8*)msg;
// Used same values for DNS server as specified during init of unit test
if (aiList) freeaddrinfo(aiList);
}
+// The AddDNSServer_ut function adds a dns server to mDNSResponder's list.
+mDNSexport mStatus AddDNSServer_ut(void)
+{
+ mDNS *m = &mDNSStorage;
+ m->timenow = 0;
+ mDNS_Lock(m);
+ domainname d;
+ mDNSAddr addr;
+ mDNSIPPort port;
+ mDNSs32 serviceID = 0;
+ mDNSu32 scoped = 0;
+ mDNSu32 timeout = dns_server_timeout;
+ mDNSBool cellIntf = 0;
+ mDNSBool isExpensive = 0;
+ mDNSBool isConstrained = 0;
+ mDNSBool isCLAT46 = mDNSfalse;
+ mDNSu32 resGroupID = dns_server_resGroupID;
+ mDNSBool reqA = mDNStrue;
+ mDNSBool reqAAAA = mDNStrue;
+ mDNSBool reqDO = mDNSfalse;
+ d.c[0] = 0;
+ addr.type = mDNSAddrType_IPv4;
+ addr.ip.v4.NotAnInteger = dns_server_ipv4.NotAnInteger;
+ port.NotAnInteger = client_resp_src_port;
+ mDNS_AddDNSServer(m, &d, primary_interfaceID, serviceID, &addr, port, scoped, timeout,
+ cellIntf, isExpensive, isConstrained, isCLAT46, resGroupID,
+ reqA, reqAAAA, reqDO);
+ mDNS_Unlock(m);
+ return mStatus_NoError;
+}
#include <netdb.h> // for getaddrinfo
#include <net/if.h>
#include <pthread.h>
+#include <CoreFoundation/CoreFoundation.h>
// Primary interface info that is used when simulating the receive of the response packet
extern mDNSInterfaceID primary_interfaceID;
extern mDNSBool mDNSMacOSXCreateEtcHostsEntry_ut(const domainname *domain, const struct sockaddr *sa,
const domainname *cname, char *ifname, AuthHash *auth);
extern void UpdateEtcHosts_ut(void *context);
+extern mStatus AddDNSServer_ut(void);
+
+// HelperFunctionTest
+extern void mDNSDomainLabelFromCFString_ut(CFStringRef cfs, domainlabel *const namelabel);
#endif /* UNITTEST_COMMON_H */