]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSWindows/Applications/DNSServiceTest/Tool.c
46e8e0c025cc74a4166bfbcb2c20ea6c8b13b703
[apple/mdnsresponder.git] / mDNSWindows / Applications / DNSServiceTest / Tool.c
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24
25 Change History (most recent first):
26
27 $Log: Tool.c,v $
28 Revision 1.12 2004/04/09 21:03:15 bradley
29 Changed port numbers to use network byte order for consistency with other platforms.
30
31 Revision 1.11 2004/01/30 03:04:32 bradley
32 Updated for latest changes to mDNSWindows.
33
34 Revision 1.10 2003/10/31 12:18:31 bradley
35 Added display of the resolved host name. Show separate TXT record entries on separate lines.
36
37 Revision 1.9 2003/10/22 02:00:20 bradley
38 Fixed proxy IP setup to be in network byte order so it works on Mac and Windows.
39
40 Revision 1.8 2003/10/04 04:47:08 bradley
41 Changed DNSServiceRegistrationCreate to treat the port in network byte order for end-to-end consistency.
42
43 Revision 1.7 2003/08/20 07:06:34 bradley
44 Update to APSL 2.0. Updated change history to match other mDNSResponder files.
45
46 Revision 1.6 2003/08/20 06:50:55 bradley
47 Updated to latest internal version of the Rendezvous for Windows code: Re-did everything to support
48 the latest DNSServices APIs (proxies, record updates, etc.); Added support for testing the platform
49 neutral DNSServices-based emulation layer for the Mac OS X DNSServiceDiscovery API.
50
51 */
52
53 #if( defined( _MSC_VER ) )
54 #pragma warning( disable:4068 ) // Disable "unknown pragma" warning for "pragma unused".
55 #pragma warning( disable:4127 ) // Disable "conditional expression is constant" warning for debug macros.
56 #pragma warning( disable:4311 ) // Disable "type cast : pointer truncation from void *const to int".
57
58 // No stdint.h with Visual C++ so emulate it here.
59
60 typedef signed char int8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
61 typedef unsigned char uint8_t; // C99 stdint.h not supported in VC++/VS.NET yet.
62 typedef signed short int16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
63 typedef unsigned short uint16_t; // C99 stdint.h not supported in VC++/VS.NET yet.
64 typedef signed long int32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
65 typedef unsigned long uint32_t; // C99 stdint.h not supported in VC++/VS.NET yet.
66 #else
67 #include <stdint.h>
68 #endif
69
70 #include <stdio.h>
71 #include <stdlib.h>
72
73 #if( __MACH__ )
74 #include <sys/types.h>
75 #include <sys/socket.h>
76 #include <netinet/in.h>
77
78 #include <signal.h>
79 #include <unistd.h>
80
81 #include <CoreServices/CoreServices.h>
82 #else
83 #define WIN32_LEAN_AND_MEAN
84
85 #include <winsock2.h>
86 #include <windows.h>
87 #endif
88
89 #include "DNSServices.h"
90 #include "DNSServiceDiscovery.h"
91
92 //===========================================================================================================================
93 // Macros
94 //===========================================================================================================================
95
96 #if( !TARGET_OS_MAC )
97 #define require_action_string( X, LABEL, ACTION, STR ) \
98 do \
99 { \
100 if( !( X ) ) \
101 { \
102 fprintf( stderr, "%s\n", ( STR ) ); \
103 { ACTION; } \
104 goto LABEL; \
105 } \
106 } while( 0 )
107
108 #define require_string( X, LABEL, STR ) \
109 do \
110 { \
111 if( !( X ) ) \
112 { \
113 fprintf( stderr, "%s\n", ( STR ) ); \
114 goto LABEL; \
115 \
116 } \
117 } while( 0 )
118
119 #define require_noerr_string( ERR, LABEL, STR ) \
120 do \
121 { \
122 if( ( ERR ) != 0 ) \
123 { \
124 fprintf( stderr, "%s (%ld)\n", ( STR ), ( ERR ) ); \
125 goto LABEL; \
126 } \
127 } while( 0 )
128 #endif
129
130 //===========================================================================================================================
131 // Prototypes
132 //===========================================================================================================================
133
134 int main( int argc, char* argv[] );
135 static void Usage( void );
136 static int ProcessArgs( int argc, char* argv[] );
137 static DNSStatus ProcessPreset( int inPreset );
138
139 #if( __MACH__ )
140 static void SigIntHandler( int inSignalNumber );
141 #endif
142
143 #if( defined( WINVER ) )
144 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent );
145 #endif
146
147 static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent );
148 static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent );
149
150 static void
151 RegistrationCallBack(
152 void * inContext,
153 DNSRegistrationRef inRef,
154 DNSStatus inStatusCode,
155 const DNSRegistrationEvent * inEvent );
156
157 static void
158 HostRegistrationCallBack(
159 void * inContext,
160 DNSHostRegistrationRef inRef,
161 DNSStatus inStatusCode,
162 void * inData );
163
164 static void
165 EmulatedBrowserCallBack(
166 DNSServiceBrowserReplyResultType inResult,
167 const char * inName,
168 const char * inType,
169 const char * inDomain,
170 DNSServiceDiscoveryReplyFlags inFlags,
171 void * inContext );
172
173 static void
174 EmulatedDomainEnumerationCallBack(
175 DNSServiceDomainEnumerationReplyResultType inResult,
176 const char * inDomain,
177 DNSServiceDiscoveryReplyFlags inFlags,
178 void * inContext );
179
180 static void
181 EmulatedResolverCallBack(
182 struct sockaddr * inInterfaceAddr,
183 struct sockaddr * inAddr,
184 const char * inTextRecord,
185 DNSServiceDiscoveryReplyFlags inFlags,
186 void * inContext );
187
188 static void EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext );
189
190 static char * IPv4ToString( DNSOpaque32 inIP, char *outString );
191
192 //===========================================================================================================================
193 // Globals
194 //===========================================================================================================================
195
196 #if( defined( WINVER ) )
197 static volatile int gQuit = 0;
198 #endif
199
200 static int gPrintTXTRecords = 1;
201
202 // Presets
203
204 typedef struct PresetData PresetData;
205 struct PresetData
206 {
207 int argc;
208 char * argv[ 16 ];
209 };
210
211 #if 0
212 #pragma mark == Presets ==
213 #endif
214
215 static const PresetData gPresets[] =
216 {
217 /* 01 */ { 2, { "rendezvous", "-bbd" } },
218 /* 02 */ { 4, { "rendezvous", "-bs", "_airport._tcp", "local." } },
219 /* 03 */ { 4, { "rendezvous", "-bs", "_xserveraid._tcp", "local." } },
220 /* 04 */ { 3, { "rendezvous", "-rdb", "apple.com" } },
221 /* 05 */ { 7, { "rendezvous", "-rs", "My Fake AirPort", "_airport._tcp", "local.", "1234", "My Fake Info" } },
222 /* 06 */ { 7, { "rendezvous", "-rs", "My Fake Xserve RAID", "_xserveraid._tcp", "local.", "1234", "My Fake Info" } },
223 /* 07 */ { 7, { "rendezvous", "-rs", "My Fake Web Server", "_http._tcp", "local.", "8080", "index.html" } },
224 /* 08 */ { 9, { "rendezvous", "-rps", "www.apple.com", "17.254.0.91", "Apple Web Server", "_http._tcp", "local.", "80", "index.html" } },
225 };
226
227 const int gPresetsCount = sizeof( gPresets ) / sizeof( gPresets[ 0 ] );
228
229 #if 0
230 #pragma mark -
231 #endif
232
233 //===========================================================================================================================
234 // main
235 //===========================================================================================================================
236
237 int main( int argc, char* argv[] )
238 {
239 DNSStatus err;
240
241 // Set up DNS Services and install a Console Control Handler to handle things like control-c signals.
242
243 err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
244 require_noerr_string( err, exit, "could not initialize Rendezvous" );
245
246 #if( __MACH__ )
247 signal( SIGINT, SigIntHandler );
248 #endif
249
250 #if( defined( WINVER ) )
251 SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
252 #endif
253
254 ProcessArgs( argc, argv );
255
256 exit:
257 DNSServicesFinalize();
258 return( err );
259 }
260
261 //===========================================================================================================================
262 // Usage
263 //===========================================================================================================================
264
265 static void Usage( void )
266 {
267 fprintf( stderr, "\n" );
268 fprintf( stderr, "rendezvous - Rendezvous Tool 1.0d1\n" );
269 fprintf( stderr, "\n" );
270 fprintf( stderr, " -bbd 'b'rowse for 'b'rowsing 'd'omains\n" );
271 fprintf( stderr, " -brd 'b'rowse for 'r'egistration 'd'omains\n" );
272 fprintf( stderr, " -bs <type> <domain> 'b'rowse for 's'ervices\n" );
273 fprintf( stderr, " -lsi <name> <type> <domain> 'l'ookup 's'ervice 'i'nstance\n" );
274 fprintf( stderr, " -rdb[d] <domain> 'r'egister 'd'omain for 'b'rowsing ['d'efault]\n" );
275 fprintf( stderr, " -rdr[d] <domain> 'r'egister 'd'omain for 'r'egistration ['d'efault]\n" );
276 fprintf( stderr, " -rs <name> <type> <domain> <port> <txt> 'r'egister 's'ervice\n" );
277 fprintf( stderr, " -rps <host> <ip> <name> <type> <domain> <port> <txt> 'r'egister 'p'roxy 's'ervice\n" );
278 fprintf( stderr, " -rnss <name> <type> <domain> 'r'egister 'n'o 's'uch 's'ervice\n" );
279
280 fprintf( stderr, " -ebs <type> <domain> 'e'mulated 'b'rowse for 's'ervices\n" );
281 fprintf( stderr, " -ebd <registration/browse> 'e'mulated 'b'rowse for 'd'omains\n" );
282 fprintf( stderr, " -elsi <name> <type> <domain> 'e'mulated 'l'ookup 's'ervice 'i'nstance\n" );
283 fprintf( stderr, " -ers <name> <type> <domain> <port> <txt> 'e'mulated 'r'egister 's'ervice\n" );
284
285 fprintf( stderr, " -h[elp] 'h'elp\n" );
286 fprintf( stderr, "\n" );
287
288 fprintf( stderr, " -1 Preset 1 (browse for browsing domains) rendezvous -bbd\n" );
289 fprintf( stderr, " -2 Preset 2 (browse for AirPort) rendezvous -bs \"_airport._tcp\" \"local.\"\n" );
290 fprintf( stderr, " -3 Preset 3 (browse for Xserve RAID) rendezvous -bs \"_xserveraid._tcp\" \"local.\"\n" );
291 fprintf( stderr, " -4 Preset 4 (register apple.com domain) rendezvous -rdb \"apple.com\"\n" );
292 fprintf( stderr, " -5 Preset 5 (register fake AirPort) rendezvous -rs \"My Fake AirPort\" \"_airport._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
293 fprintf( stderr, " -6 Preset 6 (register fake Xserve RAID) rendezvous -rs \"My Fake Xserve RAID\" \"_xserveraid._tcp\" \"local.\" 1234 \"My Fake Info\"\n" );
294 fprintf( stderr, " -7 Preset 7 (register fake web server) rendezvous -rs \"My Fake Web Server\" \"_http._tcp\" \"local.\" 8080 \"index.html\"\n" );
295 fprintf( stderr, "\n" );
296 }
297
298 //===========================================================================================================================
299 // ProcessArgs
300 //===========================================================================================================================
301
302 static int ProcessArgs( int argc, char* argv[] )
303 {
304 DNSStatus err;
305 int i;
306 const char * name;
307 const char * type;
308 const char * domain;
309 uint16_t port;
310 const char * text;
311 size_t textSize;
312 DNSBrowserRef browser;
313 DNSResolverFlags resolverFlags;
314 DNSDomainRegistrationType domainType;
315 const char * label;
316 const char * host;
317 const char * ip;
318 unsigned int b[ 4 ];
319 DNSNetworkAddress addr;
320 dns_service_discovery_ref emulatedRef;
321
322 // Parse the command line arguments (ignore first argument since it's just the program name).
323
324 require_action_string( argc >= 2, exit, err = kDNSBadParamErr, "no arguments specified" );
325
326 for( i = 1; i < argc; ++i )
327 {
328 if( strcmp( argv[ i ], "-bbd" ) == 0 )
329 {
330 // 'b'rowse for 'b'rowsing 'd'omains
331
332 fprintf( stdout, "browsing for browsing domains\n" );
333
334 err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
335 require_noerr_string( err, exit, "create browser failed" );
336
337 err = DNSBrowserStartDomainSearch( browser, 0 );
338 require_noerr_string( err, exit, "start domain search failed" );
339 }
340 else if( strcmp( argv[ i ], "-brd" ) == 0 )
341 {
342 // 'b'rowse for 'r'egistration 'd'omains
343
344 fprintf( stdout, "browsing for registration domains\n" );
345
346 err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
347 require_noerr_string( err, exit, "create browser failed" );
348
349 err = DNSBrowserStartDomainSearch( browser, kDNSBrowserFlagRegistrationDomainsOnly );
350 require_noerr_string( err, exit, "start domain search failed" );
351 }
352 else if( strcmp( argv[ i ], "-bs" ) == 0 )
353 {
354 // 'b'rowse for 's'ervices <type> <domain>
355
356 require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
357 ++i;
358 type = argv[ i++ ];
359 domain = argv[ i ];
360 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
361 {
362 domain = "local.";
363 }
364 fprintf( stdout, "browsing for \"%s.%s\"\n", type, domain );
365
366 err = DNSBrowserCreate( 0, BrowserCallBack, NULL, &browser );
367 require_noerr_string( err, exit, "create browser failed" );
368
369 err = DNSBrowserStartServiceSearch( browser, kDNSBrowserFlagAutoResolve, type, domain );
370 require_noerr_string( err, exit, "start service search failed" );
371 }
372 else if( strcmp( argv[ i ], "-lsi" ) == 0 )
373 {
374 // 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
375
376 require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
377 ++i;
378 name = argv[ i++ ];
379 type = argv[ i++ ];
380 domain = argv[ i ];
381 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
382 {
383 domain = "local.";
384 }
385 fprintf( stdout, "resolving \"%s.%s.%s\"\n", name, type, domain );
386
387 resolverFlags = kDNSResolverFlagOnlyIfUnique |
388 kDNSResolverFlagAutoReleaseByName;
389 err = DNSResolverCreate( resolverFlags, name, type, domain, ResolverCallBack, 0, NULL, NULL );
390 require_noerr_string( err, exit, "create resolver failed" );
391 }
392 else if( ( strcmp( argv[ i ], "-rdb" ) == 0 ) || ( strcmp( argv[ i ], "-rdbd" ) == 0 ) )
393 {
394 // 'r'egister 'd'omain for 'b'rowsing ['d'efault] <domain>
395
396 require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
397 if( strcmp( argv[ i ], "-rdb" ) == 0 )
398 {
399 domainType = kDNSDomainRegistrationTypeBrowse;
400 label = "";
401 }
402 else
403 {
404 domainType = kDNSDomainRegistrationTypeBrowseDefault;
405 label = "default ";
406 }
407 ++i;
408 domain = argv[ i ];
409 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
410 {
411 domain = "local.";
412 }
413 fprintf( stdout, "registering \"%s\" as %sbrowse domain\n", domain, label );
414
415 err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
416 require_noerr_string( err, exit, "create domain registration failed" );
417 }
418 else if( ( strcmp( argv[ i ], "-rdr" ) == 0 ) || ( strcmp( argv[ i ], "-rdrd" ) == 0 ) )
419 {
420 // 'r'egister 'd'omain for 'r'egistration ['d'efault] <domain>
421
422 require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
423 if( strcmp( argv[ i ], "-rdr" ) == 0 )
424 {
425 domainType = kDNSDomainRegistrationTypeRegistration;
426 label = "";
427 }
428 else
429 {
430 domainType = kDNSDomainRegistrationTypeRegistrationDefault;
431 label = "default ";
432 }
433 ++i;
434 domain = argv[ i ];
435 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
436 {
437 domain = "local.";
438 }
439 fprintf( stdout, "registering \"%s\" as %sregistration domain\n", domain, label );
440
441 err = DNSDomainRegistrationCreate( 0, domain, domainType, NULL );
442 require_noerr_string( err, exit, "create domain registration failed" );
443 }
444 else if( strcmp( argv[ i ], "-rs" ) == 0 )
445 {
446 // 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
447
448 require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
449 ++i;
450 name = argv[ i++ ];
451 type = argv[ i++ ];
452 domain = argv[ i++ ];
453 port = (uint16_t) atoi( argv[ i++ ] );
454 text = argv[ i ];
455 textSize = strlen( text );
456 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
457 {
458 domain = "local.";
459 }
460 fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
461
462 err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, NULL, NULL,
463 RegistrationCallBack, NULL, NULL );
464 require_noerr_string( err, exit, "create registration failed" );
465 }
466 else if( strcmp( argv[ i ], "-rps" ) == 0 )
467 {
468 DNSHostRegistrationFlags hostFlags;
469
470 // 'r'egister 'p'roxy 's'ervice <host> <ip> <name> <type> <domain> <port> <txt>
471
472 require_action_string( argc > ( i + 7 ), exit, err = kDNSBadParamErr, "missing arguments" );
473 ++i;
474 host = argv[ i++ ];
475 ip = argv[ i++ ];
476 name = argv[ i++ ];
477 type = argv[ i++ ];
478 domain = argv[ i++ ];
479 port = (uint16_t) atoi( argv[ i++ ] );
480 text = argv[ i ];
481 textSize = strlen( text );
482 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
483 {
484 domain = "local.";
485 }
486
487 sscanf( ip, "%u.%u.%u.%u", &b[ 0 ], &b[ 1 ], &b[ 2 ], &b[ 3 ] );
488 addr.addressType = kDNSNetworkAddressTypeIPv4;
489 addr.u.ipv4.addr.v8[ 0 ] = (DNSUInt8) b[ 0 ];
490 addr.u.ipv4.addr.v8[ 1 ] = (DNSUInt8) b[ 1 ];
491 addr.u.ipv4.addr.v8[ 2 ] = (DNSUInt8) b[ 2 ];
492 addr.u.ipv4.addr.v8[ 3 ] = (DNSUInt8) b[ 3 ];
493
494 fprintf( stdout, "registering proxy service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
495
496 hostFlags = kDNSHostRegistrationFlagOnlyIfNotFound | kDNSHostRegistrationFlagAutoRenameOnConflict;
497 err = DNSHostRegistrationCreate( hostFlags, host, domain, &addr, NULL,
498 HostRegistrationCallBack, NULL, NULL );
499 require_noerr_string( err, exit, "create host registration failed" );
500
501 err = DNSRegistrationCreate( 0, name, type, domain, (DNSPort) port, text, (DNSCount) textSize, host, NULL,
502 RegistrationCallBack, NULL, NULL );
503 require_noerr_string( err, exit, "create registration failed" );
504 }
505 else if( strcmp( argv[ i ], "-rnss" ) == 0 )
506 {
507 // 'r'egister 'n'o 's'uch 's'ervice <name> <type> <domain>
508
509 require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
510 ++i;
511 name = argv[ i++ ];
512 type = argv[ i++ ];
513 domain = argv[ i++ ];
514 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
515 {
516 domain = "local.";
517 }
518 fprintf( stdout, "registering no-such-service \"%s.%s.%s\"\n", name, type, domain );
519
520 err = DNSNoSuchServiceRegistrationCreate( 0, name, type, domain, NULL, RegistrationCallBack, NULL, NULL );
521 require_noerr_string( err, exit, "create no-such-service registration failed" );
522 }
523 else if( strcmp( argv[ i ], "-ebs" ) == 0 )
524 {
525 // 'e'mulated 'b'rowse for 's'ervices <type> <domain>
526
527 require_action_string( argc > ( i + 2 ), exit, err = kDNSBadParamErr, "missing arguments" );
528 ++i;
529 type = argv[ i++ ];
530 domain = argv[ i ];
531 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
532 {
533 domain = "local.";
534 }
535 fprintf( stdout, "emulated browsing for \"%s.%s\"\n", type, domain );
536
537 emulatedRef = DNSServiceBrowserCreate( type, domain, EmulatedBrowserCallBack, NULL );
538 require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated browser failed" );
539 }
540 else if( strcmp( argv[ i ], "-ebd" ) == 0 )
541 {
542 int registrationOnly;
543
544 // 'e'mulated 'b'rowse for 'd'omains <registration/browse>
545
546 require_action_string( argc > ( i + 1 ), exit, err = kDNSBadParamErr, "missing arguments" );
547 ++i;
548 type = argv[ i++ ];
549 if( strcmp( type, "registration" ) == 0 )
550 {
551 registrationOnly = 1;
552 }
553 else if( strcmp( type, "browse" ) == 0 )
554 {
555 registrationOnly = 0;
556 }
557 else
558 {
559 require_action_string( 0, exit, err = kDNSBadParamErr, "invalid browse type" );
560 }
561 fprintf( stdout, "emulated browsing for %s domains\n", type );
562
563 emulatedRef = DNSServiceDomainEnumerationCreate( registrationOnly, EmulatedDomainEnumerationCallBack, NULL );
564 require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated domain browser failed" );
565 }
566 else if( strcmp( argv[ i ], "-elsi" ) == 0 )
567 {
568 // 'e'mulated 'l'ookup 's'ervice 'i'nstance <name> <type> <domain>
569
570 require_action_string( argc > ( i + 3 ), exit, err = kDNSBadParamErr, "missing arguments" );
571 ++i;
572 name = argv[ i++ ];
573 type = argv[ i++ ];
574 domain = argv[ i ];
575 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
576 {
577 domain = "local.";
578 }
579 fprintf( stdout, "emulated resolving \"%s.%s.%s\"\n", name, type, domain );
580
581 emulatedRef = DNSServiceResolverResolve( name, type, domain, EmulatedResolverCallBack, NULL );
582 require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated resolver failed" );
583 }
584 else if( strcmp( argv[ i ], "-ers" ) == 0 )
585 {
586 // 'e'mulated 'r'egister 's'ervice <name> <type> <domain> <port> <txt>
587
588 require_action_string( argc > ( i + 5 ), exit, err = kDNSBadParamErr, "missing arguments" );
589 ++i;
590 name = argv[ i++ ];
591 type = argv[ i++ ];
592 domain = argv[ i++ ];
593 port = (uint16_t) atoi( argv[ i++ ] );
594 text = argv[ i ];
595 textSize = strlen( text );
596 if( ( domain[ 0 ] == '\0' ) || ( ( domain[ 0 ] == '.' ) && ( domain[ 1 ] == '\0' ) ) )
597 {
598 domain = "local.";
599 }
600 fprintf( stdout, "registering service \"%s.%s.%s\" port %d text \"%s\"\n", name, type, domain, port, text );
601
602 emulatedRef = DNSServiceRegistrationCreate( name, type, domain, htons( port ), text,
603 EmulatedRegistrationCallBack, NULL );
604 require_action_string( emulatedRef, exit, err = kDNSUnknownErr, "create emulated registration failed" );
605 }
606 else if( ( argv[ i ][ 0 ] == '-' ) && isdigit( argv[ i ][ 1 ] ) )
607 {
608 // Preset
609
610 ProcessPreset( atoi( &argv[ i ][ 1 ] ) );
611 err = 0;
612 goto exit;
613 }
614 else if( strcmp( argv[ i ], "-q" ) == 0 )
615 {
616 // Quiet (no text records)
617
618 gPrintTXTRecords = 0;
619 }
620 else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || ( strcmp( argv[ i ], "-h" ) == 0 ) )
621 {
622 // Help
623
624 Usage();
625 err = 0;
626 goto exit;
627 }
628 else
629 {
630 // Unknown parameter.
631
632 require_action_string( 0, exit, err = kDNSBadParamErr, "unknown parameter" );
633 goto exit;
634 }
635 }
636
637 // Run until control-C'd.
638
639 #if( __MACH__ )
640 CFRunLoopRun();
641 #endif
642
643 #if( defined( WINVER ) )
644 while( !gQuit )
645 {
646 Sleep( 200 );
647 }
648 #endif
649
650 err = kDNSNoErr;
651
652 exit:
653 if( err )
654 {
655 Usage();
656 }
657 return( err );
658 }
659
660 //===========================================================================================================================
661 // ProcessPreset
662 //===========================================================================================================================
663
664 static DNSStatus ProcessPreset( int inPreset )
665 {
666 DNSStatus err;
667
668 require_action_string( ( inPreset > 0 ) && ( inPreset <= gPresetsCount ), exit, err = kDNSBadParamErr, "invalid preset" );
669
670 err = ProcessArgs( gPresets[ inPreset - 1 ].argc, (char **) gPresets[ inPreset - 1 ].argv );
671
672 exit:
673 return( err );
674 }
675
676 #if( __MACH__ )
677 //===========================================================================================================================
678 // SigIntHandler
679 //===========================================================================================================================
680
681 static void SigIntHandler( int inSignalNumber )
682 {
683 DNS_UNUSED( inSignalNumber );
684
685 signal( SIGINT, SIG_DFL );
686 CFRunLoopStop( CFRunLoopGetCurrent() );
687 }
688 #endif
689
690 #if( defined( WINVER ) )
691 //===========================================================================================================================
692 // ConsoleControlHandler
693 //===========================================================================================================================
694
695 static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent )
696 {
697 BOOL handled;
698
699 handled = 0;
700 switch( inControlEvent )
701 {
702 case CTRL_C_EVENT:
703 case CTRL_BREAK_EVENT:
704 case CTRL_CLOSE_EVENT:
705 case CTRL_LOGOFF_EVENT:
706 case CTRL_SHUTDOWN_EVENT:
707 gQuit = 1;
708 handled = 1;
709 break;
710
711 default:
712 break;
713 }
714 return( handled );
715 }
716 #endif
717
718 //===========================================================================================================================
719 // BrowserCallBack
720 //===========================================================================================================================
721
722 static void BrowserCallBack( void *inContext, DNSBrowserRef inRef, DNSStatus inStatusCode, const DNSBrowserEvent *inEvent )
723 {
724 char ifIP[ 32 ];
725 char ip[ 32 ];
726
727 DNS_UNUSED( inContext );
728 DNS_UNUSED( inRef );
729 DNS_UNUSED( inStatusCode );
730
731 switch( inEvent->type )
732 {
733 case kDNSBrowserEventTypeRelease:
734 break;
735
736 case kDNSBrowserEventTypeAddDomain:
737 fprintf( stdout, "domain \"%s\" added on interface 0x%08X (%s)\n",
738 inEvent->data.addDomain.domain,
739 (int) inEvent->data.addDomain.interfaceID,
740 IPv4ToString( inEvent->data.addDomain.interfaceIP.u.ipv4.addr, ifIP ) );
741 break;
742
743 case kDNSBrowserEventTypeAddDefaultDomain:
744 fprintf( stdout, "default domain \"%s\" added on interface 0x%08X (%s)\n",
745 inEvent->data.addDefaultDomain.domain,
746 (int) inEvent->data.addDefaultDomain.interfaceID,
747 IPv4ToString( inEvent->data.addDefaultDomain.interfaceIP.u.ipv4.addr, ifIP ) );
748 break;
749
750 case kDNSBrowserEventTypeRemoveDomain:
751 fprintf( stdout, "domain \"%s\" removed on interface 0x%08X (%s)\n",
752 inEvent->data.removeDomain.domain,
753 (int) inEvent->data.removeDomain.interfaceID,
754 IPv4ToString( inEvent->data.removeDomain.interfaceIP.u.ipv4.addr, ifIP ) );
755 break;
756
757 case kDNSBrowserEventTypeAddService:
758 fprintf( stdout, "service \"%s.%s%s\" added on interface 0x%08X (%s)\n",
759 inEvent->data.addService.name,
760 inEvent->data.addService.type,
761 inEvent->data.addService.domain,
762 (int) inEvent->data.addService.interfaceID,
763 IPv4ToString( inEvent->data.addService.interfaceIP.u.ipv4.addr, ifIP ) );
764 break;
765
766 case kDNSBrowserEventTypeRemoveService:
767 fprintf( stdout, "service \"%s.%s%s\" removed on interface 0x%08X (%s)\n",
768 inEvent->data.removeService.name,
769 inEvent->data.removeService.type,
770 inEvent->data.removeService.domain,
771 (int) inEvent->data.removeService.interfaceID,
772 IPv4ToString( inEvent->data.removeService.interfaceIP.u.ipv4.addr, ifIP ) );
773 break;
774
775 case kDNSBrowserEventTypeResolved:
776 {
777 const uint8_t * p;
778 const uint8_t * end;
779 int i;
780
781 fprintf( stdout, "resolved \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%08X (%s)%s\n",
782 inEvent->data.resolved->name,
783 inEvent->data.resolved->type,
784 inEvent->data.resolved->domain,
785 inEvent->data.resolved->hostName,
786 IPv4ToString( inEvent->data.resolved->address.u.ipv4.addr, ip ),
787 ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) |
788 inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ],
789 (int) inEvent->data.resolved->interfaceID,
790 IPv4ToString( inEvent->data.resolved->interfaceIP.u.ipv4.addr, ifIP ),
791 ( inEvent->data.resolved->textRecordRawSize > 0 ) ? " with text:" : "" );
792
793 p = (const uint8_t *) inEvent->data.resolved->textRecordRaw;
794 end = p + inEvent->data.resolved->textRecordRawSize;
795 i = 0;
796
797 if( gPrintTXTRecords )
798 {
799 while( p < end )
800 {
801 uint8_t size;
802
803 size = *p++;
804 if( ( p + size ) > end )
805 {
806 fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
807 break;
808 }
809 fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
810 p += size;
811 ++i;
812 }
813 fprintf( stdout, "\n" );
814 }
815 break;
816 }
817
818 default:
819 break;
820 }
821 }
822
823 //===========================================================================================================================
824 // ResolverCallBack
825 //===========================================================================================================================
826
827 static void ResolverCallBack( void *inContext, DNSResolverRef inRef, DNSStatus inStatusCode, const DNSResolverEvent *inEvent )
828 {
829 char ifIP[ 32 ];
830 char ip[ 32 ];
831
832 DNS_UNUSED( inContext );
833 DNS_UNUSED( inRef );
834 DNS_UNUSED( inStatusCode );
835
836 switch( inEvent->type )
837 {
838 case kDNSResolverEventTypeResolved:
839 {
840 const uint8_t * p;
841 const uint8_t * end;
842 int i;
843
844 fprintf( stdout, "resolved \"%s.%s%s\" to \"%s\" (%s:%u) on interface 0x%08X (%s)%s\n",
845 inEvent->data.resolved.name,
846 inEvent->data.resolved.type,
847 inEvent->data.resolved.domain,
848 inEvent->data.resolved.hostName,
849 IPv4ToString( inEvent->data.resolved.address.u.ipv4.addr, ip ),
850 ( inEvent->data.resolved.address.u.ipv4.port.v8[ 0 ] << 8 ) |
851 inEvent->data.resolved.address.u.ipv4.port.v8[ 1 ],
852 (int) inEvent->data.resolved.interfaceID,
853 IPv4ToString( inEvent->data.resolved.interfaceIP.u.ipv4.addr, ifIP ),
854 ( inEvent->data.resolved.textRecordRawSize > 0 ) ? " with text:" : "" );
855
856 p = (const uint8_t *) inEvent->data.resolved.textRecordRaw;
857 end = p + inEvent->data.resolved.textRecordRawSize;
858 i = 0;
859
860 if( gPrintTXTRecords )
861 {
862 while( p < end )
863 {
864 uint8_t size;
865
866 size = *p++;
867 if( ( p + size ) > end )
868 {
869 fprintf( stdout, "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
870 break;
871 }
872 fprintf( stdout, "%5d (%3d bytes): \"%.*s\"\n", i, size, size, p );
873 p += size;
874 ++i;
875 }
876 fprintf( stdout, "\n" );
877 }
878 break;
879 }
880
881 case kDNSResolverEventTypeRelease:
882 break;
883
884 default:
885 break;
886 }
887 }
888
889 //===========================================================================================================================
890 // RegistrationCallBack
891 //===========================================================================================================================
892
893 static void
894 RegistrationCallBack(
895 void * inContext,
896 DNSRegistrationRef inRef,
897 DNSStatus inStatusCode,
898 const DNSRegistrationEvent * inEvent )
899 {
900 DNS_UNUSED( inContext );
901 DNS_UNUSED( inRef );
902 DNS_UNUSED( inStatusCode );
903
904 switch( inEvent->type )
905 {
906 case kDNSRegistrationEventTypeRelease:
907 break;
908
909 case kDNSRegistrationEventTypeRegistered:
910 fprintf( stdout, "name registered and active\n" );
911 break;
912
913 case kDNSRegistrationEventTypeNameCollision:
914 fprintf( stdout, "name in use, please choose another name\n" );
915 break;
916
917 default:
918 break;
919 }
920 }
921
922 //===========================================================================================================================
923 // HostRegistrationCallBack
924 //===========================================================================================================================
925
926 static void
927 HostRegistrationCallBack(
928 void * inContext,
929 DNSHostRegistrationRef inRef,
930 DNSStatus inStatusCode,
931 void * inData )
932 {
933 DNS_UNUSED( inContext );
934 DNS_UNUSED( inRef );
935 DNS_UNUSED( inData );
936
937 if( inStatusCode == kDNSNoErr )
938 {
939 fprintf( stdout, "host name registered and active\n" );
940 }
941 else if( inStatusCode == kDNSNameConflictErr )
942 {
943 fprintf( stdout, "host name in use, please choose another name\n" );
944 }
945 else
946 {
947 fprintf( stdout, "unknown host registration status (%ld)\n", inStatusCode );
948 }
949 }
950
951 //===========================================================================================================================
952 // EmulatedBrowserCallBack
953 //===========================================================================================================================
954
955 static void
956 EmulatedBrowserCallBack(
957 DNSServiceBrowserReplyResultType inResult,
958 const char * inName,
959 const char * inType,
960 const char * inDomain,
961 DNSServiceDiscoveryReplyFlags inFlags,
962 void * inContext )
963 {
964 DNS_UNUSED( inFlags );
965 DNS_UNUSED( inContext );
966
967 if( inResult == DNSServiceBrowserReplyAddInstance )
968 {
969 fprintf( stdout, "\"%s.%s%s\" service added emulated\n", inName, inType, inDomain );
970 }
971 else if( inResult == DNSServiceBrowserReplyRemoveInstance )
972 {
973 fprintf( stdout, "\"%s.%s%s\" service removed emulated\n", inName, inType, inDomain );
974 }
975 else
976 {
977 fprintf( stdout, "### unknown emulated browser callback result (%d)\n", inResult );
978 }
979 }
980
981 //===========================================================================================================================
982 // EmulatedDomainEnumerationCallBack
983 //===========================================================================================================================
984
985 static void
986 EmulatedDomainEnumerationCallBack(
987 DNSServiceDomainEnumerationReplyResultType inResult,
988 const char * inDomain,
989 DNSServiceDiscoveryReplyFlags inFlags,
990 void * inContext )
991 {
992 DNS_UNUSED( inFlags );
993 DNS_UNUSED( inContext );
994
995 if( inResult == DNSServiceDomainEnumerationReplyAddDomain )
996 {
997 fprintf( stdout, "\"%s\" domain added emulated\n", inDomain );
998 }
999 else if( inResult == DNSServiceDomainEnumerationReplyAddDomainDefault )
1000 {
1001 fprintf( stdout, "\"%s\" default domain added emulated\n", inDomain );
1002 }
1003 else if( inResult == DNSServiceDomainEnumerationReplyRemoveDomain )
1004 {
1005 fprintf( stdout, "\"%s\" domain removed emulated\n", inDomain );
1006 }
1007 else
1008 {
1009 fprintf( stdout, "### unknown emulated domain enumeration callback result (%d)\n", inResult );
1010 }
1011 }
1012
1013 //===========================================================================================================================
1014 // EmulatedResolverCallBack
1015 //===========================================================================================================================
1016
1017 static void
1018 EmulatedResolverCallBack(
1019 struct sockaddr * inInterfaceAddr,
1020 struct sockaddr * inAddr,
1021 const char * inTextRecord,
1022 DNSServiceDiscoveryReplyFlags inFlags,
1023 void * inContext )
1024 {
1025 struct sockaddr_in * ifSin4;
1026 struct sockaddr_in * sin4;
1027 char ifIP[ 64 ];
1028 char ip[ 64 ];
1029
1030 DNS_UNUSED( inFlags );
1031 DNS_UNUSED( inContext );
1032
1033 ifSin4 = (struct sockaddr_in *) inInterfaceAddr;
1034 sin4 = (struct sockaddr_in *) inAddr;
1035
1036 fprintf( stdout, "service resolved to %s:%d on interface %s with text \"%s\"\n",
1037 IPv4ToString( *( (DNSOpaque32 *) &sin4->sin_addr.s_addr ), ip ),
1038 ntohs( sin4->sin_port ),
1039 IPv4ToString( *( (DNSOpaque32 *) &ifSin4->sin_addr.s_addr ), ifIP ),
1040 inTextRecord ? inTextRecord : "" );
1041 }
1042
1043 //===========================================================================================================================
1044 // EmulatedResolverCallBack
1045 //===========================================================================================================================
1046
1047 static void EmulatedRegistrationCallBack( DNSServiceRegistrationReplyErrorType inResult, void *inContext )
1048 {
1049 DNS_UNUSED( inContext );
1050
1051 if( inResult == kDNSServiceDiscoveryNoError )
1052 {
1053 fprintf( stdout, "service name registered successfully\n" );
1054 }
1055 else
1056 {
1057 fprintf( stdout, "service registration failed( %d)\n", inResult );
1058 }
1059 }
1060
1061 //===========================================================================================================================
1062 // IPv4ToString
1063 //===========================================================================================================================
1064
1065 static char * IPv4ToString( DNSOpaque32 inIP, char *outString )
1066 {
1067 sprintf( outString, "%u.%u.%u.%u", inIP.v8[ 0 ], inIP.v8[ 1 ], inIP.v8[ 2 ], inIP.v8[ 3 ] );
1068 return( outString );
1069 }