/*
* Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
Change History (most recent first):
$Log: Tool.c,v $
Revision 1.3 2004/09/16 01:58:25 cheshire
Fix compiler warnings
Revision 1.2 2004/07/13 21:24:28 rpantos
Fix for <rdar://problem/3701120>.
Revision 1.1 2004/06/18 04:07:54 rpantos
Move up one level
Revision 1.12 2004/04/09 21:03:15 bradley
Changed port numbers to use network byte order for consistency with other platforms.
Revision 1.11 2004/01/30 03:04:32 bradley
Updated for latest changes to mDNSWindows.
Revision 1.10 2003/10/31 12:18:31 bradley
Added display of the resolved host name. Show separate TXT record entries on separate lines.
Revision 1.9 2003/10/22 02:00:20 bradley
Fixed proxy IP setup to be in network byte order so it works on Mac and Windows.
Revision 1.8 2003/10/04 04:47:08 bradley
Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
Revision 1.7 2003/08/20 07:06:34 bradley
Update to APSL 2.0. Updated change history to match other mDNSResponder files.
Revision 1.6 2003/08/20 06:50:55 bradley
Updated to latest internal version of the mDNSCore code: Re-did everything to support
the latest DNSServices APIs (proxies, record updates, etc.); Added support for testing the platform
neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
*/
#if( defined( _MSC_VER ) )
#pragma warning( disable:4068 ) // Disable "unknown pragma" warning for "pragma unused".
#pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
#pragma warning( disable:4311 ) // Disable "type cast : pointer truncation from void *const to int".
// No stdint.h with Visual C++ so emulate it here.
typedef signed char int8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
typedef unsigned char uint8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
typedef signed short int16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
typedef unsigned short uint16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
typedef signed long int32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
typedef unsigned long uint32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
#else
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#if( __MACH__ )
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <CoreServices/CoreServices.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#endif
#include "DNSServices.h"
#include "DNSServiceDiscovery.h"
//===========================================================================================================================
// Macros
//===========================================================================================================================
#if( !TARGET_OS_MAC )
#define require_action_string( X, LABEL, ACTION, STR ) \
do \
{ \
if( !( X ) ) \
{ \
fprintf( stderr, "%s\n", ( STR ) ); \
{ ACTION; } \
goto LABEL; \
} \
} while( 0 )
#define require_string( X, LABEL, STR ) \
do \
{ \
if( !( X ) ) \
{ \
fprintf( stderr, "%s\n", ( STR ) ); \
goto LABEL; \
\
} \
} while( 0 )
#define require_noerr_string( ERR, LABEL, STR ) \
do \
{ \
if( ( ERR ) != 0 ) \
{ \
fprintf( stderr, "%s (%ld)\n", ( STR ), ( ERR ) ); \
goto LABEL; \
} \
} while( 0 )
#endif
//===========================================================================================================================
// Prototypes
//===========================================================================================================================
int main( int argc, char* argv[] );
static void Usage( void );
static int ProcessArgs( int argc, char* argv[] );
static DNSStatus ProcessPreset( int inPreset );
#if( __MACH__ )
static void SigIntHandler( int inSignalNumber );
#endif
#if( defined( WINVER ) )
static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
#endif
static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent );
static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent );
static void
RegistrationCallBack(
void * inContext,
DNSRegistrationRef inRef,
DNSStatus inStatusCode,
const DNSRegistrationEvent * inEvent );
static void
HostRegistrationCallBack(
void * inContext,
DNSHostRegistrationRef inRef,
DNSStatus inStatusCode,
void * inData );
static void
EmulatedBrowserCallBack(
DNSServiceBrowserReplyResultType inResult,
const char * inName,
const char * inType,
const char * inDomain,
DNSServiceDiscoveryReplyFlags inFlags,
void * inContext );
static void
EmulatedDomainEnumerationCallBack(
DNSServiceDomainEnumerationReplyResultType inResult,
const char * inDomain,
DNSServiceDiscoveryReplyFlags inFlags,
void * inContext );
static void
EmulatedResolverCallBack(
struct sockaddr * inInterfaceAddr,
struct sockaddr * inAddr,
const char * inTextRecord,
DNSServiceDiscoveryReplyFlags inFlags,
void * inContext );
static void EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext );
static char * IPv4ToString( DNSOpaque32 inIP, char *outString );
//===========================================================================================================================
// Globals
//===========================================================================================================================
#if( defined( WINVER ) )
static volatile int gQuit = 0;
#endif
static int gPrintTXTRecords = 1;
// Presets
typedef struct PresetData PresetData;
struct PresetData
{
int argc;
char * argv[ 16 ];
};
#if 0
#pragma mark == Presets ==
#endif
static const PresetData gPresets[] =
{
/* 01 */ { 2, { "DNSServiceTest", "-bbd" } },
/* 02 */ { 4, { "DNSServiceTest", "-bs", "_airport._tcp", "local." } },
/* 03 */ { 4, { "DNSServiceTest", "-bs", "_xserveraid._tcp", "local." } },
/* 04 */ { 3, { "DNSServiceTest", "-rdb", "apple.com" } },
/* 05 */ { 7, { "DNSServiceTest", "-rs", "My Fake AirPort", "_airport._tcp", "local.", "1234", "My Fake Info" } },
/* 06 */ { 7, { "DNSServiceTest", "-rs", "My Fake Xserve RAID", "_xserveraid._tcp", "local.", "1234", "My Fake Info" } },
/* 07 */ { 7, { "DNSServiceTest", "-rs", "My Fake Web Server", "_http._tcp", "local.", "8080", "index.html" } },
/* 08 */ { 9, { "DNSServiceTest", "-rps", "www.apple.com", "17.254.0.91", "Apple Web Server", "_http._tcp", "local.", "80", "index.html" } },
};
const int gPresetsCount = sizeof( gPresets ) / sizeof( gPresets[ 0 ] );
#if 0
#pragma mark -
#endif
//===========================================================================================================================
// main
//===========================================================================================================================
int main( int argc, char* argv[] )
{
DNSStatus err;
// Set up DNS Services and install a Console Control Handler to handle things like control-c signals.
err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
require_noerr_string( err, exit, "could not initialize DNSServiceTest" );
#if( __MACH__ )
signal( SIGINT, SigIntHandler );
#endif
#if( defined( WINVER ) )
SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
#endif
ProcessArgs( argc, argv );
exit:
DNSServicesFinalize();
return( err );
}
//===========================================================================================================================
// Usage
//===========================================================================================================================
static void Usage( void )
{
fprintf( stderr, "\n" );
fprintf( stderr, "DNSServiceTest - DNS-SD Test Tool 1.0d1\n" );
fprintf( stderr, "\n" );
fprintf( stderr, " -bbd 'b'rowse for 'b'rowsing 'd'omains\n" );
fprintf( stderr, " -brd 'b'rowse for 'r'egistration 'd'omains\n" );
fprintf( stderr, " -bs <type> <domain> 'b'rowse for 's'ervices\n" );
fprintf( stderr, " -lsi <name> <type> <domain> 'l'ookup 's'ervice 'i'nstance\n" );
fprintf( stderr, " -rdb[d] <domain> 'r'egister 'd'omain for 'b'rowsing ['d'efault]\n" );
fprintf( stderr, " -rdr[d] <domain> 'r'egister 'd'omain for 'r'egistration ['d'efault]\n" );
fprintf( stderr, " -rs <name> <type> <domain> <port> <txt> 'r'egister 's'ervice\n" );
fprintf( stderr, " -rps <host> <ip> <name> <type> <domain> <port> <txt> 'r'egister 'p'roxy 's'ervice\n" );
fprintf( stderr, " -rnss <name> <type> <domain> 'r'egister 'n'o 's'uch 's'ervice\n" );
fprintf( stderr, " -ebs <type> <domain> 'e'mulated 'b'rowse for 's'ervices\n" );
fprintf( stderr, " -ebd <registration/browse> 'e'mulated 'b'rowse for 'd'omains\n" );
fprintf( stderr, " -elsi <name> <type> <domain> 'e'mulated 'l'ookup 's'ervice 'i'nstance\n" );
fprintf( stderr, " -ers <name> <type> <domain> <port> <txt> 'e'mulated 'r'egister 's'ervice\n" );
fprintf( stderr, " -h[elp] 'h'elp\n" );
fprintf( stderr, "\n" );
fprintf( stderr, " -1 Preset 1 (browse for browsing domains) DNSServiceTest -bbd\n" );
fprintf( stderr, " -2 Preset 2 (browse for AirPort) DNSServiceTest -bs \"_airport._tcp\" \"local.\"\n" );
fprintf( stderr, " -3 Preset 3 (browse for Xserve RAID) DNSServiceTest -bs \"_xserveraid._tcp\" \"local.\"\n" );
fprintf( stderr, " -4 Preset 4 (register apple.com domain) DNSServiceTest -rdb \"apple.com\"\n" );
fprintf( stderr, " -5 Preset 5 (register fake AirPort) DNSServiceTest -rs \"My Fake AirPort\" \"_airport._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
fprintf( stderr, " -6 Preset 6 (register fake Xserve RAID) DNSServiceTest -rs \"My Fake Xserve RAID\" \"_xserveraid._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
fprintf( stderr, " -7 Preset 7 (register fake web server) DNSServiceTest -rs \"My Fake Web Server\" \"_http._tcp\" \"local.\" 8080 \"index.html\"\n" );
fprintf( stderr, "\n" );
}
//===========================================================================================================================
// ProcessArgs
//===========================================================================================================================
static int ProcessArgs( int argc, char* argv[] )
{
DNSStatus err;
int i;
const char * name;
const char * type;
const char * domain;
uint16_t port;
const char * text;
size_t textSize;
DNSBrowserRef browser;
DNSResolverFlags resolverFlags;
DNSDomainRegistrationType domainType;
const char * label;
const char * host;
const char * ip;
unsigned int b[ 4 ];
DNSNetworkAddress addr;
dns_service_discovery_ref emulatedRef;
// Parse the command line arguments (ignore first argument since it's just the program name).
require_action_string( argc >= 2, exit, err = kDNSBadParamErr, "no arguments specified" );
for( i = 1; i < argc; ++i )
{
if( strcmp( argv[ i ], "-bbd" ) == 0 )
{
// 'b'rowse for 'b'rowsing 'd'omains
fprintf( stdout, "browsing for browsing domains\n" );
err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
require_noerr_string( err, exit, "create browser failed" );
err = DNSBrowserStartDomainSearch( browser, 0 );
require_noerr_string( err, exit, "start domain search failed" );
}
else if( strcmp( argv[ i ], "-brd" ) == 0 )
{
// 'b'rowse for 'r'egistration 'd'omains
fprintf( stdout, "browsing for registration domains\n" );
err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
require_noerr_string( err, exit, "create browser failed" );
err = DNSBrowserStartDomainSearch( browser, kDNSBrowserFlagRegistrationDomainsOnly );
require_noerr_string( err, exit, "start domain search failed" );
}
else if( strcmp( argv[ i ], "-bs" ) == 0 )
{
// 'b'rowse for 's'ervices <type> <domain>
require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
type = argv[ i++ ];
domain = argv[ i ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "browsing for \"%s.%s\"\n", type, domain );
err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
require_noerr_string( err, exit, "create browser failed" );
err = DNSBrowserStartServiceSearch( browser, kDNSBrowserFlagAutoResolve, type, domain );
require_noerr_string( err, exit, "start service search failed" );
}
else if( strcmp( argv[ i ], "-lsi" ) == 0 )
{
// 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
name = argv[ i++ ];
type = argv[ i++ ];
domain = argv[ i ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "resolving \"%s.%s.%s\"\n", name, type, domain );
resolverFlags = kDNSResolverFlagOnlyIfUnique |
kDNSResolverFlagAutoReleaseByName;
err = DNSResolverCreate( resolverFlags, name, type, domain, ResolverCallBack, 0, NULL, NULL );
require_noerr_string( err, exit, "create resolver failed" );
}
else if( ( strcmp( argv[ i ], "-rdb" ) == 0 ) || ( strcmp( argv[ i ], "-rdbd" ) == 0 ) )
{
// 'r'egister 'd'omain for 'b'rowsing ['d'efault] <domain>
require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
if( strcmp( argv[ i ], "-rdb" ) == 0 )
{
domainType = kDNSDomainRegistrationTypeBrowse;
label = "";
}
else
{
domainType = kDNSDomainRegistrationTypeBrowseDefault;
label = "default ";
}
++i;
domain = argv[ i ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "registering \"%s\" as %sbrowse domain\n", domain, label );
err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
require_noerr_string( err, exit, "create domain registration failed" );
}
else if( ( strcmp( argv[ i ], "-rdr" ) == 0 ) || ( strcmp( argv[ i ], "-rdrd" ) == 0 ) )
{
// 'r'egister 'd'omain for 'r'egistration ['d'efault] <domain>
require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
if( strcmp( argv[ i ], "-rdr" ) == 0 )
{
domainType = kDNSDomainRegistrationTypeRegistration;
label = "";
}
else
{
domainType = kDNSDomainRegistrationTypeRegistrationDefault;
label = "default ";
}
++i;
domain = argv[ i ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "registering \"%s\" as %sregistration domain\n", domain, label );
err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
require_noerr_string( err, exit, "create domain registration failed" );
}
else if( strcmp( argv[ i ], "-rs" ) == 0 )
{
// 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
name = argv[ i++ ];
type = argv[ i++ ];
domain = argv[ i++ ];
port = (uint16_t) atoi( argv[ i++ ] );
text = argv[ i ];
textSize = strlen( text );
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, NULL, NULL,
RegistrationCallBack, NULL, NULL );
require_noerr_string( err, exit, "create registration failed" );
}
else if( strcmp( argv[ i ], "-rps" ) == 0 )
{
DNSHostRegistrationFlags hostFlags;
// 'r'egister 'p'roxy 's'ervice <host> <ip> <name> <type> <domain> <port> <txt>
require_action_string( argc > ( i + 7 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
host = argv[ i++ ];
ip = argv[ i++ ];
name = argv[ i++ ];
type = argv[ i++ ];
domain = argv[ i++ ];
port = (uint16_t) atoi( argv[ i++ ] );
text = argv[ i ];
textSize = strlen( text );
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
sscanf( ip, "%u.%u.%u.%u", &b[ 0 ], &b[ 1 ], &b[ 2 ], &b[ 3 ] );
addr.addressType = kDNSNetworkAddressTypeIPv4;
addr.u.ipv4.addr.v8[ 0 ] = (DNSUInt8) b[ 0 ];
addr.u.ipv4.addr.v8[ 1 ] = (DNSUInt8) b[ 1 ];
addr.u.ipv4.addr.v8[ 2 ] = (DNSUInt8) b[ 2 ];
addr.u.ipv4.addr.v8[ 3 ] = (DNSUInt8) b[ 3 ];
fprintf( stdout, "registering proxy service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
hostFlags = kDNSHostRegistrationFlagOnlyIfNotFound | kDNSHostRegistrationFlagAutoRenameOnConflict;
err = DNSHostRegistrationCreate( hostFlags, host, domain, &addr, NULL,
HostRegistrationCallBack, NULL, NULL );
require_noerr_string( err, exit, "create host registration failed" );
err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, host, NULL,
RegistrationCallBack, NULL, NULL );
require_noerr_string( err, exit, "create registration failed" );
}
else if( strcmp( argv[ i ], "-rnss" ) == 0 )
{
// 'r'egister 'n'o 's'uch 's'ervice <name> <type> <domain>
require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
name = argv[ i++ ];
type = argv[ i++ ];
domain = argv[ i++ ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "registering no-such-service \"%s.%s.%s\"\n", name, type, domain );
err = DNSNoSuchServiceRegistrationCreate( 0, name, type, domain, NULL, RegistrationCallBack, NULL, NULL );
require_noerr_string( err, exit, "create no-such-service registration failed" );
}
else if( strcmp( argv[ i ], "-ebs" ) == 0 )
{
// 'e'mulated 'b'rowse for 's'ervices <type> <domain>
require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
type = argv[ i++ ];
domain = argv[ i ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "emulated browsing for \"%s.%s\"\n", type, domain );
emulatedRef = DNSServiceBrowserCreate( type, domain, EmulatedBrowserCallBack, NULL );
require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated browser failed" );
}
else if( strcmp( argv[ i ], "-ebd" ) == 0 )
{
int registrationOnly;
// 'e'mulated 'b'rowse for 'd'omains <registration/browse>
require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
type = argv[ i++ ];
if( strcmp( type, "registration" ) == 0 )
{
registrationOnly = 1;
}
else if( strcmp( type, "browse" ) == 0 )
{
registrationOnly = 0;
}
else
{
require_action_string( 0, exit, err = kDNSBadParamErr, "invalid browse type" );
}
fprintf( stdout, "emulated browsing for %s domains\n", type );
emulatedRef = DNSServiceDomainEnumerationCreate( registrationOnly, EmulatedDomainEnumerationCallBack, NULL );
require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated domain browser failed" );
}
else if( strcmp( argv[ i ], "-elsi" ) == 0 )
{
// 'e'mulated 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
name = argv[ i++ ];
type = argv[ i++ ];
domain = argv[ i ];
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "emulated resolving \"%s.%s.%s\"\n", name, type, domain );
emulatedRef = DNSServiceResolverResolve( name, type, domain, EmulatedResolverCallBack, NULL );
require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated resolver failed" );
}
else if( strcmp( argv[ i ], "-ers" ) == 0 )
{
// 'e'mulated 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
++i;
name = argv[ i++ ];
type = argv[ i++ ];
domain = argv[ i++ ];
port = (uint16_t) atoi( argv[ i++ ] );
text = argv[ i ];
textSize = strlen( text );
if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
{
domain = "local.";
}
fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
emulatedRef = DNSServiceRegistrationCreate( name, type, domain, htons( port ), text,
EmulatedRegistrationCallBack, NULL );
require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated registration failed" );
}
else if( ( argv[ i ][ 0 ] == '-' ) && isdigit( argv[ i ][ 1 ] ) )
{
// Preset
ProcessPreset( atoi( &argv[ i ][ 1 ] ) );
err = 0;
goto exit;
}
else if( strcmp( argv[ i ], "-q" ) == 0 )
{
// Quiet (no text records)
gPrintTXTRecords = 0;
}
else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || ( strcmp( argv[ i ], "-h" ) == 0 ) )
{
// Help
Usage();
err = 0;
goto exit;
}
else
{
// Unknown parameter.
require_action_string( 0, exit, err = kDNSBadParamErr, "unknown parameter" );
goto exit;
}
}
// Run until control-C'd.
#if( __MACH__ )
CFRunLoopRun();
#endif
#if( defined( WINVER ) )
while( !gQuit )
{
Sleep( 200 );
}
#endif
err = kDNSNoErr;
exit:
if( err )
{
Usage();
}
return( err );
}
//===========================================================================================================================
// ProcessPreset
//===========================================================================================================================
static DNSStatus ProcessPreset( int inPreset )
{
DNSStatus err;
require_action_string( ( inPreset > 0 ) && ( inPreset <= gPresetsCount ), exit, err = kDNSBadParamErr, "invalid preset" );
err = ProcessArgs( gPresets[ inPreset - 1 ].argc, (char **) gPresets[ inPreset - 1 ].argv );
exit:
return( err );
}
#if( __MACH__ )
//===========================================================================================================================
// SigIntHandler
//===========================================================================================================================
static void SigIntHandler( int inSignalNumber )
{
DNS_UNUSED( inSignalNumber );
signal( SIGINT, SIG_DFL );
CFRunLoopStop( CFRunLoopGetCurrent() );
}
#endif
#if( defined( WINVER ) )
//===========================================================================================================================
// ConsoleControlHandler
//===========================================================================================================================
static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
{
BOOL handled;
handled = 0;
switch( inControlEvent )
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
gQuit = 1;
handled = 1;
break;
default:
break;
}
return( handled );
}
#endif
//===========================================================================================================================
// BrowserCallBack
//===========================================================================================================================
static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent )
{
char ifIP[ 32 ];
char ip[ 32 ];
DNS_UNUSED( inContext );
DNS_UNUSED( inRef );
DNS_UNUSED( inStatusCode );
switch( inEvent->type )
{
case kDNSBrowserEventTypeRelease:
break;
case kDNSBrowserEventTypeAddDomain:
fprintf( stdout, "domain \"%s\" added on interface 0x%p (%s)\n",
inEvent->data.addDomain.domain,
(int) inEvent->data.addDomain.interfaceID,
IPv4ToString( inEvent->data.addDomain.interfaceIP.u.ipv4.addr, ifIP ) );
break;
case kDNSBrowserEventTypeAddDefaultDomain:
fprintf( stdout, "default domain \"%s\" added on interface 0x%p (%s)\n",
inEvent->data.addDefaultDomain.domain,
(int) inEvent->data.addDefaultDomain.interfaceID,
IPv4ToString( inEvent->data.addDefaultDomain.interfaceIP.u.ipv4.addr, ifIP ) );
break;
case kDNSBrowserEventTypeRemoveDomain:
fprintf( stdout, "domain \"%s\" removed on interface 0x%p (%s)\n",
inEvent->data.removeDomain.domain,
(int) inEvent->data.removeDomain.interfaceID,
IPv4ToString( inEvent->data.removeDomain.interfaceIP.u.ipv4.addr, ifIP ) );
break;
case kDNSBrowserEventTypeAddService:
fprintf( stdout, "service \"%s.%s%s\" added on interface 0x%p (%s)\n",
inEvent->data.addService.name,
inEvent->data.addService.type,
inEvent->data.addService.domain,
(int) inEvent->data.addService.interfaceID,
IPv4ToString( inEvent->data.addService.interfaceIP.u.ipv4.addr, ifIP ) );
break;
case kDNSBrowserEventTypeRemoveService:
fprintf( stdout, "service \"%s.%s%s\" removed on interface 0x%p (%s)\n",
inEvent->data.removeService.name,
inEvent->data.removeService.type,
inEvent->data.removeService.domain,
(int) inEvent->data.removeService.interfaceID,
IPv4ToString( inEvent->data.removeService.interfaceIP.u.ipv4.addr, ifIP ) );
break;
case kDNSBrowserEventTypeResolved:
{
const uint8_t * p;
const uint8_t * end;
int i;
fprintf( stdout, "resolved \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n",
inEvent->data.resolved->name,
inEvent->data.resolved->type,
inEvent->data.resolved->domain,
inEvent->data.resolved->hostName,
IPv4ToString( inEvent->data.resolved->address.u.ipv4.addr, ip ),
( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) |
inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ],
(int) inEvent->data.resolved->interfaceID,
IPv4ToString( inEvent->data.resolved->interfaceIP.u.ipv4.addr, ifIP ),
( inEvent->data.resolved->textRecordRawSize > 0 ) ? " with text:" : "" );
p = (const uint8_t *) inEvent->data.resolved->textRecordRaw;
end = p + inEvent->data.resolved->textRecordRawSize;
i = 0;
if( gPrintTXTRecords )
{
while( p < end )
{
uint8_t size;
size = *p++;
if( ( p + size ) > end )
{
fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
break;
}
fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
p += size;
++i;
}
fprintf( stdout, "\n" );
}
break;
}
default:
break;
}
}
//===========================================================================================================================
// ResolverCallBack
//===========================================================================================================================
static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent )
{
char ifIP[ 32 ];
char ip[ 32 ];
DNS_UNUSED( inContext );
DNS_UNUSED( inRef );
DNS_UNUSED( inStatusCode );
switch( inEvent->type )
{
case kDNSResolverEventTypeResolved:
{
const uint8_t * p;
const uint8_t * end;
int i;
fprintf( stdout, "resolved \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%p (%s)%s\n",
inEvent->data.resolved.name,
inEvent->data.resolved.type,
inEvent->data.resolved.domain,
inEvent->data.resolved.hostName,
IPv4ToString( inEvent->data.resolved.address.u.ipv4.addr, ip ),
( inEvent->data.resolved.address.u.ipv4.port.v8[ 0 ] << 8 ) |
inEvent->data.resolved.address.u.ipv4.port.v8[ 1 ],
(int) inEvent->data.resolved.interfaceID,
IPv4ToString( inEvent->data.resolved.interfaceIP.u.ipv4.addr, ifIP ),
( inEvent->data.resolved.textRecordRawSize > 0 ) ? " with text:" : "" );
p = (const uint8_t *) inEvent->data.resolved.textRecordRaw;
end = p + inEvent->data.resolved.textRecordRawSize;
i = 0;
if( gPrintTXTRecords )
{
while( p < end )
{
uint8_t size;
size = *p++;
if( ( p + size ) > end )
{
fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
break;
}
fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
p += size;
++i;
}
fprintf( stdout, "\n" );
}
break;
}
case kDNSResolverEventTypeRelease:
break;
default:
break;
}
}
//===========================================================================================================================
// RegistrationCallBack
//===========================================================================================================================
static void
RegistrationCallBack(
void * inContext,
DNSRegistrationRef inRef,
DNSStatus inStatusCode,
const DNSRegistrationEvent * inEvent )
{
DNS_UNUSED( inContext );
DNS_UNUSED( inRef );
DNS_UNUSED( inStatusCode );
switch( inEvent->type )
{
case kDNSRegistrationEventTypeRelease:
break;
case kDNSRegistrationEventTypeRegistered:
fprintf( stdout, "name registered and active\n" );
break;
case kDNSRegistrationEventTypeNameCollision:
fprintf( stdout, "name in use, please choose another name\n" );
break;
default:
break;
}
}
//===========================================================================================================================
// HostRegistrationCallBack
//===========================================================================================================================
static void
HostRegistrationCallBack(
void * inContext,
DNSHostRegistrationRef inRef,
DNSStatus inStatusCode,
void * inData )
{
DNS_UNUSED( inContext );
DNS_UNUSED( inRef );
DNS_UNUSED( inData );
if( inStatusCode == kDNSNoErr )
{
fprintf( stdout, "host name registered and active\n" );
}
else if( inStatusCode == kDNSNameConflictErr )
{
fprintf( stdout, "host name in use, please choose another name\n" );
}
else
{
fprintf( stdout, "unknown host registration status (%ld)\n", inStatusCode );
}
}
//===========================================================================================================================
// EmulatedBrowserCallBack
//===========================================================================================================================
static void
EmulatedBrowserCallBack(
DNSServiceBrowserReplyResultType inResult,
const char * inName,
const char * inType,
const char * inDomain,
DNSServiceDiscoveryReplyFlags inFlags,
void * inContext )
{
DNS_UNUSED( inFlags );
DNS_UNUSED( inContext );
if( inResult == DNSServiceBrowserReplyAddInstance )
{
fprintf( stdout, "\"%s.%s%s\" service added emulated\n", inName, inType, inDomain );
}
else if( inResult == DNSServiceBrowserReplyRemoveInstance )
{
fprintf( stdout, "\"%s.%s%s\" service removed emulated\n", inName, inType, inDomain );
}
else
{
fprintf( stdout, "### unknown emulated browser callback result (%d)\n", inResult );
}
}
//===========================================================================================================================
// EmulatedDomainEnumerationCallBack
//===========================================================================================================================
static void
EmulatedDomainEnumerationCallBack(
DNSServiceDomainEnumerationReplyResultType inResult,
const char * inDomain,
DNSServiceDiscoveryReplyFlags inFlags,
void * inContext )
{
DNS_UNUSED( inFlags );
DNS_UNUSED( inContext );
if( inResult == DNSServiceDomainEnumerationReplyAddDomain )
{
fprintf( stdout, "\"%s\" domain added emulated\n", inDomain );
}
else if( inResult == DNSServiceDomainEnumerationReplyAddDomainDefault )
{
fprintf( stdout, "\"%s\" default domain added emulated\n", inDomain );
}
else if( inResult == DNSServiceDomainEnumerationReplyRemoveDomain )
{
fprintf( stdout, "\"%s\" domain removed emulated\n", inDomain );
}
else
{
fprintf( stdout, "### unknown emulated domain enumeration callback result (%d)\n", inResult );
}
}
//===========================================================================================================================
// EmulatedResolverCallBack
//===========================================================================================================================
static void
EmulatedResolverCallBack(
struct sockaddr * inInterfaceAddr,
struct sockaddr * inAddr,
const char * inTextRecord,
DNSServiceDiscoveryReplyFlags inFlags,
void * inContext )
{
struct sockaddr_in * ifSin4;
struct sockaddr_in * sin4;
char ifIP[ 64 ];
char ip[ 64 ];
DNS_UNUSED( inFlags );
DNS_UNUSED( inContext );
ifSin4 = (struct sockaddr_in *) inInterfaceAddr;
sin4 = (struct sockaddr_in *) inAddr;
fprintf( stdout, "service resolved to %s:%d on interface %s with text \"%s\"\n",
IPv4ToString( *( (DNSOpaque32 *) &sin4->sin_addr.s_addr ), ip ),
ntohs( sin4->sin_port ),
IPv4ToString( *( (DNSOpaque32 *) &ifSin4->sin_addr.s_addr ), ifIP ),
inTextRecord ? inTextRecord : "" );
}
//===========================================================================================================================
// EmulatedResolverCallBack
//===========================================================================================================================
static void EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext )
{
DNS_UNUSED( inContext );
if( inResult == kDNSServiceDiscoveryNoError )
{
fprintf( stdout, "service name registered successfully\n" );
}
else
{
fprintf( stdout, "service registration failed( %d)\n", inResult );
}
}
//===========================================================================================================================
// IPv4ToString
//===========================================================================================================================
static char * IPv4ToString( DNSOpaque32 inIP, char *outString )
{
sprintf( outString, "%u.%u.%u.%u", inIP.v8[ 0 ], inIP.v8[ 1 ], inIP.v8[ 2 ], inIP.v8[ 3 ] );
return( outString );
}
syntax highlighted by Code2HTML, v. 0.9.1