From c71e3068dca7ed8b0536b4ce3fe0552e9f39d389 Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 1 May 2020 18:23:30 +0000 Subject: [PATCH] mDNSResponder-1096.100.3.tar.gz --- Clients/dnssdutil/dnssdutil.c | 1069 ++++++++++++++++- Makefile | 2 +- mDNSMacOSX/DNSSECSupport.c | 6 +- mDNSMacOSX/Tests/mDNSResponder.plist | 41 + .../mDNSResponder.xcodeproj/project.pbxproj | 54 + mDNSPosix/Makefile | 322 ----- mDNSShared/dns_sd.h | 2 +- mDNSShared/dns_sd_private.h | 12 + mDNSShared/dnssd_clientstub.c | 84 +- 9 files changed, 1223 insertions(+), 369 deletions(-) diff --git a/Clients/dnssdutil/dnssdutil.c b/Clients/dnssdutil/dnssdutil.c index 9852be0..d56ed00 100644 --- a/Clients/dnssdutil/dnssdutil.c +++ b/Clients/dnssdutil/dnssdutil.c @@ -183,6 +183,24 @@ static const uint8_t kDNSServerBadBaseAddrV6[] = check_compile_time( sizeof( kDNSServerBadBaseAddrV6 ) == 16 ); +//=========================================================================================================================== +// Soft Linking +//=========================================================================================================================== + +#if( TARGET_OS_DARWIN ) +SOFT_LINK_LIBRARY_EX( "/usr/lib/system", system_dnssd ); +SOFT_LINK_FUNCTION_EX( system_dnssd, DNSServiceSleepKeepalive_sockaddr, + DNSServiceErrorType, ( + DNSServiceRef * sdRef, + DNSServiceFlags flags, + const struct sockaddr * localAddr, + const struct sockaddr * remoteAddr, + unsigned int timeout, + DNSServiceSleepKeepaliveReply callBack, + void * context ), + ( sdRef, flags, localAddr, remoteAddr, timeout, callBack, context ) ); +#endif + //=========================================================================================================================== // Misc. //=========================================================================================================================== @@ -769,6 +787,27 @@ static CLIOption kPortMappingOpts[] = CLI_OPTION_END() }; +#if( TARGET_OS_DARWIN ) +//=========================================================================================================================== +// RegisterKA Command Options +//=========================================================================================================================== + +static const char * gRegisterKA_LocalAddress = NULL; +static const char * gRegisterKA_RemoteAddress = NULL; +static int gRegisterKA_Timeout = 0; + +static CLIOption kRegisterKA_Opts[] = +{ + DNSSDFlagsOption(), + StringOption( 'l', "local", &gRegisterKA_LocalAddress, "IP addr+port", "TCP connection's local IPv4 or IPv6 address and port pair.", true ), + StringOption( 'r', "remote", &gRegisterKA_RemoteAddress, "IP addr+port", "TCP connection's remote IPv4 or IPv6 address and port pair.", true ), + IntegerOption( 't', "timeout", &gRegisterKA_Timeout, "timeout", "Keepalive record's timeout value, i.e., its 't=' value.", false ), + CLI_OPTION_END() +}; + +static void RegisterKACmd( void ); +#endif + //=========================================================================================================================== // BrowseAll Command Options //=========================================================================================================================== @@ -1790,6 +1829,23 @@ static CLIOption kXCTestOpts[] = }; #endif +#if( TARGET_OS_DARWIN ) +static void KeepAliveTestCmd( void ); + +static const char * gKeepAliveTest_OutputFormat = kOutputFormatStr_JSON; +static const char * gKeepAliveTest_OutputFilePath = NULL; + +static CLIOption kKeepAliveTestOpts[] = +{ + CLI_OPTION_GROUP( "Results" ), + FormatOption( 'f', "format", &gKeepAliveTest_OutputFormat, "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ), + StringOption( 'o', "output", &gKeepAliveTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ), + + TestExitStatusSection(), + CLI_OPTION_END() +}; +#endif + static CLIOption kTestOpts[] = { Command( "gaiperf", GAIPerfCmd, kGAIPerfOpts, "Runs DNSServiceGetAddrInfo() performance tests.", false ), @@ -1801,7 +1857,10 @@ static CLIOption kTestOpts[] = #if( MDNSRESPONDER_PROJECT ) Command( "xctest", XCTestCmd, kXCTestOpts, "Run a XCTest from /AppleInternal/XCTests/com.apple.mDNSResponder/Tests.xctest.", true ), #endif - CLI_OPTION_END() +#if( TARGET_OS_DARWIN ) + Command( "keepalive", KeepAliveTestCmd, kKeepAliveTestOpts, "Tests keepalive record registrations.", false ), +#endif + CLI_OPTION_END() }; //=========================================================================================================================== @@ -2065,6 +2124,9 @@ static CLIOption kGlobalOpts[] = 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 ), +#if( TARGET_OS_DARWIN ) + Command( "registerKA", RegisterKACmd, kRegisterKA_Opts, "Uses DNSServiceSleepKeepalive_sockaddr() to register a keep alive record.", false ), +#endif Command( "browseAll", BrowseAllCmd, kBrowseAllOpts, "Browse and resolve all (or specific) services and, optionally, attempt connections.", false ), // Uncommon commands. @@ -2182,6 +2244,7 @@ typedef void ( *DispatchHandler )( void *inContext ); static OSStatus DispatchSignalSourceCreate( int inSignal, + dispatch_queue_t inQueue, DispatchHandler inEventHandler, void * inContext, dispatch_source_t * outSource ); @@ -2669,7 +2732,7 @@ static void BrowseCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -3075,7 +3138,7 @@ static void GetAddrInfoCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -3326,7 +3389,7 @@ static void QueryRecordCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -3584,7 +3647,7 @@ static void RegisterCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -3893,7 +3956,7 @@ static void RegisterRecordCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -4122,7 +4185,7 @@ static void ResolveCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -4487,7 +4550,7 @@ static void ReverseLookupCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -4650,7 +4713,7 @@ static void PortMappingCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -4802,6 +4865,180 @@ static void DNSSD_API inProtocol, kDNSServiceProtocolDescriptors, inError, errorStr ); } +#if( TARGET_OS_DARWIN ) +//=========================================================================================================================== +// RegisterKACmd +//=========================================================================================================================== + +typedef struct +{ + dispatch_queue_t queue; // Serial queue for command's events. + dispatch_semaphore_t doneSem; // Semaphore to signal when underlying command operation is done. + sockaddr_ip local; // Connection's local IP address and port. + sockaddr_ip remote; // Connection's remote IP address and port. + DNSServiceFlags flags; // Flags to pass to DNSServiceSleepKeepalive_sockaddr(). + unsigned int timeout; // Timeout to pass to DNSServiceSleepKeepalive_sockaddr(). + DNSServiceRef keepalive; // DNSServiceSleepKeepalive_sockaddr operation. + dispatch_source_t sourceSigInt; // Dispatch source for SIGINT. + dispatch_source_t sourceSigTerm; // Dispatch source for SIGTERM. + OSStatus error; // Command's error. + +} RegisterKACmdContext; + +static void _RegisterKACmdFree( RegisterKACmdContext *inCmd ); +static void _RegisterKACmdStart( void *inContext ); +static OSStatus _RegisterKACmdGetIPAddressArgument( const char *inArgStr, const char *inArgName, sockaddr_ip *outSA ); + +static void RegisterKACmd( void ) +{ + OSStatus err; + RegisterKACmdContext * cmd = NULL; + + if( !SOFT_LINK_HAS_FUNCTION( system_dnssd, DNSServiceSleepKeepalive_sockaddr ) ) + { + FPrintF( stderr, "error: Failed to soft link DNSServiceSleepKeepalive_sockaddr from libsystem_dnssd.\n" ); + err = kNotFoundErr; + goto exit; + } + cmd = (RegisterKACmdContext *) calloc( 1, sizeof( *cmd ) ); + require_action( cmd, exit, err = kNoMemoryErr ); + + err = _RegisterKACmdGetIPAddressArgument( gRegisterKA_LocalAddress, "local IP address", &cmd->local ); + require_noerr_quiet( err, exit ); + + err = _RegisterKACmdGetIPAddressArgument( gRegisterKA_RemoteAddress, "remote IP address", &cmd->remote ); + require_noerr_quiet( err, exit ); + + err = CheckIntegerArgument( gRegisterKA_Timeout, "timeout", 0, INT_MAX ); + require_noerr_quiet( err, exit ); + + cmd->flags = GetDNSSDFlagsFromOpts(); + cmd->timeout = (unsigned int) gRegisterKA_Timeout; + + // Start command. + + cmd->queue = dispatch_queue_create( "com.apple.dnssdutil.registerka-command", DISPATCH_QUEUE_SERIAL ); + require_action( cmd->queue, exit, err = kNoResourcesErr ); + + cmd->doneSem = dispatch_semaphore_create( 0 ); + require_action( cmd->doneSem, exit, err = kNoResourcesErr ); + + dispatch_async_f( cmd->queue, cmd, _RegisterKACmdStart ); + dispatch_semaphore_wait( cmd->doneSem, DISPATCH_TIME_FOREVER ); + if( cmd->error ) err = cmd->error; + + FPrintF( stdout, "---\n" ); + FPrintF( stdout, "End time: %{du:time}\n", NULL ); + +exit: + if( cmd ) _RegisterKACmdFree( cmd ); + gExitCode = err ? 1 : 0; +} + +//=========================================================================================================================== + +static void _RegisterKACmdFree( RegisterKACmdContext *inCmd ) +{ + check( !inCmd->keepalive ); + check( !inCmd->sourceSigInt ); + check( !inCmd->sourceSigTerm ); + dispatch_forget( &inCmd->queue ); + dispatch_forget( &inCmd->doneSem ); + free( inCmd ); +} + +//=========================================================================================================================== + +static void _RegisterKACmdStop( RegisterKACmdContext *inCmd, OSStatus inError ); +static void _RegisterKACmdSignalHandler( void *inContext ); +static void DNSSD_API _RegisterKACmdKeepaliveCallback( DNSServiceRef inSDRef, DNSServiceErrorType inError, void *inCtx ); + +static void _RegisterKACmdStart( void *inContext ) +{ + OSStatus err; + RegisterKACmdContext * const cmd = (RegisterKACmdContext *) inContext; + + signal( SIGINT, SIG_IGN ); + err = DispatchSignalSourceCreate( SIGINT, cmd->queue, _RegisterKACmdSignalHandler, cmd, &cmd->sourceSigInt ); + require_noerr( err, exit ); + dispatch_resume( cmd->sourceSigInt ); + + signal( SIGTERM, SIG_IGN ); + err = DispatchSignalSourceCreate( SIGTERM, cmd->queue, _RegisterKACmdSignalHandler, cmd, &cmd->sourceSigTerm ); + require_noerr( err, exit ); + dispatch_resume( cmd->sourceSigTerm ); + + FPrintF( stdout, "Flags: %#{flags}\n", cmd->flags, kDNSServiceFlagsDescriptors ); + FPrintF( stdout, "Local: %##a\n", &cmd->local.sa ); + FPrintF( stdout, "Remote: %##a\n", &cmd->remote.sa ); + FPrintF( stdout, "Timeout: %u\n", cmd->timeout ); + FPrintF( stdout, "Start time: %{du:time}\n", NULL ); + FPrintF( stdout, "---\n" ); + + err = soft_DNSServiceSleepKeepalive_sockaddr( &cmd->keepalive, cmd->flags, &cmd->local.sa, &cmd->remote.sa, + cmd->timeout, _RegisterKACmdKeepaliveCallback, cmd ); + require_noerr( err, exit ); + + err = DNSServiceSetDispatchQueue( cmd->keepalive, cmd->queue ); + require_noerr( err, exit ); + +exit: + if( err ) _RegisterKACmdStop( cmd, err ); +} + +//=========================================================================================================================== + +static OSStatus _RegisterKACmdGetIPAddressArgument( const char *inArgStr, const char *inArgName, sockaddr_ip *outSA ) +{ + OSStatus err; + sockaddr_ip sip; + + err = StringToSockAddr( inArgStr, &sip, sizeof( sip ), NULL ); + if( !err && ( ( sip.sa.sa_family == AF_INET ) || ( sip.sa.sa_family == AF_INET6 ) ) ) + { + if( outSA ) SockAddrCopy( &sip, outSA ); + } + else + { + FPrintF( stderr, "error: Invalid %s: '%s'\n", inArgName, inArgStr ); + err = kParamErr; + } + return( err ); +} + +//=========================================================================================================================== + +static void _RegisterKACmdStop( RegisterKACmdContext *inCmd, OSStatus inError ) +{ + if( !inCmd->error ) inCmd->error = inError; + DNSServiceForget( &inCmd->keepalive ); + dispatch_source_forget( &inCmd->sourceSigInt ); + dispatch_source_forget( &inCmd->sourceSigTerm ); + dispatch_semaphore_signal( inCmd->doneSem ); +} + +//=========================================================================================================================== + +static void _RegisterKACmdSignalHandler( void *inContext ) +{ + RegisterKACmdContext * const cmd = (RegisterKACmdContext *) inContext; + + _RegisterKACmdStop( cmd, kNoErr ); +} + +//=========================================================================================================================== + +static void DNSSD_API _RegisterKACmdKeepaliveCallback( DNSServiceRef inSDRef, DNSServiceErrorType inError, void *inCtx ) +{ + RegisterKACmdContext * const cmd = (RegisterKACmdContext *) inCtx; + + Unused( inSDRef ); + + FPrintF( stdout, "%{du:time} Record registration result: %#m\n", NULL, inError ); + if( !cmd->error ) cmd->error = inError; +} +#endif // TARGET_OS_DARWIN + //=========================================================================================================================== // BrowseAllCmd //=========================================================================================================================== @@ -6943,12 +7180,14 @@ static void DNSServerCmd( void ) #endif signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, DNSServerCmdSigIntHandler, context, &context->sigIntSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), DNSServerCmdSigIntHandler, context, + &context->sigIntSource ); require_noerr( err, exit ); dispatch_resume( context->sigIntSource ); signal( SIGTERM, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGTERM, DNSServerCmdSigTermHandler, context, &context->sigTermSource ); + err = DispatchSignalSourceCreate( SIGTERM, dispatch_get_main_queue(), DNSServerCmdSigTermHandler, context, + &context->sigTermSource ); require_noerr( err, exit ); dispatch_resume( context->sigTermSource ); @@ -10548,12 +10787,14 @@ static void GAIPerfCmd( void ) GAITesterSetResultsHandler( context->tester, GAIPerfResultsHandler, context ); signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, GAIPerfSignalHandler, context, &context->sigIntSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), GAIPerfSignalHandler, context, + &context->sigIntSource ); require_noerr( err, exit ); dispatch_resume( context->sigIntSource ); signal( SIGTERM, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGTERM, GAIPerfSignalHandler, context, &context->sigTermSource ); + err = DispatchSignalSourceCreate( SIGTERM, dispatch_get_main_queue(), GAIPerfSignalHandler, context, + &context->sigTermSource ); require_noerr( err, exit ); dispatch_resume( context->sigTermSource ); @@ -14546,7 +14787,7 @@ static void ExpensiveConstrainedTestCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -15712,7 +15953,8 @@ static OSStatus _RegistrationTestStart( RegistrationTest *inTest ) signal( SIGINT, SIG_IGN ); check( !inTest->sigSourceINT ); - err = DispatchSignalSourceCreate( SIGINT, _RegistrationTestSignalHandler, inTest, &inTest->sigSourceINT ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), _RegistrationTestSignalHandler, inTest, + &inTest->sigSourceINT ); require_noerr( err, exit ); dispatch_resume( inTest->sigSourceINT ); @@ -15720,7 +15962,8 @@ static OSStatus _RegistrationTestStart( RegistrationTest *inTest ) signal( SIGTERM, SIG_IGN ); check( !inTest->sigSourceTERM ); - err = DispatchSignalSourceCreate( SIGTERM, _RegistrationTestSignalHandler, inTest, &inTest->sigSourceTERM ); + err = DispatchSignalSourceCreate( SIGTERM, dispatch_get_main_queue(), _RegistrationTestSignalHandler, inTest, + &inTest->sigSourceTERM ); require_noerr( err, exit ); dispatch_resume( inTest->sigSourceTERM ); @@ -16838,6 +17081,786 @@ static Boolean _RegistrationTestInterfaceIsWiFi( const char *inIfName ) } #endif +#if( TARGET_OS_DARWIN ) +//=========================================================================================================================== +// KeepAliveTestCmd +//=========================================================================================================================== + +typedef enum +{ + kKeepAliveCallVariant_Null = 0, + kKeepAliveCallVariant_TakesSocket = 1, // DNSServiceSleepKeepalive(), which takes a connected socket. + kKeepAliveCallVariant_TakesSockAddrs = 2, // DNSServiceSleepKeepalive_sockaddr(), which takes connection's sockaddrs. + +} KeepAliveCallVariant; + +typedef struct +{ + int family; // TCP connection's address family. + KeepAliveCallVariant callVariant; // Describes which DNSServiceSleepKeepalive* call to use. + const char * description; + +} KeepAliveSubtestParams; + +const KeepAliveSubtestParams kKeepAliveSubtestParams[] = +{ + { AF_INET, kKeepAliveCallVariant_TakesSocket, "Calls DNSServiceSleepKeepalive() for IPv4 TCP connection." }, + { AF_INET, kKeepAliveCallVariant_TakesSockAddrs, "Calls DNSServiceSleepKeepalive_sockaddr() for IPv4 TCP connection." }, + { AF_INET6, kKeepAliveCallVariant_TakesSocket, "Calls DNSServiceSleepKeepalive() for IPv6 TCP connection." }, + { AF_INET6, kKeepAliveCallVariant_TakesSockAddrs, "Calls DNSServiceSleepKeepalive_sockaddr() for IPv6 TCP connection." } +}; + +typedef struct +{ + sockaddr_ip local; // TCP connection's local address and port. + sockaddr_ip remote; // TCP connection's remote address and port. + NanoTime64 startTime; // Subtest's start time. + NanoTime64 endTime; // Subtest's end time. + SocketRef clientSock; // Socket for client-side of TCP connection. + SocketRef serverSock; // Socket for server-side of TCP connection. + char * recordName; // Keepalive record's name. + char * dataStr; // Data expected to be contained in keepalive record's data. + const char * description; // Subtests's description. + unsigned int timeoutKA; // Randomly-generated timeout value that gets put in keepalive record's rdata. + OSStatus error; // Subtest's error. + +} KeepAliveSubtest; + +typedef struct KeepAliveTest * KeepAliveTestRef; + +typedef struct +{ + KeepAliveTestRef test; // Weak back pointer to test. + +} KeepAliveTestConnectionContext; + +struct KeepAliveTest +{ + dispatch_queue_t queue; // Serial queue for test events. + dispatch_semaphore_t doneSem; // Semaphore to signal when the test is done. + dispatch_source_t readSource; // Read source for TCP listener socket. + DNSServiceRef keepalive; // DNSServiceSleepKeepalive{,2} operation. + DNSServiceRef query; // Query to verify registered keepalive record. + dispatch_source_t timer; // Timer to put time limit on query. + AsyncConnectionRef connection; // Establishes current subtest's TCP connection. + KeepAliveTestConnectionContext * connectionCtx; // Weak pointer to connection's context. + NanoTime64 startTime; // Test's start time. + NanoTime64 endTime; // Test's end time. + OSStatus error; // Test's error. + size_t subtestIdx; // Index of current subtest. + KeepAliveSubtest subtests[ 4 ]; // Subtest array. +}; +check_compile_time( countof_field( struct KeepAliveTest, subtests ) == countof( kKeepAliveSubtestParams ) ); + +ulog_define_ex( kDNSSDUtilIdentifier, KeepAliveTest, kLogLevelInfo, kLogFlags_None, "KeepAliveTest", NULL ); +#define kat_ulog( LEVEL, ... ) ulog( &log_category_from_name( KeepAliveTest ), (LEVEL), __VA_ARGS__ ) + +static OSStatus _KeepAliveTestCreate( KeepAliveTestRef *outTest ); +static OSStatus _KeepAliveTestRun( KeepAliveTestRef inTest ); +static void _KeepAliveTestFree( KeepAliveTestRef inTest ); + +static void KeepAliveTestCmd( void ) +{ + OSStatus err; + OutputFormatType outputFormat; + KeepAliveTestRef test = NULL; + CFPropertyListRef plist = NULL; + CFMutableArrayRef subtests; + size_t i; + size_t subtestFailCount; + Boolean testPassed = false; + char startTime[ 32 ]; + char endTime[ 32 ]; + + err = OutputFormatFromArgString( gKeepAliveTest_OutputFormat, &outputFormat ); + require_noerr_quiet( err, exit ); + + err = _KeepAliveTestCreate( &test ); + require_noerr( err, exit ); + + err = _KeepAliveTestRun( test ); + require_noerr( err, exit ); + + _NanoTime64ToTimestamp( test->startTime, startTime, sizeof( startTime ) ); + _NanoTime64ToTimestamp( test->endTime, endTime, sizeof( endTime ) ); + err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist, + "{" + "%kO=%s" // startTime + "%kO=%s" // endTime + "%kO=[%@]" // subtests + "}", + CFSTR( "startTime" ), startTime, + CFSTR( "endTime" ), endTime, + CFSTR( "subtests" ), &subtests ); + require_noerr( err, exit ); + + subtestFailCount = 0; + check( test->subtestIdx == countof( test->subtests ) ); + for( i = 0; i < countof( test->subtests ); ++i ) + { + KeepAliveSubtest * const subtest = &test->subtests[ i ]; + char errorDesc[ 128 ]; + + _NanoTime64ToTimestamp( subtest->startTime, startTime, sizeof( startTime ) ); + _NanoTime64ToTimestamp( subtest->endTime, endTime, sizeof( endTime ) ); + SNPrintF( errorDesc, sizeof( errorDesc ), "%m", subtest->error ); + err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtests, + "{" + "%kO=%s" // startTime + "%kO=%s" // endTime + "%kO=%s" // description + "%kO=%##a" // localAddr + "%kO=%##a" // remoteAddr + "%kO=%s" // recordName + "%kO=%s" // expectedRData + "%kO=" // error + "{" + "%kO=%lli" // code + "%kO=%s" // description + "}" + "}", + CFSTR( "startTime" ), startTime, + CFSTR( "endTime" ), endTime, + CFSTR( "description" ), subtest->description, + CFSTR( "localAddr" ), &subtest->local.sa, + CFSTR( "remoteAddr" ), &subtest->remote.sa, + CFSTR( "recordName" ), subtest->recordName, + CFSTR( "expectedRData" ), subtest->dataStr, + CFSTR( "error" ), + CFSTR( "code" ), (int64_t) subtest->error, + CFSTR( "description" ), errorDesc + ); + require_noerr( err, exit ); + if( subtest->error ) ++subtestFailCount; + } + if( subtestFailCount == 0 ) testPassed = true; + CFPropertyListAppendFormatted( kCFAllocatorDefault, plist, "%kO=%b", CFSTR( "pass" ), testPassed ); + + err = OutputPropertyList( plist, outputFormat, gKeepAliveTest_OutputFilePath ); + require_noerr( err, exit ); + +exit: + if( test ) _KeepAliveTestFree( test ); + CFReleaseNullSafe( plist ); + gExitCode = err ? 1 : ( testPassed ? 0 : 2 ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestStart( void *inCtx ); +static void _KeepAliveTestStop( KeepAliveTestRef inTest, OSStatus inError ); +static OSStatus _KeepAliveTestStartSubtest( KeepAliveTestRef inTest ); +static void _KeepAliveTestStopSubtest( KeepAliveTestRef inTest ); +static KeepAliveSubtest * _KeepAliveTestGetSubtest( KeepAliveTestRef inTest ); +static const char * _KeepAliveTestGetSubtestLogPrefix( KeepAliveTestRef inTest, char *inBufPtr, size_t inBufLen ); +static OSStatus _KeepAliveTestContinue( KeepAliveTestRef inTest, OSStatus inSubtestError, Boolean *outDone ); +static void _KeepAliveTestTCPAcceptHandler( void *inCtx ); +static void _KeepAliveTestConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg ); +static void _KeepAliveTestHandleConnection( KeepAliveTestRef inTest, SocketRef inSock, OSStatus inError ); +static void _KeepAliveTestForgetConnection( KeepAliveTestRef inTest ); +static void DNSSD_API _KeepAliveTestKeepaliveCallback( DNSServiceRef inSDRef, DNSServiceErrorType inErr, void *inCtx ); +static void _KeepAliveTestQueryTimerHandler( void *inCtx ); +static void DNSSD_API + _KeepAliveTestQueryRecordCallback( + 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 * inCtx ); + +static OSStatus _KeepAliveTestCreate( KeepAliveTestRef *outTest ) +{ + OSStatus err; + KeepAliveTestRef test; + size_t i; + + test = (KeepAliveTestRef) calloc( 1, sizeof( *test ) ); + require_action( test, exit, err = kNoMemoryErr ); + + test->error = kInProgressErr; + for( i = 0; i < countof( test->subtests ); ++i ) + { + KeepAliveSubtest * const subtest = &test->subtests[ i ]; + + subtest->local.sa.sa_family = AF_UNSPEC; + subtest->remote.sa.sa_family = AF_UNSPEC; + subtest->clientSock = kInvalidSocketRef; + subtest->serverSock = kInvalidSocketRef; + } + test->queue = dispatch_queue_create( "com.apple.dnssdutil.keepalive-test", DISPATCH_QUEUE_SERIAL ); + require_action( test->queue, exit, err = kNoResourcesErr ); + + test->doneSem = dispatch_semaphore_create( 0 ); + require_action( test->doneSem, exit, err = kNoResourcesErr ); + + *outTest = test; + test = NULL; + err = kNoErr; + +exit: + if( test ) _KeepAliveTestFree( test ); + return( err ); +} + +//=========================================================================================================================== + +static OSStatus _KeepAliveTestRun( KeepAliveTestRef inTest ) +{ + dispatch_async_f( inTest->queue, inTest, _KeepAliveTestStart ); + dispatch_semaphore_wait( inTest->doneSem, DISPATCH_TIME_FOREVER ); + return( inTest->error ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestFree( KeepAliveTestRef inTest ) +{ + size_t i; + + check( !inTest->readSource ); + check( !inTest->query ); + check( !inTest->timer ); + check( !inTest->keepalive ); + check( !inTest->connection ); + check( !inTest->connectionCtx ); + dispatch_forget( &inTest->queue ); + dispatch_forget( &inTest->doneSem ); + for( i = 0; i < countof( inTest->subtests ); ++i ) + { + KeepAliveSubtest * const subtest = &inTest->subtests[ i ]; + + check( !IsValidSocket( subtest->clientSock ) ); + check( !IsValidSocket( subtest->serverSock ) ); + ForgetMem( &subtest->recordName ); + ForgetMem( &subtest->dataStr ); + } + free( inTest ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestStart( void *inCtx ) +{ + OSStatus err; + const KeepAliveTestRef test = (KeepAliveTestRef) inCtx; + + test->error = kInProgressErr; + test->startTime = NanoTimeGetCurrent(); + err = _KeepAliveTestStartSubtest( test ); + require_noerr( err, exit ); + +exit: + if( err ) _KeepAliveTestStop( test, err ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestStop( KeepAliveTestRef inTest, OSStatus inError ) +{ + size_t i; + + inTest->error = inError; + inTest->endTime = NanoTimeGetCurrent(); + _KeepAliveTestStopSubtest( inTest ); + for( i = 0; i < countof( inTest->subtests ); ++i ) + { + KeepAliveSubtest * const subtest = &inTest->subtests[ i ]; + + ForgetSocket( &subtest->clientSock ); + ForgetSocket( &subtest->serverSock ); + } + dispatch_semaphore_signal( inTest->doneSem ); +} + +//=========================================================================================================================== + +static OSStatus _KeepAliveTestStartSubtest( KeepAliveTestRef inTest ) +{ + OSStatus err; + KeepAliveSubtest * const subtest = _KeepAliveTestGetSubtest( inTest ); + const KeepAliveSubtestParams * const params = &kKeepAliveSubtestParams[ inTest->subtestIdx ]; + int port; + SocketRef sock = kInvalidSocketRef; + const uint32_t loopbackV4 = htonl( INADDR_LOOPBACK ); + SocketContext * sockCtx = NULL; + KeepAliveTestConnectionContext * cnxCtx = NULL; + Boolean useIPv4; + char serverAddrStr[ 64 ]; + char prefix[ 64 ]; + + subtest->error = kInProgressErr; + subtest->startTime = NanoTimeGetCurrent(); + subtest->description = params->description; + + require_action( ( params->family == AF_INET ) || ( params->family == AF_INET6 ), exit, err = kInternalErr ); + + // Create TCP listener socket. + + useIPv4 = ( params->family == AF_INET ) ? true : false; + err = ServerSocketOpenEx( params->family, SOCK_STREAM, IPPROTO_TCP, + useIPv4 ? ( (const void *) &loopbackV4 ) : ( (const void *) &in6addr_loopback ), kSocketPort_Auto, &port, + kSocketBufferSize_DontSet, &sock ); + require_noerr( err, exit ); + + if( useIPv4 ) SNPrintF( serverAddrStr, sizeof( serverAddrStr ), "%.4a:%d", &loopbackV4, port ); + else SNPrintF( serverAddrStr, sizeof( serverAddrStr ), "[%.16a]:%d", in6addr_loopback.s6_addr, port ); + _KeepAliveTestGetSubtestLogPrefix( inTest, prefix, sizeof( prefix ) ); + kat_ulog( kLogLevelInfo, "%s: Will listen for connections on %s\n", prefix, serverAddrStr ); + + err = SocketContextCreate( sock, inTest, &sockCtx ); + require_noerr( err, exit ); + sock = kInvalidSocketRef; + + // Create read source for TCP listener socket. + + check( !inTest->readSource ); + err = DispatchReadSourceCreate( sockCtx->sock, inTest->queue, _KeepAliveTestTCPAcceptHandler, + SocketContextCancelHandler, sockCtx, &inTest->readSource ); + require_noerr( err, exit ); + sockCtx = NULL; + dispatch_resume( inTest->readSource ); + + cnxCtx = (KeepAliveTestConnectionContext *) calloc( 1, sizeof( *cnxCtx ) ); + require_action( cnxCtx, exit, err = kNoMemoryErr ); + + // Start asynchronous connection to listener socket. + + kat_ulog( kLogLevelInfo, "%s: Will connect to %s\n", prefix, serverAddrStr ); + + check( !inTest->connection ); + err = AsyncConnection_Connect( &inTest->connection, serverAddrStr, 0, kAsyncConnectionFlags_None, + 5 * UINT64_C_safe( kNanosecondsPerSecond ), kSocketBufferSize_DontSet, kSocketBufferSize_DontSet, + NULL, NULL, _KeepAliveTestConnectionHandler, cnxCtx, inTest->queue ); + require_noerr( err, exit ); + + cnxCtx->test = inTest; + check( !inTest->connectionCtx ); + inTest->connectionCtx = cnxCtx; + cnxCtx = NULL; + +exit: + ForgetSocket( &sock ); + if( sockCtx ) SocketContextRelease( sockCtx ); + FreeNullSafe( cnxCtx ); + return( err ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestStopSubtest( KeepAliveTestRef inTest ) +{ + dispatch_source_forget( &inTest->readSource ); + DNSServiceForget( &inTest->keepalive ); + DNSServiceForget( &inTest->query ); + dispatch_source_forget( &inTest->timer ); + _KeepAliveTestForgetConnection( inTest ); +} + +//=========================================================================================================================== + +static KeepAliveSubtest * _KeepAliveTestGetSubtest( KeepAliveTestRef inTest ) +{ + return( ( inTest->subtestIdx < countof( inTest->subtests ) ) ? &inTest->subtests[ inTest->subtestIdx ] : NULL ); +} + +//=========================================================================================================================== + +static const char * _KeepAliveTestGetSubtestLogPrefix( KeepAliveTestRef inTest, char *inBufPtr, size_t inBufLen ) +{ + SNPrintF( inBufPtr, inBufLen, "Subtest %zu/%zu", inTest->subtestIdx + 1, countof( inTest->subtests ) ); + return( inBufPtr ); +} + +//=========================================================================================================================== + +static OSStatus _KeepAliveTestContinue( KeepAliveTestRef inTest, OSStatus inSubtestError, Boolean *outDone ) +{ + OSStatus err; + KeepAliveSubtest * subtest; + + require_action( inTest->subtestIdx <= countof( inTest->subtests ), exit, err = kInternalErr ); + + if( inTest->subtestIdx < countof( inTest->subtests ) ) + { + subtest = _KeepAliveTestGetSubtest( inTest ); + _KeepAliveTestStopSubtest( inTest ); + subtest->endTime = NanoTimeGetCurrent(); + subtest->error = inSubtestError; + if( ++inTest->subtestIdx < countof( inTest->subtests ) ) + { + err = _KeepAliveTestStartSubtest( inTest ); + require_noerr_quiet( err, exit ); + } + } + err = kNoErr; + +exit: + if( outDone ) *outDone = ( !err && ( inTest->subtestIdx == countof( inTest->subtests ) ) ) ? true : false; + return( err ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestTCPAcceptHandler( void *inCtx ) +{ + OSStatus err; + const SocketContext * const sockCtx = (SocketContext *) inCtx; + const KeepAliveTestRef test = (KeepAliveTestRef) sockCtx->userContext; + KeepAliveSubtest * const subtest = _KeepAliveTestGetSubtest( test ); + sockaddr_ip peer; + socklen_t len; + char prefix[ 64 ]; + + check( !IsValidSocket( subtest->serverSock ) ); + len = (socklen_t) sizeof( peer ); + subtest->serverSock = accept( sockCtx->sock, &peer.sa, &len ); + err = map_socket_creation_errno( subtest->serverSock ); + require_noerr( err, exit ); + + _KeepAliveTestGetSubtestLogPrefix( test, prefix, sizeof( prefix ) ); + kat_ulog( kLogLevelInfo, "%s: Accepted connection from %##a\n", prefix, &peer.sa ); + + dispatch_source_forget( &test->readSource ); + +exit: + if( err ) _KeepAliveTestStop( test, err ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg ) +{ + KeepAliveTestConnectionContext * ctx = (KeepAliveTestConnectionContext *) inArg; + const KeepAliveTestRef test = ctx->test; + + if( test ) + { + _KeepAliveTestForgetConnection( test ); + _KeepAliveTestHandleConnection( test, inSock, inError ); + inSock = kInvalidSocketRef; + } + ForgetSocket( &inSock ); + free( ctx ); +} + +//=========================================================================================================================== + +#define kKeepAliveTestQueryTimeoutSecs 5 + +static void _KeepAliveTestHandleConnection( KeepAliveTestRef inTest, SocketRef inSock, OSStatus inError ) +{ + OSStatus err; + KeepAliveSubtest * const subtest = _KeepAliveTestGetSubtest( inTest ); + const KeepAliveSubtestParams * const params = &kKeepAliveSubtestParams[ inTest->subtestIdx ]; + socklen_t len; + uint32_t value; + int family, i; + Boolean subtestFailed = false; + Boolean done; + char prefix[ 64 ]; + + require_noerr_action( inError, exit, err = inError ); + + check( !IsValidSocket( subtest->clientSock ) ); + subtest->clientSock = inSock; + inSock = kInvalidSocketRef; + + // Get local and remote IP addresses. + + len = (socklen_t) sizeof( subtest->local ); + err = getsockname( subtest->clientSock, &subtest->local.sa, &len ); + err = map_global_noerr_errno( err ); + require_noerr( err, exit ); + + len = (socklen_t) sizeof( subtest->remote ); + err = getpeername( subtest->clientSock, &subtest->remote.sa, &len ); + err = map_global_noerr_errno( err ); + require_noerr( err, exit ); + + _KeepAliveTestGetSubtestLogPrefix( inTest, prefix, sizeof( prefix ) ); + kat_ulog( kLogLevelInfo, "%s: Connection established: %##a <-> %##a\n", + prefix, &subtest->local.sa, &subtest->remote.sa ); + + // Call either DNSServiceSleepKeepalive() or DNSServiceSleepKeepalive_sockaddr(). + + check( subtest->timeoutKA == 0 ); + subtest->timeoutKA = (unsigned int) RandomRange( 1, UINT_MAX ); + + switch( params->callVariant ) + { + case kKeepAliveCallVariant_TakesSocket: + kat_ulog( kLogLevelInfo, "%s: Will call DNSServiceSleepKeepalive() for client-side socket\n", prefix ); + check( !inTest->keepalive ); + err = DNSServiceSleepKeepalive( &inTest->keepalive, 0, subtest->clientSock, + subtest->timeoutKA, _KeepAliveTestKeepaliveCallback, inTest ); + require_noerr( err, exit ); + + err = DNSServiceSetDispatchQueue( inTest->keepalive, inTest->queue ); + require_noerr( err, exit ); + break; + + case kKeepAliveCallVariant_TakesSockAddrs: + kat_ulog( kLogLevelInfo, + "%s: Will call DNSServiceSleepKeepalive_sockaddr() for local and remote sockaddrs\n", prefix ); + if( !SOFT_LINK_HAS_FUNCTION( system_dnssd, DNSServiceSleepKeepalive_sockaddr ) ) + { + kat_ulog( kLogLevelError, + "%s: Failed to soft link DNSServiceSleepKeepalive_sockaddr from libsystem_dnssd.\n", prefix ); + subtestFailed = true; + err = kUnsupportedErr; + goto exit; + } + check( !inTest->keepalive ); + err = soft_DNSServiceSleepKeepalive_sockaddr( &inTest->keepalive, 0, &subtest->local.sa, &subtest->remote.sa, + subtest->timeoutKA, _KeepAliveTestKeepaliveCallback, inTest ); + require_noerr( err, exit ); + + err = DNSServiceSetDispatchQueue( inTest->keepalive, inTest->queue ); + require_noerr( err, exit ); + break; + + default: + kat_ulog( kLogLevelError, "%s: Invalid KeepAliveCallVariant value %d\n", prefix, (int) params->callVariant ); + err = kInternalErr; + goto exit; + } + // Use the same logic that the DNSServiceSleepKeepalive functions use to derive a record name and rdata. + + value = 0; + family = subtest->local.sa.sa_family; + if( family == AF_INET ) + { + const struct sockaddr_in * const sin = &subtest->local.v4; + const uint8_t * ptr; + + check_compile_time_code( sizeof( sin->sin_addr.s_addr ) == 4 ); + ptr = (const uint8_t *) &sin->sin_addr.s_addr; + for( i = 0; i < 4; ++i ) value += ptr[ i ]; + value += sin->sin_port; // Note: No ntohl(). This is what DNSServiceSleepKeepalive does. + + check( subtest->remote.sa.sa_family == AF_INET ); + ASPrintF( &subtest->dataStr, "t=%u h=%.4a d=%.4a l=%u r=%u", + subtest->timeoutKA, &subtest->local.v4.sin_addr.s_addr, &subtest->remote.v4.sin_addr.s_addr, + ntohs( subtest->local.v4.sin_port ), ntohs( subtest->remote.v4.sin_port ) ); + require_action( subtest->dataStr, exit, err = kNoMemoryErr ); + } + else if( family == AF_INET6 ) + { + const struct sockaddr_in6 * const sin6 = &subtest->local.v6; + + check_compile_time_code( countof( sin6->sin6_addr.s6_addr ) == 16 ); + for( i = 0; i < 16; ++i ) value += sin6->sin6_addr.s6_addr[ i ]; + value += sin6->sin6_port; // Note: No ntohl(). This is what DNSServiceSleepKeepalive does. + + check( subtest->remote.sa.sa_family == AF_INET6 ); + ASPrintF( &subtest->dataStr, "t=%u H=%.16a D=%.16a l=%u r=%u", + subtest->timeoutKA, subtest->local.v6.sin6_addr.s6_addr, subtest->remote.v6.sin6_addr.s6_addr, + ntohs( subtest->local.v6.sin6_port ), ntohs( subtest->remote.v6.sin6_port ) ); + require_action( subtest->dataStr, exit, err = kNoMemoryErr ); + } + else + { + kat_ulog( kLogLevelError, "%s: Unexpected local address family %d\n", prefix, family ); + err = kInternalErr; + goto exit; + } + + // Start query for the new keepalive record. + + check( !subtest->recordName ); + ASPrintF( &subtest->recordName, "%u._keepalive._dns-sd._udp.local.", value ); + require_action( subtest->recordName, exit, err = kNoMemoryErr ); + + kat_ulog( kLogLevelInfo, "%s: Will query for %s NULL record\n", prefix, subtest->recordName ); + check( !inTest->query ); + err = DNSServiceQueryRecord( &inTest->query, 0, kDNSServiceInterfaceIndexLocalOnly, subtest->recordName, + kDNSServiceType_NULL, kDNSServiceClass_IN, _KeepAliveTestQueryRecordCallback, inTest ); + require_noerr( err, exit ); + + err = DNSServiceSetDispatchQueue( inTest->query, inTest->queue ); + require_noerr( err, exit ); + + // Start timer to enforce a time limit on the query. + + check( !inTest->timer ); + err = DispatchTimerOneShotCreate( dispatch_time_seconds( kKeepAliveTestQueryTimeoutSecs ), + kKeepAliveTestQueryTimeoutSecs * ( INT64_C_safe( kNanosecondsPerSecond ) / 20 ), inTest->queue, + _KeepAliveTestQueryTimerHandler, inTest, &inTest->timer ); + require_noerr( err, exit ); + dispatch_resume( inTest->timer ); + +exit: + ForgetSocket( &inSock ); + if( subtestFailed ) + { + err = _KeepAliveTestContinue( inTest, err, &done ); + check_noerr( err ); + } + else + { + done = false; + } + if( err || done ) _KeepAliveTestStop( inTest, err ); +} + +//=========================================================================================================================== + +static void _KeepAliveTestForgetConnection( KeepAliveTestRef inTest ) +{ + if( inTest->connection ) + { + check( inTest->connectionCtx ); + inTest->connectionCtx->test = NULL; // Unset the connection's back pointer to test. + inTest->connectionCtx = NULL; // Context will be freed by the connection's handler. + AsyncConnection_Forget( &inTest->connection ); + } +} + +//=========================================================================================================================== + +static void DNSSD_API _KeepAliveTestKeepaliveCallback( DNSServiceRef inSDRef, DNSServiceErrorType inError, void *inCtx ) +{ + OSStatus err; + const KeepAliveTestRef test = (KeepAliveTestRef) inCtx; + char prefix[ 64 ]; + + Unused( inSDRef ); + + _KeepAliveTestGetSubtestLogPrefix( test, prefix, sizeof( prefix ) ); + kat_ulog( kLogLevelInfo, "%s: Keepalive callback error: %#m\n", prefix, inError ); + + if( inError ) + { + Boolean done; + + err = _KeepAliveTestContinue( test, inError, &done ); + check_noerr( err ); + if( err || done ) _KeepAliveTestStop( test, err ); + } +} + +//=========================================================================================================================== + +static void _KeepAliveTestQueryTimerHandler( void *inCtx ) +{ + OSStatus err; + const KeepAliveTestRef test = (KeepAliveTestRef) inCtx; + KeepAliveSubtest * const subtest = _KeepAliveTestGetSubtest( test ); + Boolean done; + char prefix[ 64 ]; + + _KeepAliveTestGetSubtestLogPrefix( test, prefix, sizeof( prefix ) ); + kat_ulog( kLogLevelInfo, "%s: Query for \"%s\" timed out.\n", prefix, subtest->recordName ); + + err = _KeepAliveTestContinue( test, kTimeoutErr, &done ); + check_noerr( err ); + if( err || done ) _KeepAliveTestStop( test, err ); +} + +//=========================================================================================================================== + +static void DNSSD_API + _KeepAliveTestQueryRecordCallback( + 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 * inCtx ) +{ + OSStatus err; + const KeepAliveTestRef test = (KeepAliveTestRef) inCtx; + KeepAliveSubtest * const subtest = _KeepAliveTestGetSubtest( test ); + const uint8_t * ptr; + size_t dataStrLen, minLen; + Boolean done; + char prefix[ 64 ]; + + Unused( inSDRef ); + Unused( inInterfaceIndex ); + Unused( inTTL ); + + _KeepAliveTestGetSubtestLogPrefix( test, prefix, sizeof( prefix ) ); + if( strcasecmp( inFullName, subtest->recordName ) != 0 ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: Got unexpected record name \"%s\".\n", + prefix, subtest->recordName, inFullName ); + err = kUnexpectedErr; + goto exit; + } + if( inType != kDNSServiceType_NULL ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: Got unexpected record type %d (%s) != %d (NULL).\n", + prefix, subtest->recordName, inType, RecordTypeToString( inType ), kDNSServiceType_NULL ); + err = kUnexpectedErr; + goto exit; + } + if( inClass != kDNSServiceClass_IN ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: Got unexpected record class %d != %d (IN).\n", + prefix, subtest->recordName, inClass, kDNSServiceClass_IN ); + err = kUnexpectedErr; + goto exit; + } + if( inError ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: Got unexpected error %#m.\n", + prefix, subtest->recordName, inError ); + err = inError; + goto exit; + } + if( ( inFlags & kDNSServiceFlagsAdd ) == 0 ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: Missing Add flag.\n", prefix, subtest->recordName ); + err = kUnexpectedErr; + goto exit; + } + kat_ulog( kLogLevelInfo, "%s: QueryRecord(%s) result rdata: %#H\n", + prefix, subtest->recordName, inRDataPtr, inRDataLen, inRDataLen ); + + dataStrLen = strlen( subtest->dataStr ) + 1; // There's a NUL terminator at the end of the rdata. + minLen = 1 + dataStrLen; // The first byte of the rdata is a length byte. + if( inRDataLen < minLen ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: rdata length (%d) is less than expected minimum (%zu).\n", + prefix, subtest->recordName, inRDataLen, minLen ); + err = kUnexpectedErr; + goto exit; + } + ptr = (const uint8_t *) inRDataPtr; + if( ptr[ 0 ] < dataStrLen ) + { + kat_ulog( kLogLevelError, + "%s: QueryRecord(%s) result: rdata length byte value (%d) is less than expected minimum (%zu).\n", + prefix, subtest->recordName, ptr[ 0 ], dataStrLen ); + err = kUnexpectedErr; + goto exit; + } + if( memcmp( &ptr[ 1 ], subtest->dataStr, dataStrLen - 1 ) != 0 ) + { + kat_ulog( kLogLevelError, "%s: QueryRecord(%s) result: rdata body doesn't contain '%s'.\n", + prefix, subtest->recordName, subtest->dataStr ); + } + err = kNoErr; + +exit: + err = _KeepAliveTestContinue( test, err, &done ); + check_noerr( err ); + if( err || done ) _KeepAliveTestStop( test, kNoErr ); +} +#endif // TARGET_OS_DARWIN + //=========================================================================================================================== // SSDPDiscoverCmd //=========================================================================================================================== @@ -16875,7 +17898,7 @@ static void SSDPDiscoverCmd( void ) // Set up SIGINT handler. signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), Exit, kExitReason_SIGINT, &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -18085,7 +19108,8 @@ static void InterfaceMonitorCmd( void ) mdns_interface_monitor_activate( monitor ); signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, _InterfaceMonitorSignalHandler, monitor, &signalSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), _InterfaceMonitorSignalHandler, monitor, + &signalSource ); require_noerr( err, exit ); dispatch_resume( signalSource ); @@ -18170,12 +19194,14 @@ static void DNSProxyCmd( void ) require_noerr_quiet( err, exit ); signal( SIGINT, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGINT, _DNSProxyCmdSignalHandler, connection, &sigIntSource ); + err = DispatchSignalSourceCreate( SIGINT, dispatch_get_main_queue(), _DNSProxyCmdSignalHandler, connection, + &sigIntSource ); require_noerr( err, exit ); dispatch_activate( sigIntSource ); signal( SIGTERM, SIG_IGN ); - err = DispatchSignalSourceCreate( SIGTERM, _DNSProxyCmdSignalHandler, connection, &sigTermSource ); + err = DispatchSignalSourceCreate( SIGTERM, dispatch_get_main_queue(), _DNSProxyCmdSignalHandler, connection, + &sigTermSource ); require_noerr( err, exit ); dispatch_activate( sigTermSource ); @@ -19334,6 +20360,7 @@ exit: static OSStatus DispatchSignalSourceCreate( int inSignal, + dispatch_queue_t inQueue, DispatchHandler inEventHandler, void * inContext, dispatch_source_t * outSource ) @@ -19341,7 +20368,7 @@ static OSStatus OSStatus err; dispatch_source_t source; - source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, dispatch_get_main_queue() ); + source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, inQueue ); require_action( source, exit, err = kUnknownErr ); dispatch_set_context( source, inContext ); diff --git a/Makefile b/Makefile index f2d7645..ad4b4ca 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ include $(MAKEFILEPATH)/pb_makefiles/platform.make -MVERS = "mDNSResponder-1096.60.2" +MVERS = "mDNSResponder-1096.100.3" VER = ifneq ($(strip $(GCC_VERSION)),) diff --git a/mDNSMacOSX/DNSSECSupport.c b/mDNSMacOSX/DNSSECSupport.c index 6e1ac46..acaff4e 100644 --- a/mDNSMacOSX/DNSSECSupport.c +++ b/mDNSMacOSX/DNSSECSupport.c @@ -28,9 +28,9 @@ // Following are needed for fetching the root trust anchor dynamically #include -#include -#include -#include +#include +#include +#include #include // 30 days diff --git a/mDNSMacOSX/Tests/mDNSResponder.plist b/mDNSMacOSX/Tests/mDNSResponder.plist index 5007abf..79dc174 100644 --- a/mDNSMacOSX/Tests/mDNSResponder.plist +++ b/mDNSMacOSX/Tests/mDNSResponder.plist @@ -957,6 +957,47 @@ mDNSResponder + + TestName + KeepAlive Record Registration + Description + Tests KeepAlive record registrations. + AsRoot + + RequiresWiFi + + Timeout + 60 + IgnoreOutput + + Command + + /usr/local/bin/dnssdutil + test + keepalive + --format + json + + + + TestName + mDNSResponder Leaks + Description + Checks mDNSResponder for memory leaks. + AsRoot + + RequiresWiFi + + Timeout + 10 + IgnoreOutput + + Command + + /usr/bin/leaks + mDNSResponder + + TestName Probe Conflicts diff --git a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj index 5f23f0b..1aafbd1 100644 --- a/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj +++ b/mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj @@ -4010,6 +4010,19 @@ 0C419F241BA20DF600A70FF7 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_ASSIGN_ENUM = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES_ERROR; + CLANG_WARN_BOOL_CONVERSION = YES_ERROR; + CLANG_WARN_COMMA = YES_ERROR; + CLANG_WARN_CONSTANT_CONVERSION = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES_ERROR; + CLANG_WARN_FLOAT_CONVERSION = YES_ERROR; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES_ERROR; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; + CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES; + CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; EXECUTABLE_EXTENSION = dylib; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -4017,6 +4030,20 @@ "__DARWIN_NON_CANCELABLE=1", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES_ERROR; + 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_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; INSTALLHDRS_COPY_PHASE = YES; INSTALLHDRS_SCRIPT_PHASE = YES; @@ -6027,6 +6054,19 @@ FFB7658A0AEED9FB00583A2C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_WARN_ASSIGN_ENUM = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES_ERROR; + CLANG_WARN_BOOL_CONVERSION = YES_ERROR; + CLANG_WARN_COMMA = YES_ERROR; + CLANG_WARN_CONSTANT_CONVERSION = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES_ERROR; + CLANG_WARN_FLOAT_CONVERSION = YES_ERROR; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES_ERROR; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; + CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES; + CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; EXECUTABLE_EXTENSION = dylib; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -6034,6 +6074,20 @@ "__DARWIN_NON_CANCELABLE=1", ); GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES_ERROR; + 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_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_LABEL = YES; + GCC_WARN_UNUSED_PARAMETER = YES; + GCC_WARN_UNUSED_VARIABLE = YES; HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/"; INSTALLHDRS_COPY_PHASE = YES; INSTALLHDRS_SCRIPT_PHASE = YES; diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile index 78222e0..16477ce 100755 --- a/mDNSPosix/Makefile +++ b/mDNSPosix/Makefile @@ -222,325 +222,3 @@ ifeq ($(wildcard /etc/init.d/rc2.d/), /etc/init.d/rc2.d/) STARTUPSCRIPTDIR = /etc/init.d RUNLEVELSCRIPTSDIR = /etc/init.d else -# else if directory /etc/rc.d/init.d/ exists, then we install into that (old Linux) -ifeq ($(wildcard /etc/rc.d/init.d/), /etc/rc.d/init.d/) -STARTUPSCRIPTDIR = /etc/rc.d/init.d -RUNLEVELSCRIPTSDIR = /etc/rc.d -else -# else if directory /etc/init.d/ exists, then we install into that (new Linux) -ifeq ($(wildcard /etc/init.d/), /etc/init.d/) -STARTUPSCRIPTDIR = /etc/init.d -RUNLEVELSCRIPTSDIR = /etc -else -# else install into /etc/rc.d/ (*BSD) -STARTUPSCRIPTDIR = $(INSTBASE)/etc/rc.d -endif -endif -endif - -MDNSCFLAGS = $(CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUGGING) $(CFLAGS_OPEN_SOURCE) - -############################################################################# - -all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder NetMonitor $(OPTIONALTARG) - -install: setup InstalledStartup InstalledDaemon InstalledLib InstalledManPages InstalledClients $(OPTINSTALL) - -# '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 - @$(MAKE) -C ../Clients clean - -############################################################################# - -# 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)/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 \ - $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/PlatformCommon.c.o $(OBJDIR)/dnsextd_parser.y.o $(OBJDIR)/dnsextd_lexer.l.o \ - $(OBJDIR)/CryptoAlg.c.o - -Daemon: setup $(BUILDDIR)/mdnsd - @echo "Responder daemon done" - -$(BUILDDIR)/mdnsd: $(DAEMONOBJS) - $(CC) -o $@ $+ $(LINKOPTS) - $(STRIP) $@ - -# libdns_sd target builds the client library -libdns_sd: setup $(BUILDDIR)/libdns_sd.$(LDSUFFIX) - @echo "Client library done" - -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) $(SOOPTS) $(LINKOPTS) -o $@ $+ - $(STRIP) $@ - -Clients: setup libdns_sd ../Clients/build/dns-sd - @echo "Clients done" - -../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) $(SOOPTS) $(LINKOPTS) -o $@ $+ - $(STRIP) $@ - -############################################################################# - -# The Install targets place built stuff in their proper places -InstalledDaemon: $(INSTBASE)/sbin/mdnsd - @echo $+ " installed" - -InstalledLib: $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS) $(INSTBASE)/include/dns_sd.h - @echo $+ " installed" - -InstalledStartup: $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) - @echo $+ " installed" - -InstalledManPages: $(MANPATH)/man8/mdnsd.8 - @echo $+ " installed" - -InstalledClients: $(INSTBASE)/bin/dns-sd - @echo $+ " installed" - -InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/nss_mdns.conf.5 $(MANPATH)/man8/libnss_mdns.8 - @echo $+ " installed" - -# Note: If daemon already installed, we make sure it's stopped before overwriting it -$(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) - if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi - $(CP) $< $@ - $(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' - $(LDCONFIG) -mR -endif - -$(INSTBASE)/include/dns_sd.h: $(SHAREDDIR)/dns_sd.h - $(CP) $< $@ - -$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME): mdnsd.sh $(STARTUPSCRIPTDIR) - $(CP) $< $@ - chmod ugo+x $@ -ifdef RUNLEVELSCRIPTSDIR -ifeq ($(wildcard $(RUNLEVELSCRIPTSDIR)/runlevels/default), $(RUNLEVELSCRIPTSDIR)/runlevels/default) - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/runlevels/default/mdns -else - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc2.d/S52mdns - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc3.d/S52mdns - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc4.d/S52mdns - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc5.d/S52mdns - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc0.d/K16mdns - $(LN) $@ $(RUNLEVELSCRIPTSDIR)/rc6.d/K16mdns -endif -endif - -$(MANPATH)/man5/%.5: %.5 - cp $< $@ - chmod 444 $@ - -$(MANPATH)/man8/%.8: %.8 - cp $< $@ - chmod 444 $@ - -$(MANPATH)/man8/mdnsd.8: $(SHAREDDIR)/mDNSResponder.8 - cp $< $@ - chmod 444 $@ - -$(INSTBASE)/bin/dns-sd: ../Clients/build/dns-sd - $(CP) $< $@ - -$(NSSINSTPATH)/$(NSSLINKNAME): $(NSSINSTPATH)/$(NSSLIBFILE) - $(LN) $< $@ - ldconfig - -$(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE) - $(CP) $< $@ - chmod 444 $@ - -/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' - 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 - -############################################################################# - -# The following targets build Java wrappers for the dns-sd.h API. -# Note that the JavaForXcode targets are used when building the project for OS X using Xcode - -JAVAC = $(JDK)/bin/javac -JAVAH = $(JDK)/bin/javah -JAVADOC = $(JDK)/bin/javadoc -JAR = $(JDK)/bin/jar -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) $< $@ - -JavaForXcode_clean: - @if test -d $(OBJDIR) ; then rm -r $(OBJDIR) ; fi - @if test -f $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h ; then $(RM) $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h ; fi - @if test -f $(BUILDDIR)/dns_sd.jar ; then $(RM) $(BUILDDIR)/dns_sd.jar ; fi - @echo $@ done - -JavaForXcode_installhdrs: - @echo $@ NOOP - -JavaForXcode_install: JavaForXcode_ $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions/dns_sd.jar - @echo $@ done - -$(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions/dns_sd.jar: $(BUILDDIR)/dns_sd.jar - @if test ! -d $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions ; then mkdir -p $(DSTROOT)/$(SYSTEM_LIBRARY_DIR)/Java/Extensions ; fi - $(CP) $< $@ - -Java: setup $(BUILDDIR)/dns_sd.jar $(BUILDDIR)/libjdns_sd.$(LDSUFFIX) - @echo "Java wrappers done" - -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/BaseListener.class \ - $(OBJDIR)/com/apple/dnssd/BrowseListener.class \ - $(OBJDIR)/com/apple/dnssd/ResolveListener.class \ - $(OBJDIR)/com/apple/dnssd/RegisterListener.class \ - $(OBJDIR)/com/apple/dnssd/QueryListener.class \ - $(OBJDIR)/com/apple/dnssd/DomainListener.class \ - $(OBJDIR)/com/apple/dnssd/RegisterRecordListener.class \ - $(OBJDIR)/com/apple/dnssd/DNSSDRecordRegistrar.class \ - $(OBJDIR)/com/apple/dnssd/DNSSD.class - -$(BUILDDIR)/dns_sd.jar: $(JARCONTENTS) setup - $(JAR) -cf $@ -C $(OBJDIR) com - -$(BUILDDIR)/libjdns_sd.$(LDSUFFIX): $(JAVASRC)/JNISupport.c $(OBJDIR)/DNSSD.java.h setup libdns_sd - $(CC) -o $@ $< $(JAVACFLAGS) -I$(OBJDIR) -L$(BUILDDIR) - -$(OBJDIR)/com/apple/dnssd/%.class: $(JAVASRC)/%.java - $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $< - -$(OBJDIR)/DNSSD.java.h: $(OBJDIR)/com/apple/dnssd/DNSSD.class - $(JAVAH) -force -classpath $(OBJDIR) -o $@ \ - com.apple.dnssd.AppleDNSSD \ - com.apple.dnssd.AppleBrowser \ - com.apple.dnssd.AppleResolver \ - com.apple.dnssd.AppleRegistration \ - com.apple.dnssd.AppleQuery \ - com.apple.dnssd.AppleDomainEnum \ - com.apple.dnssd.AppleService \ - com.apple.dnssd.AppleDNSRecord \ - com.apple.dnssd.AppleRecordRegistrar - -############################################################################# - -# The following target builds documentation for the Java wrappers. - -JavaDoc: Java setup - $(JAVADOC) $(JAVASRC)/*.java -classpath $(OBJDIR) -d $(BUILDDIR) -public - -############################################################################# - -# 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)/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 - -SAClient: setup $(BUILDDIR)/mDNSClientPosix - @echo "Embedded Standalone Client done" - -SAResponder: setup $(BUILDDIR)/mDNSResponderPosix - @echo "Embedded Standalone Responder done" - -SAProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix - @echo "Embedded Standalone ProxyResponder done" - -NetMonitor: setup $(BUILDDIR)/mDNSNetMonitor - @echo "NetMonitor done" - -dnsextd: setup $(BUILDDIR)/dnsextd - @echo "dnsextd done" - -$(BUILDDIR)/mDNSClientPosix: $(APPOBJ) $(OBJDIR)/Client.c.o - $(CC) $+ -o $@ $(LINKOPTS) - -$(BUILDDIR)/mDNSResponderPosix: $(COMMONOBJ) $(OBJDIR)/Responder.c.o - $(CC) $+ -o $@ $(LINKOPTS) - -$(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ) $(OBJDIR)/ProxyResponder.c.o - $(CC) $+ -o $@ $(LINKOPTS) - -$(BUILDDIR)/mDNSNetMonitor: $(SPECIALOBJ) $(OBJDIR)/NetMonitor.c.o - $(CC) $+ -o $@ $(LINKOPTS) - -$(OBJDIR)/NetMonitor.c.o: $(COREDIR)/mDNS.c # Note: NetMonitor.c textually imports mDNS.c - -$(BUILDDIR)/dnsextd: $(DNSEXTDOBJ) $(OBJDIR)/dnsextd.c.threadsafe.o - $(CC) $+ -o $@ $(LINKOPTS) $(LINKOPTS_PTHREAD) - -############################################################################# - -# Implicit rules -$(OBJDIR)/%.c.o: %.c - $(CC) $(MDNSCFLAGS) -c -o $@ $< - -$(OBJDIR)/%.c.o: $(COREDIR)/%.c - $(CC) $(MDNSCFLAGS) -c -o $@ $< - -$(OBJDIR)/%.c.o: $(SHAREDDIR)/%.c - $(CC) $(MDNSCFLAGS) -c -o $@ $< - -$(OBJDIR)/%.c.o: $(DSODIR)/%.c - $(CC) $(MDNSCFLAGS) -c -o $@ $< - -$(OBJDIR)/%.c.threadsafe.o: %.c - $(CC) $(MDNSCFLAGS) $(MDNSCFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $< - -$(OBJDIR)/%.c.threadsafe.o: $(SHAREDDIR)/%.c - $(CC) $(MDNSCFLAGS) $(MDNSCFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $< - -$(OBJDIR)/%.c.so.o: %.c - $(CC) $(MDNSCFLAGS) -c -fPIC -o $@ $< - -$(OBJDIR)/%.c.so.o: $(SHAREDDIR)/%.c - $(CC) $(MDNSCFLAGS) -c -fPIC -o $@ $< - -$(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y - $(BISON) -o $(OBJDIR)/$*.c -d $< - $(CC) $(MDNSCFLAGS) -c -o $@ $(OBJDIR)/$*.c - -$(OBJDIR)/%.l.o: $(SHAREDDIR)/%.l - $(FLEX) $(FLEXFLAGS_OS) -i -o$(OBJDIR)/$*.l.c $< - $(CC) $(MDNSCFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h index d44a949..e1080ff 100644 --- a/mDNSShared/dns_sd.h +++ b/mDNSShared/dns_sd.h @@ -66,7 +66,7 @@ */ #ifndef _DNS_SD_H -#define _DNS_SD_H 10966002 +#define _DNS_SD_H 10970003 #ifdef __cplusplus extern "C" { diff --git a/mDNSShared/dns_sd_private.h b/mDNSShared/dns_sd_private.h index 0c5d2c9..19de052 100644 --- a/mDNSShared/dns_sd_private.h +++ b/mDNSShared/dns_sd_private.h @@ -94,6 +94,18 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID DNSSD_EXPORT DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain); +SPI_AVAILABLE(macos(10.15.4), ios(13.2.2), watchos(6.2), tvos(13.2)) +DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive_sockaddr +( + DNSServiceRef * sdRef, + DNSServiceFlags flags, + const struct sockaddr * localAddr, + const struct sockaddr * remoteAddr, + unsigned int timeout, + DNSServiceSleepKeepaliveReply callBack, + void * context +); + #define kDNSServiceCompPrivateDNS "PrivateDNS" #define kDNSServiceCompMulticastDNS "MulticastDNS" diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c index fbeeb12..a5111a2 100644 --- a/mDNSShared/dnssd_clientstub.c +++ b/mDNSShared/dnssd_clientstub.c @@ -2353,6 +2353,17 @@ static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef r ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext); } +static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr +( + DNSServiceRef * sdRef, + DNSServiceFlags flags, + const struct sockaddr * localAddr, + const struct sockaddr * remoteAddr, + unsigned int timeout, + DNSServiceSleepKeepaliveReply callBack, + void * context +); + DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive ( DNSServiceRef *sdRef, @@ -2363,24 +2374,9 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive void *context ) { - char source_str[INET6_ADDRSTRLEN]; - char target_str[INET6_ADDRSTRLEN]; struct sockaddr_storage lss; struct sockaddr_storage rss; socklen_t len1, len2; - unsigned int len, proxyreclen; - char buf[256]; - DNSServiceErrorType err; - DNSRecordRef record = NULL; - char name[10]; - char recname[128]; - SleepKAContext *ka; - unsigned int i, unique; - - - (void) flags; //unused - if (!timeout) return kDNSServiceErr_BadParam; - len1 = sizeof(lss); if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0) @@ -2401,12 +2397,54 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same"); return kDNSServiceErr_Unknown; } + return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, (const struct sockaddr *)&lss, (const struct sockaddr *)&rss, + timeout, callBack, context); +} + +DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive_sockaddr +( + DNSServiceRef * sdRef, + DNSServiceFlags flags, + const struct sockaddr * localAddr, + const struct sockaddr * remoteAddr, + unsigned int timeout, + DNSServiceSleepKeepaliveReply callBack, + void * context +) +{ + return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, localAddr, remoteAddr, timeout, callBack, context ); +} + +static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr +( + DNSServiceRef * sdRef, + DNSServiceFlags flags, + const struct sockaddr * localAddr, + const struct sockaddr * remoteAddr, + unsigned int timeout, + DNSServiceSleepKeepaliveReply callBack, + void * context +) +{ + char source_str[INET6_ADDRSTRLEN]; + char target_str[INET6_ADDRSTRLEN]; + unsigned int len, proxyreclen; + char buf[256]; + DNSServiceErrorType err; + DNSRecordRef record = NULL; + char name[10]; + char recname[128]; + SleepKAContext *ka; + unsigned int i, unique; + + (void) flags; //unused + if (!timeout) return kDNSServiceErr_BadParam; unique = 0; - if (lss.ss_family == AF_INET) + if ((localAddr->sa_family == AF_INET) && (remoteAddr->sa_family == AF_INET)) { - struct sockaddr_in *sl = (struct sockaddr_in *)&lss; - struct sockaddr_in *sr = (struct sockaddr_in *)&rss; + const struct sockaddr_in *sl = (const struct sockaddr_in *)localAddr; + const struct sockaddr_in *sr = (const struct sockaddr_in *)remoteAddr; unsigned char *ptr = (unsigned char *)&sl->sin_addr; if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str))) @@ -2426,10 +2464,10 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive unique += sl->sin_port; len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port)); } - else + else if ((localAddr->sa_family == AF_INET6) && (remoteAddr->sa_family == AF_INET6)) { - struct sockaddr_in6 *sl6 = (struct sockaddr_in6 *)&lss; - struct sockaddr_in6 *sr6 = (struct sockaddr_in6 *)&rss; + const struct sockaddr_in6 *sl6 = (const struct sockaddr_in6 *)localAddr; + const struct sockaddr_in6 *sr6 = (const struct sockaddr_in6 *)remoteAddr; unsigned char *ptr = (unsigned char *)&sl6->sin6_addr; if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str))) @@ -2447,6 +2485,10 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive unique += sl6->sin6_port; len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port)); } + else + { + return kDNSServiceErr_BadParam; + } if (len >= (sizeof(buf) - 1)) { -- 2.45.2