2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
26 Revision 1.2 2004/07/13 21:24:28 rpantos
27 Fix for <rdar://problem/3701120>.
29 Revision 1.1 2004/06/18 04:17:43 rpantos
32 Revision 1.3 2004/04/09 21:03:15 bradley
33 Changed port numbers to use network byte order for consistency with other platforms.
35 Revision 1.2 2004/04/08 09:43:43 bradley
36 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
38 Revision 1.1 2004/01/30 02:58:57 bradley
39 Test tool for the mDNSResponder Windows service.
46 #include "CommonServices.h"
47 #include "DebugServices.h"
50 //===========================================================================================================================
52 //===========================================================================================================================
54 #define MAX_DOMAIN_LABEL 63
55 #define MAX_DOMAIN_NAME 255
57 typedef union { unsigned char b
[2]; unsigned short NotAnInteger
; } Opaque16
;
59 typedef struct { u_char c
[ 64]; } domainlabel
;
60 typedef struct { u_char c
[256]; } domainname
;
70 //===========================================================================================================================
72 //===========================================================================================================================
74 int main( int argc
, char* argv
[] );
75 static void Usage( void );
76 static int ProcessArgs( int argc
, char* argv
[] );
78 #if( defined( WINVER ) )
79 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
82 static void CALLBACK_COMPAT
83 EnumerateDomainsCallBack(
85 DNSServiceFlags inFlags
,
86 uint32_t inInterfaceIndex
,
87 DNSServiceErrorType inErrorCode
,
88 const char * inDomain
,
91 static void CALLBACK_COMPAT
94 DNSServiceFlags inFlags
,
95 uint32_t inInterfaceIndex
,
96 DNSServiceErrorType inErrorCode
,
99 const char * inDomain
,
102 static void CALLBACK_COMPAT
105 DNSServiceFlags inFlags
,
106 uint32_t inInterfaceIndex
,
107 DNSServiceErrorType inErrorCode
,
108 const char * inFullName
,
109 const char * inHostName
,
115 static void CALLBACK_COMPAT
118 DNSServiceFlags inFlags
,
119 DNSServiceErrorType inErrorCode
,
122 const char * inDomain
,
125 static void CALLBACK_COMPAT
128 DNSRecordRef inRecordRef
,
129 DNSServiceFlags inFlags
,
130 DNSServiceErrorType inErrorCode
,
133 static void CALLBACK_COMPAT
135 const DNSServiceRef inRef
,
136 const DNSServiceFlags inFlags
,
137 const uint32_t inInterfaceIndex
,
138 const DNSServiceErrorType inErrorCode
,
140 const uint16_t inRRType
,
141 const uint16_t inRRClass
,
142 const uint16_t inRDataSize
,
143 const void * inRData
,
144 const uint32_t inTTL
,
147 static void PrintRData( uint16_t inRRType
, size_t inRDataSize
, const uint8_t *inRData
);
149 static char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
);
150 static char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
);
152 //===========================================================================================================================
154 //===========================================================================================================================
156 #if( defined( WINVER ) )
157 static volatile int gQuit
= 0;
160 //===========================================================================================================================
162 //===========================================================================================================================
164 int main( int argc
, char *argv
[] )
168 debug_initialize( kDebugOutputTypeMetaConsole
);
169 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelTrace
);
171 SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
172 err
= ProcessArgs( argc
, argv
);
176 //===========================================================================================================================
178 //===========================================================================================================================
180 static void Usage( void )
182 fprintf( stderr
, "\n" );
183 fprintf( stderr
, "DNSServiceTest 1.0d1\n" );
184 fprintf( stderr
, "\n" );
185 fprintf( stderr
, " -server <IP> Set Remote Server\n" );
186 fprintf( stderr
, " -cv Check Version\n" );
187 fprintf( stderr
, " -bd Browse for Browse Domains\n" );
188 fprintf( stderr
, " -bs <type> <domain> Browse for Services\n" );
189 fprintf( stderr
, " -rsi <name> <type> <domain> Resolve Service Instance\n" );
190 fprintf( stderr
, " -rs <name> <type> <domain> <host> <port> <txt> Register Service\n" );
191 fprintf( stderr
, " -rr Register Records\n" );
192 fprintf( stderr
, " -qr <name> <type> <domain> <rrType> Query Record\n" );
193 fprintf( stderr
, " -cr <name> <type> <domain> <rrType> Reconfirm Record\n" );
194 fprintf( stderr
, " -cp <code> Copy Property\n" );
195 fprintf( stderr
, " -h[elp] Help\n" );
196 fprintf( stderr
, "\n" );
199 DEBUG_LOCAL DNSServiceRef gRef
= NULL
;
200 DEBUG_LOCAL DNSRecordRef gRecordRef
= NULL
;
201 DEBUG_LOCAL
const char * gServer
= NULL
;
203 //===========================================================================================================================
205 //===========================================================================================================================
207 static int ProcessArgs( int argc
, char* argv
[] )
218 uint8_t txtStorage
[ 256 ];
221 DNSRecordRef records
[ 10 ];
222 char fullName
[ kDNSServiceMaxDomainName
];
225 err
= DNSServiceInitialize( kDNSServiceInitializeFlagsNoServerCheck
, 0 );
226 require_noerr( err
, exit
);
228 // Parse the command line arguments (ignore first argument since it's just the program name).
236 for( i
= 1; i
< argc
; ++i
)
238 if( strcmp( argv
[ i
], "-server" ) == 0 )
240 require_action( argc
> ( i
+ 1 ), exit
, err
= kParamErr
);
241 gServer
= argv
[ ++i
];
243 printf( "Server set to \"%s\"\n", gServer
);
245 else if( strcmp( argv
[ i
], "-cv" ) == 0 )
249 err
= DNSServiceCheckVersion();
250 printf( "CheckVersion: %ld\n", err
);
254 else if( strcmp( argv
[ i
], "-bd" ) == 0 )
256 err
= DNSServiceEnumerateDomains( &gRef
, kDNSServiceFlagsBrowseDomains
, 0,
257 EnumerateDomainsCallBack
, NULL
);
258 require_noerr( err
, exit
);
260 else if( strcmp( argv
[ i
], "-bs" ) == 0 )
262 // Browse service <type> <domain>
264 if( argc
> ( i
+ 2 ) )
267 domain
= argv
[ ++i
];
274 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
279 err
= DNSServiceBrowse( &gRef
, 0, 0, type
, domain
, BrowseCallBack
, NULL
);
280 require_noerr( err
, exit
);
282 else if( strcmp( argv
[ i
], "-rsi" ) == 0 )
284 // Resolve Service Instance <name> <type> <domain>
286 if( argc
> ( i
+ 3 ) )
290 domain
= argv
[ ++i
];
294 name
= "test service";
298 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
303 err
= DNSServiceResolve( &gRef
, 0, 0, name
, type
, domain
, ResolveCallBack
, NULL
);
304 require_noerr( err
, exit
);
306 else if( strcmp( argv
[ i
], "-rs" ) == 0 )
308 // Register Service <name> <type> <domain> <host> <port> <txt>
310 if( argc
> ( i
+ 6 ) )
314 domain
= argv
[ ++i
];
316 port
= (uint16_t) atoi( argv
[ ++i
] );
321 name
= "test service";
326 txt
= "My TXT Record";
330 txtStorage
[ 0 ] = (uint8_t) strlen( txt
);
331 memcpy( &txtStorage
[ 1 ], txt
, txtStorage
[ 0 ] );
332 txtSize
= (uint16_t)( 1 + txtStorage
[ 0 ] );
333 txt
= (const char *) txtStorage
;
340 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
345 err
= DNSServiceRegister( &gRef
, 0, 0, name
, type
, domain
, host
, htons( port
), txtSize
, txt
,
346 RegisterCallBack
, NULL
);
347 require_noerr( err
, exit
);
349 #if( TEST_SERVICE_RECORDS )
351 err
= DNSServiceAddRecord( gRef
, &gRecordRef
, 0, kDNSServiceDNSType_A
, kDNSServiceDNSClass_IN
, &ipv4
, 60 );
352 require_noerr( err
, exit
);
357 err
= DNSServiceUpdateRecord( gRef
, gRecordRef
, 0, 4, &ipv4
, 60 );
358 require_noerr( err
, exit
);
362 err
= DNSServiceRemoveRecord( gRef
, gRecordRef
, 0 );
363 require_noerr( err
, exit
);
369 else if( strcmp( argv
[ i
], "-rr" ) == 0 )
373 err
= DNSServiceCreateConnection( &gRef
);
374 require_noerr( err
, exit
);
376 printf( "registering 10 address records...\n" );
378 for( i
= 0; i
< 10; ++i
)
380 sprintf( s
, "testhost-%d.local.", i
);
382 err
= DNSServiceRegisterRecord( gRef
, &records
[ i
], kDNSServiceFlagsUnique
, 0, s
,
383 kDNSServiceDNSType_A
, kDNSServiceDNSClass_IN
, 4, &ipv4
, 60, RecordCallBack
, NULL
);
388 printf( "deregistering half of the records\n" );
389 for( i
= 0; i
< 10; ++i
)
393 err
= DNSServiceRemoveRecord( gRef
, records
[ i
], 0 );
400 printf( "updating the remaining records\n" );
401 for( i
= 0; i
< 10; ++i
)
406 err
= DNSServiceUpdateRecord( gRef
, records
[ i
], 0, 4, &ipv4
, 60 );
412 printf( "deregistering all remaining records\n" );
413 DNSServiceRefDeallocate( gRef
);
417 else if( strcmp( argv
[ i
], "-qr" ) == 0 )
419 // Query Record <name> <type> <domain> <rrType>
421 if( argc
> ( i
+ 4 ) )
425 domain
= argv
[ ++i
];
426 rrType
= (uint16_t) atoi( argv
[ ++i
] );
433 rrType
= 1; // Address
435 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
439 err
= DNSServiceConstructFullName( fullName
, name
, type
, domain
);
440 require_noerr( err
, exit
);
442 printf( "resolving fullname %s type %d\n", fullName
, rrType
);
443 err
= DNSServiceQueryRecord( &gRef
, 0, 0, fullName
, rrType
, kDNSServiceDNSClass_IN
, QueryCallBack
, NULL
);
444 require_noerr( err
, exit
);
446 else if( strcmp( argv
[ i
], "-cr" ) == 0 )
448 // Reconfirm Record <name> <type> <domain> <rrType>
450 if( argc
> ( i
+ 4 ) )
454 domain
= argv
[ ++i
];
455 rrType
= (uint16_t) atoi( argv
[ ++i
] );
462 rrType
= 1; // Address
464 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
468 err
= DNSServiceConstructFullName( fullName
, name
, type
, domain
);
469 require_noerr( err
, exit
);
471 printf( "reconfirming record fullname %s type %d\n", fullName
, rrType
);
473 DNSServiceReconfirmRecord( 0, 0, fullName
, rrType
, kDNSServiceDNSClass_IN
, 4, &ipv4
);
475 else if( strcmp( argv
[ i
], "-cp" ) == 0 )
477 DNSPropertyCode code
;
478 DNSPropertyData data
;
480 // Copy Property <code>
482 if( argc
> ( i
+ 1 ) )
485 require_action( strlen( name
) == 4, exit
, err
= kParamErr
);
487 code
= (DNSPropertyCode
)( name
[ 0 ] << 24 );
488 code
|= (DNSPropertyCode
)( name
[ 1 ] << 16 );
489 code
|= (DNSPropertyCode
)( name
[ 2 ] << 8 );
490 code
|= (DNSPropertyCode
) name
[ 3 ];
494 code
= kDNSPropertyCodeVersion
;
498 err
= DNSServiceCopyProperty( code
, &data
);
499 require_noerr( err
, exit
);
501 printf( "'%s' property:\n", name
);
502 if( code
== kDNSPropertyCodeVersion
)
504 printf( " clientCurrentVersion: 0x%08X\n", data
.u
.version
.clientCurrentVersion
);
505 printf( " clientOldestServerVersion: 0x%08X\n", data
.u
.version
.clientOldestServerVersion
);
506 printf( " serverCurrentVersion: 0x%08X\n", data
.u
.version
.serverCurrentVersion
);
507 printf( " serverOldestClientVersion: 0x%08X\n", data
.u
.version
.serverOldestClientVersion
);
510 else if( ( strcmp( argv
[ i
], "-help" ) == 0 ) || ( strcmp( argv
[ i
], "-h" ) == 0 ) )
520 // Unknown parameter.
522 dlog( kDebugLevelError
, "unknown parameter (%s)\n", argv
[ i
] );
528 // Run until control-C'd.
537 DNSServiceFinalize();
545 //===========================================================================================================================
546 // ConsoleControlHandler
547 //===========================================================================================================================
549 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
554 switch( inControlEvent
)
557 case CTRL_BREAK_EVENT
:
558 case CTRL_CLOSE_EVENT
:
559 case CTRL_LOGOFF_EVENT
:
560 case CTRL_SHUTDOWN_EVENT
:
571 //===========================================================================================================================
572 // EnumerateDomainsCallBack
573 //===========================================================================================================================
575 static void CALLBACK_COMPAT
576 EnumerateDomainsCallBack(
578 DNSServiceFlags inFlags
,
579 uint32_t inInterfaceIndex
,
580 DNSServiceErrorType inErrorCode
,
581 const char * inDomain
,
584 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
585 printf( "inFlags: 0x%08X\n", (int) inFlags
);
586 printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex
);
587 printf( "inErrorCode: %ld\n", inErrorCode
);
588 printf( "inDomain: \"%s\"\n", inDomain
? inDomain
: "<null>" );
589 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
593 //===========================================================================================================================
595 //===========================================================================================================================
597 static void CALLBACK_COMPAT
600 DNSServiceFlags inFlags
,
601 uint32_t inInterfaceIndex
,
602 DNSServiceErrorType inErrorCode
,
605 const char * inDomain
,
608 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
609 printf( "inFlags: 0x%08X\n", (int) inFlags
);
610 printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex
);
611 printf( "inErrorCode: %ld\n", inErrorCode
);
612 printf( "inName: \"%s\"\n", inName
? inName
: "<null>" );
613 printf( "inType: \"%s\"\n", inType
? inType
: "<null>" );
614 printf( "inDomain: \"%s\"\n", inDomain
? inDomain
: "<null>" );
615 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
619 //===========================================================================================================================
621 //===========================================================================================================================
623 static void CALLBACK_COMPAT
626 DNSServiceFlags inFlags
,
627 uint32_t inInterfaceIndex
,
628 DNSServiceErrorType inErrorCode
,
629 const char * inFullName
,
630 const char * inHostName
,
636 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
637 printf( "inFlags: 0x%08X\n", (int) inFlags
);
638 printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex
);
639 printf( "inErrorCode: %ld\n", inErrorCode
);
640 printf( "inFullName: \"%s\"\n", inFullName
? inFullName
: "<null>" );
641 printf( "inHostName: \"%s\"\n", inHostName
? inHostName
: "<null>" );
642 printf( "inPort: %d\n", ntohs( inPort
) );
643 printf( "inTXTSize: %ld\n", inTXTSize
);
644 printf( "inTXT: 0x%08X\n", (uintptr_t) inTXT
);
645 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
649 //===========================================================================================================================
651 //===========================================================================================================================
653 static void CALLBACK_COMPAT
656 DNSServiceFlags inFlags
,
657 DNSServiceErrorType inErrorCode
,
660 const char * inDomain
,
663 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
664 printf( "inFlags: 0x%08X\n", (int) inFlags
);
665 printf( "inErrorCode: %ld\n", inErrorCode
);
666 printf( "inName: \"%s\"\n", inName
? inName
: "<null>" );
667 printf( "inType: \"%s\"\n", inType
? inType
: "<null>" );
668 printf( "inDomain: \"%s\"\n", inDomain
? inDomain
: "<null>" );
669 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
673 //===========================================================================================================================
675 //===========================================================================================================================
677 static void CALLBACK_COMPAT
680 DNSRecordRef inRecordRef
,
681 DNSServiceFlags inFlags
,
682 DNSServiceErrorType inErrorCode
,
685 DEBUG_UNUSED( inRef
);
686 DEBUG_UNUSED( inRecordRef
);
687 DEBUG_UNUSED( inFlags
);
688 DEBUG_UNUSED( inContext
);
690 if( inErrorCode
== kDNSServiceErr_NoError
)
692 printf( "RecordCallBack: no errors\n" );
696 printf( "RecordCallBack: %ld error\n", inErrorCode
);
700 //===========================================================================================================================
702 //===========================================================================================================================
704 static void CALLBACK_COMPAT
706 const DNSServiceRef inRef
,
707 const DNSServiceFlags inFlags
,
708 const uint32_t inInterfaceIndex
,
709 const DNSServiceErrorType inErrorCode
,
711 const uint16_t inRRType
,
712 const uint16_t inRRClass
,
713 const uint16_t inRDataSize
,
714 const void * inRData
,
715 const uint32_t inTTL
,
718 DEBUG_UNUSED( inRef
);
719 DEBUG_UNUSED( inRRClass
);
720 DEBUG_UNUSED( inTTL
);
721 DEBUG_UNUSED( inContext
);
723 if( inErrorCode
== kDNSServiceErr_NoError
)
725 if( inFlags
& kDNSServiceFlagsAdd
)
733 if( inFlags
& kDNSServiceFlagsMoreComing
)
741 printf(" 0x%04X %d %s rdata ", inFlags
, inInterfaceIndex
, inName
);
742 PrintRData( inRRType
, (size_t) inRDataSize
, (const uint8_t *) inRData
);
746 printf( "QueryCallback: %ld error\n", inErrorCode
);
750 //===========================================================================================================================
752 //===========================================================================================================================
754 static void PrintRData( uint16_t inRRType
, size_t inRDataSize
, const uint8_t *inRData
)
763 case kDNSServiceDNSType_TXT
:
765 // Print all the alphanumeric and punctuation characters
767 for( i
= 0; i
< inRDataSize
; ++i
)
769 if( ( inRData
[ i
] >= 32 ) && ( inRData
[ i
] <= 127 ) )
771 printf( "%c", inRData
[ i
] );
777 case kDNSServiceDNSType_SRV
:
778 srv
= (srv_rdata
*)inRData
;
779 ConvertDomainNameToCString_withescape(&srv
->target
, s
, 0);
780 printf("pri=%d, w=%d, port=%d, target=%s\n", srv
->priority
, srv
->weight
, srv
->port
, s
);
783 case kDNSServiceDNSType_A
:
784 check( inRDataSize
== 4 );
785 memcpy( &in
, inRData
, sizeof( in
) );
786 printf( "%s\n", inet_ntoa( in
) );
789 case kDNSServiceDNSType_PTR
:
790 ConvertDomainNameToCString_withescape( (domainname
*) inRData
, s
, 0 );
793 case kDNSServiceDNSType_AAAA
:
794 check( inRDataSize
== 16 );
795 printf( "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X\n",
796 inRData
[0], inRData
[1], inRData
[2], inRData
[3], inRData
[4], inRData
[5], inRData
[6], inRData
[7], inRData
[8],
797 inRData
[9], inRData
[10], inRData
[11], inRData
[12], inRData
[13], inRData
[14], inRData
[15] );
801 printf( "ERROR: I dont know how to print inRData of type %d\n", inRRType
);
806 static char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
)
808 const unsigned char * src
= label
->c
; // Domain label we're reading
809 const unsigned char len
= *src
++; // Read length of this (non-null) label
810 const unsigned char *const end
= src
+ len
; // Work out where the label ends
811 if (len
> 63) return(NULL
); // If illegal label, abort
812 while (src
< end
) // While we have characters in the label
814 unsigned char c
= *src
++;
817 if (c
== '.') // If character is a dot,
818 *ptr
++ = esc
; // Output escape character
819 else if (c
<= ' ') // If non-printing ascii,
820 { // Output decimal escape sequence
822 *ptr
++ = (char) ('0' + (c
/ 100) );
823 *ptr
++ = (char) ('0' + (c
/ 10) % 10);
824 c
= (unsigned char)('0' + (c
) % 10);
827 *ptr
++ = (char)c
; // Copy the character
829 *ptr
= 0; // Null-terminate the string
830 return(ptr
); // and return
833 static char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
)
835 const unsigned char *src
= name
->c
; // Domain name we're reading
836 const unsigned char *const max
= name
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
838 if (*src
== 0) *ptr
++ = '.'; // Special case: For root, just write a dot
840 while (*src
) // While more characters in the domain name
842 if (src
+ 1 + *src
>= max
) return(NULL
);
843 ptr
= ConvertDomainLabelToCString_withescape((const domainlabel
*)src
, ptr
, esc
);
844 if (!ptr
) return(NULL
);
846 *ptr
++ = '.'; // Write the dot after the label
849 *ptr
++ = 0; // Null-terminate the string
850 return(ptr
); // and return