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