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