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