2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
28 Revision 1.3 2004/04/09 21:03:15 bradley
29 Changed port numbers to use network byte order for consistency with other platforms.
31 Revision 1.2 2004/04/08 09:43:43 bradley
32 Changed callback calling conventions to __stdcall so they can be used with C# delegates.
34 Revision 1.1 2004/01/30 02:58:57 bradley
35 Test tool for the mDNSResponder Windows service.
42 #include "CommonServices.h"
43 #include "DebugServices.h"
46 //===========================================================================================================================
48 //===========================================================================================================================
50 #define MAX_DOMAIN_LABEL 63
51 #define MAX_DOMAIN_NAME 255
53 typedef union { unsigned char b
[2]; unsigned short NotAnInteger
; } Opaque16
;
55 typedef struct { u_char c
[ 64]; } domainlabel
;
56 typedef struct { u_char c
[256]; } domainname
;
66 //===========================================================================================================================
68 //===========================================================================================================================
70 int main( int argc
, char* argv
[] );
71 static void Usage( void );
72 static int ProcessArgs( int argc
, char* argv
[] );
74 #if( defined( WINVER ) )
75 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
);
78 static void CALLBACK_COMPAT
79 EnumerateDomainsCallBack(
81 DNSServiceFlags inFlags
,
82 uint32_t inInterfaceIndex
,
83 DNSServiceErrorType inErrorCode
,
84 const char * inDomain
,
87 static void CALLBACK_COMPAT
90 DNSServiceFlags inFlags
,
91 uint32_t inInterfaceIndex
,
92 DNSServiceErrorType inErrorCode
,
95 const char * inDomain
,
98 static void CALLBACK_COMPAT
101 DNSServiceFlags inFlags
,
102 uint32_t inInterfaceIndex
,
103 DNSServiceErrorType inErrorCode
,
104 const char * inFullName
,
105 const char * inHostName
,
111 static void CALLBACK_COMPAT
114 DNSServiceFlags inFlags
,
115 DNSServiceErrorType inErrorCode
,
118 const char * inDomain
,
121 static void CALLBACK_COMPAT
124 DNSRecordRef inRecordRef
,
125 DNSServiceFlags inFlags
,
126 DNSServiceErrorType inErrorCode
,
129 static void CALLBACK_COMPAT
131 const DNSServiceRef inRef
,
132 const DNSServiceFlags inFlags
,
133 const uint32_t inInterfaceIndex
,
134 const DNSServiceErrorType inErrorCode
,
136 const uint16_t inRRType
,
137 const uint16_t inRRClass
,
138 const uint16_t inRDataSize
,
139 const void * inRData
,
140 const uint32_t inTTL
,
143 static void PrintRData( uint16_t inRRType
, size_t inRDataSize
, const uint8_t *inRData
);
145 static char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
);
146 static char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
);
148 //===========================================================================================================================
150 //===========================================================================================================================
152 #if( defined( WINVER ) )
153 static volatile int gQuit
= 0;
156 //===========================================================================================================================
158 //===========================================================================================================================
160 int main( int argc
, char *argv
[] )
164 debug_initialize( kDebugOutputTypeMetaConsole
);
165 debug_set_property( kDebugPropertyTagPrintLevel
, kDebugLevelTrace
);
167 SetConsoleCtrlHandler( ConsoleControlHandler
, TRUE
);
168 err
= ProcessArgs( argc
, argv
);
172 //===========================================================================================================================
174 //===========================================================================================================================
176 static void Usage( void )
178 fprintf( stderr
, "\n" );
179 fprintf( stderr
, "Rendezvous Service Test 1.0d1\n" );
180 fprintf( stderr
, "\n" );
181 fprintf( stderr
, " -server <IP> Set Remote Server\n" );
182 fprintf( stderr
, " -cv Check Version\n" );
183 fprintf( stderr
, " -bd Browse for Browse Domains\n" );
184 fprintf( stderr
, " -bs <type> <domain> Browse for Services\n" );
185 fprintf( stderr
, " -rsi <name> <type> <domain> Resolve Service Instance\n" );
186 fprintf( stderr
, " -rs <name> <type> <domain> <host> <port> <txt> Register Service\n" );
187 fprintf( stderr
, " -rr Register Records\n" );
188 fprintf( stderr
, " -qr <name> <type> <domain> <rrType> Query Record\n" );
189 fprintf( stderr
, " -cr <name> <type> <domain> <rrType> Reconfirm Record\n" );
190 fprintf( stderr
, " -cp <code> Copy Property\n" );
191 fprintf( stderr
, " -h[elp] Help\n" );
192 fprintf( stderr
, "\n" );
195 DEBUG_LOCAL DNSServiceRef gRef
= NULL
;
196 DEBUG_LOCAL DNSRecordRef gRecordRef
= NULL
;
197 DEBUG_LOCAL
const char * gServer
= NULL
;
199 //===========================================================================================================================
201 //===========================================================================================================================
203 static int ProcessArgs( int argc
, char* argv
[] )
214 uint8_t txtStorage
[ 256 ];
217 DNSRecordRef records
[ 10 ];
218 char fullName
[ kDNSServiceMaxDomainName
];
221 err
= DNSServiceInitialize( kDNSServiceInitializeFlagsNoServerCheck
, 0 );
222 require_noerr( err
, exit
);
224 // Parse the command line arguments (ignore first argument since it's just the program name).
232 for( i
= 1; i
< argc
; ++i
)
234 if( strcmp( argv
[ i
], "-server" ) == 0 )
236 require_action( argc
> ( i
+ 1 ), exit
, err
= kParamErr
);
237 gServer
= argv
[ ++i
];
239 printf( "Server set to \"%s\"\n", gServer
);
241 else if( strcmp( argv
[ i
], "-cv" ) == 0 )
245 err
= DNSServiceCheckVersion();
246 printf( "CheckVersion: %ld\n", err
);
250 else if( strcmp( argv
[ i
], "-bd" ) == 0 )
252 err
= DNSServiceEnumerateDomains( &gRef
, kDNSServiceFlagsBrowseDomains
, 0,
253 EnumerateDomainsCallBack
, NULL
);
254 require_noerr( err
, exit
);
256 else if( strcmp( argv
[ i
], "-bs" ) == 0 )
258 // Browse service <type> <domain>
260 if( argc
> ( i
+ 2 ) )
263 domain
= argv
[ ++i
];
270 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
275 err
= DNSServiceBrowse( &gRef
, 0, 0, type
, domain
, BrowseCallBack
, NULL
);
276 require_noerr( err
, exit
);
278 else if( strcmp( argv
[ i
], "-rsi" ) == 0 )
280 // Resolve Service Instance <name> <type> <domain>
282 if( argc
> ( i
+ 3 ) )
286 domain
= argv
[ ++i
];
290 name
= "test service";
294 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
299 err
= DNSServiceResolve( &gRef
, 0, 0, name
, type
, domain
, ResolveCallBack
, NULL
);
300 require_noerr( err
, exit
);
302 else if( strcmp( argv
[ i
], "-rs" ) == 0 )
304 // Register Service <name> <type> <domain> <host> <port> <txt>
306 if( argc
> ( i
+ 6 ) )
310 domain
= argv
[ ++i
];
312 port
= (uint16_t) atoi( argv
[ ++i
] );
317 name
= "test service";
322 txt
= "My TXT Record";
326 txtStorage
[ 0 ] = (uint8_t) strlen( txt
);
327 memcpy( &txtStorage
[ 1 ], txt
, txtStorage
[ 0 ] );
328 txtSize
= (uint16_t)( 1 + txtStorage
[ 0 ] );
329 txt
= (const char *) txtStorage
;
336 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
341 err
= DNSServiceRegister( &gRef
, 0, 0, name
, type
, domain
, host
, htons( port
), txtSize
, txt
,
342 RegisterCallBack
, NULL
);
343 require_noerr( err
, exit
);
345 #if( TEST_SERVICE_RECORDS )
347 err
= DNSServiceAddRecord( gRef
, &gRecordRef
, 0, kDNSServiceDNSType_A
, kDNSServiceDNSClass_IN
, &ipv4
, 60 );
348 require_noerr( err
, exit
);
353 err
= DNSServiceUpdateRecord( gRef
, gRecordRef
, 0, 4, &ipv4
, 60 );
354 require_noerr( err
, exit
);
358 err
= DNSServiceRemoveRecord( gRef
, gRecordRef
, 0 );
359 require_noerr( err
, exit
);
365 else if( strcmp( argv
[ i
], "-rr" ) == 0 )
369 err
= DNSServiceCreateConnection( &gRef
);
370 require_noerr( err
, exit
);
372 printf( "registering 10 address records...\n" );
374 for( i
= 0; i
< 10; ++i
)
376 sprintf( s
, "testhost-%d.local.", i
);
378 err
= DNSServiceRegisterRecord( gRef
, &records
[ i
], kDNSServiceFlagsUnique
, 0, s
,
379 kDNSServiceDNSType_A
, kDNSServiceDNSClass_IN
, 4, &ipv4
, 60, RecordCallBack
, NULL
);
384 printf( "deregistering half of the records\n" );
385 for( i
= 0; i
< 10; ++i
)
389 err
= DNSServiceRemoveRecord( gRef
, records
[ i
], 0 );
396 printf( "updating the remaining records\n" );
397 for( i
= 0; i
< 10; ++i
)
402 err
= DNSServiceUpdateRecord( gRef
, records
[ i
], 0, 4, &ipv4
, 60 );
408 printf( "deregistering all remaining records\n" );
409 DNSServiceRefDeallocate( gRef
);
413 else if( strcmp( argv
[ i
], "-qr" ) == 0 )
415 // Query Record <name> <type> <domain> <rrType>
417 if( argc
> ( i
+ 4 ) )
421 domain
= argv
[ ++i
];
422 rrType
= (uint16_t) atoi( argv
[ ++i
] );
429 rrType
= 1; // Address
431 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
435 err
= DNSServiceConstructFullName( fullName
, name
, type
, domain
);
436 require_noerr( err
, exit
);
438 printf( "resolving fullname %s type %d\n", fullName
, rrType
);
439 err
= DNSServiceQueryRecord( &gRef
, 0, 0, fullName
, rrType
, kDNSServiceDNSClass_IN
, QueryCallBack
, NULL
);
440 require_noerr( err
, exit
);
442 else if( strcmp( argv
[ i
], "-cr" ) == 0 )
444 // Reconfirm Record <name> <type> <domain> <rrType>
446 if( argc
> ( i
+ 4 ) )
450 domain
= argv
[ ++i
];
451 rrType
= (uint16_t) atoi( argv
[ ++i
] );
458 rrType
= 1; // Address
460 if( ( domain
[ 0 ] == '\0' ) || ( ( domain
[ 0 ] == '.' ) && ( domain
[ 1 ] == '\0' ) ) )
464 err
= DNSServiceConstructFullName( fullName
, name
, type
, domain
);
465 require_noerr( err
, exit
);
467 printf( "reconfirming record fullname %s type %d\n", fullName
, rrType
);
469 DNSServiceReconfirmRecord( 0, 0, fullName
, rrType
, kDNSServiceDNSClass_IN
, 4, &ipv4
);
471 else if( strcmp( argv
[ i
], "-cp" ) == 0 )
473 DNSPropertyCode code
;
474 DNSPropertyData data
;
476 // Copy Property <code>
478 if( argc
> ( i
+ 1 ) )
481 require_action( strlen( name
) == 4, exit
, err
= kParamErr
);
483 code
= (DNSPropertyCode
)( name
[ 0 ] << 24 );
484 code
|= (DNSPropertyCode
)( name
[ 1 ] << 16 );
485 code
|= (DNSPropertyCode
)( name
[ 2 ] << 8 );
486 code
|= (DNSPropertyCode
) name
[ 3 ];
490 code
= kDNSPropertyCodeVersion
;
494 err
= DNSServiceCopyProperty( code
, &data
);
495 require_noerr( err
, exit
);
497 printf( "'%s' property:\n", name
);
498 if( code
== kDNSPropertyCodeVersion
)
500 printf( " clientCurrentVersion: 0x%08X\n", data
.u
.version
.clientCurrentVersion
);
501 printf( " clientOldestServerVersion: 0x%08X\n", data
.u
.version
.clientOldestServerVersion
);
502 printf( " serverCurrentVersion: 0x%08X\n", data
.u
.version
.serverCurrentVersion
);
503 printf( " serverOldestClientVersion: 0x%08X\n", data
.u
.version
.serverOldestClientVersion
);
506 else if( ( strcmp( argv
[ i
], "-help" ) == 0 ) || ( strcmp( argv
[ i
], "-h" ) == 0 ) )
516 // Unknown parameter.
518 dlog( kDebugLevelError
, "unknown parameter (%s)\n", argv
[ i
] );
524 // Run until control-C'd.
533 DNSServiceFinalize();
541 //===========================================================================================================================
542 // ConsoleControlHandler
543 //===========================================================================================================================
545 static BOOL WINAPI
ConsoleControlHandler( DWORD inControlEvent
)
550 switch( inControlEvent
)
553 case CTRL_BREAK_EVENT
:
554 case CTRL_CLOSE_EVENT
:
555 case CTRL_LOGOFF_EVENT
:
556 case CTRL_SHUTDOWN_EVENT
:
567 //===========================================================================================================================
568 // EnumerateDomainsCallBack
569 //===========================================================================================================================
571 static void CALLBACK_COMPAT
572 EnumerateDomainsCallBack(
574 DNSServiceFlags inFlags
,
575 uint32_t inInterfaceIndex
,
576 DNSServiceErrorType inErrorCode
,
577 const char * inDomain
,
580 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
581 printf( "inFlags: 0x%08X\n", (int) inFlags
);
582 printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex
);
583 printf( "inErrorCode: %ld\n", inErrorCode
);
584 printf( "inDomain: \"%s\"\n", inDomain
? inDomain
: "<null>" );
585 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
589 //===========================================================================================================================
591 //===========================================================================================================================
593 static void CALLBACK_COMPAT
596 DNSServiceFlags inFlags
,
597 uint32_t inInterfaceIndex
,
598 DNSServiceErrorType inErrorCode
,
601 const char * inDomain
,
604 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
605 printf( "inFlags: 0x%08X\n", (int) inFlags
);
606 printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex
);
607 printf( "inErrorCode: %ld\n", inErrorCode
);
608 printf( "inName: \"%s\"\n", inName
? inName
: "<null>" );
609 printf( "inType: \"%s\"\n", inType
? inType
: "<null>" );
610 printf( "inDomain: \"%s\"\n", inDomain
? inDomain
: "<null>" );
611 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
615 //===========================================================================================================================
617 //===========================================================================================================================
619 static void CALLBACK_COMPAT
622 DNSServiceFlags inFlags
,
623 uint32_t inInterfaceIndex
,
624 DNSServiceErrorType inErrorCode
,
625 const char * inFullName
,
626 const char * inHostName
,
632 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
633 printf( "inFlags: 0x%08X\n", (int) inFlags
);
634 printf( "inInterfaceIndex: 0x%08X\n", (int) inInterfaceIndex
);
635 printf( "inErrorCode: %ld\n", inErrorCode
);
636 printf( "inFullName: \"%s\"\n", inFullName
? inFullName
: "<null>" );
637 printf( "inHostName: \"%s\"\n", inHostName
? inHostName
: "<null>" );
638 printf( "inPort: %d\n", ntohs( inPort
) );
639 printf( "inTXTSize: %ld\n", inTXTSize
);
640 printf( "inTXT: 0x%08X\n", (uintptr_t) inTXT
);
641 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
645 //===========================================================================================================================
647 //===========================================================================================================================
649 static void CALLBACK_COMPAT
652 DNSServiceFlags inFlags
,
653 DNSServiceErrorType inErrorCode
,
656 const char * inDomain
,
659 printf( "inRef: 0x%08X\n", (uintptr_t) inRef
);
660 printf( "inFlags: 0x%08X\n", (int) inFlags
);
661 printf( "inErrorCode: %ld\n", inErrorCode
);
662 printf( "inName: \"%s\"\n", inName
? inName
: "<null>" );
663 printf( "inType: \"%s\"\n", inType
? inType
: "<null>" );
664 printf( "inDomain: \"%s\"\n", inDomain
? inDomain
: "<null>" );
665 printf( "inContext: 0x%08X\n", (uintptr_t) inContext
);
669 //===========================================================================================================================
671 //===========================================================================================================================
673 static void CALLBACK_COMPAT
676 DNSRecordRef inRecordRef
,
677 DNSServiceFlags inFlags
,
678 DNSServiceErrorType inErrorCode
,
681 DEBUG_UNUSED( inRef
);
682 DEBUG_UNUSED( inRecordRef
);
683 DEBUG_UNUSED( inFlags
);
684 DEBUG_UNUSED( inContext
);
686 if( inErrorCode
== kDNSServiceErr_NoError
)
688 printf( "RecordCallBack: no errors\n" );
692 printf( "RecordCallBack: %ld error\n", inErrorCode
);
696 //===========================================================================================================================
698 //===========================================================================================================================
700 static void CALLBACK_COMPAT
702 const DNSServiceRef inRef
,
703 const DNSServiceFlags inFlags
,
704 const uint32_t inInterfaceIndex
,
705 const DNSServiceErrorType inErrorCode
,
707 const uint16_t inRRType
,
708 const uint16_t inRRClass
,
709 const uint16_t inRDataSize
,
710 const void * inRData
,
711 const uint32_t inTTL
,
714 DEBUG_UNUSED( inRef
);
715 DEBUG_UNUSED( inRRClass
);
716 DEBUG_UNUSED( inTTL
);
717 DEBUG_UNUSED( inContext
);
719 if( inErrorCode
== kDNSServiceErr_NoError
)
721 if( inFlags
& kDNSServiceFlagsAdd
)
729 if( inFlags
& kDNSServiceFlagsMoreComing
)
737 printf(" 0x%04X %d %s rdata ", inFlags
, inInterfaceIndex
, inName
);
738 PrintRData( inRRType
, (size_t) inRDataSize
, (const uint8_t *) inRData
);
742 printf( "QueryCallback: %ld error\n", inErrorCode
);
746 //===========================================================================================================================
748 //===========================================================================================================================
750 static void PrintRData( uint16_t inRRType
, size_t inRDataSize
, const uint8_t *inRData
)
759 case kDNSServiceDNSType_TXT
:
761 // Print all the alphanumeric and punctuation characters
763 for( i
= 0; i
< inRDataSize
; ++i
)
765 if( ( inRData
[ i
] >= 32 ) && ( inRData
[ i
] <= 127 ) )
767 printf( "%c", inRData
[ i
] );
773 case kDNSServiceDNSType_SRV
:
774 srv
= (srv_rdata
*)inRData
;
775 ConvertDomainNameToCString_withescape(&srv
->target
, s
, 0);
776 printf("pri=%d, w=%d, port=%d, target=%s\n", srv
->priority
, srv
->weight
, srv
->port
, s
);
779 case kDNSServiceDNSType_A
:
780 check( inRDataSize
== 4 );
781 memcpy( &in
, inRData
, sizeof( in
) );
782 printf( "%s\n", inet_ntoa( in
) );
785 case kDNSServiceDNSType_PTR
:
786 ConvertDomainNameToCString_withescape( (domainname
*) inRData
, s
, 0 );
789 case kDNSServiceDNSType_AAAA
:
790 check( inRDataSize
== 16 );
791 printf( "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X\n",
792 inRData
[0], inRData
[1], inRData
[2], inRData
[3], inRData
[4], inRData
[5], inRData
[6], inRData
[7], inRData
[8],
793 inRData
[9], inRData
[10], inRData
[11], inRData
[12], inRData
[13], inRData
[14], inRData
[15] );
797 printf( "ERROR: I dont know how to print inRData of type %d\n", inRRType
);
802 static char *ConvertDomainLabelToCString_withescape(const domainlabel
*const label
, char *ptr
, char esc
)
804 const unsigned char * src
= label
->c
; // Domain label we're reading
805 const unsigned char len
= *src
++; // Read length of this (non-null) label
806 const unsigned char *const end
= src
+ len
; // Work out where the label ends
807 if (len
> 63) return(NULL
); // If illegal label, abort
808 while (src
< end
) // While we have characters in the label
810 unsigned char c
= *src
++;
813 if (c
== '.') // If character is a dot,
814 *ptr
++ = esc
; // Output escape character
815 else if (c
<= ' ') // If non-printing ascii,
816 { // Output decimal escape sequence
818 *ptr
++ = (char) ('0' + (c
/ 100) );
819 *ptr
++ = (char) ('0' + (c
/ 10) % 10);
820 c
= (unsigned char)('0' + (c
) % 10);
823 *ptr
++ = (char)c
; // Copy the character
825 *ptr
= 0; // Null-terminate the string
826 return(ptr
); // and return
829 static char *ConvertDomainNameToCString_withescape(const domainname
*const name
, char *ptr
, char esc
)
831 const unsigned char *src
= name
->c
; // Domain name we're reading
832 const unsigned char *const max
= name
->c
+ MAX_DOMAIN_NAME
; // Maximum that's valid
834 if (*src
== 0) *ptr
++ = '.'; // Special case: For root, just write a dot
836 while (*src
) // While more characters in the domain name
838 if (src
+ 1 + *src
>= max
) return(NULL
);
839 ptr
= ConvertDomainLabelToCString_withescape((const domainlabel
*)src
, ptr
, esc
);
840 if (!ptr
) return(NULL
);
842 *ptr
++ = '.'; // Write the dot after the label
845 *ptr
++ = 0; // Null-terminate the string
846 return(ptr
); // and return