]> git.saurik.com Git - apple/mdnsresponder.git/blob - Clients/dns-sd.c
mDNSResponder-765.30.11.tar.gz
[apple/mdnsresponder.git] / Clients / dns-sd.c
1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
4 *
5 * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
6 * ("Apple") in consideration of your agreement to the following terms, and your
7 * use, installation, modification or redistribution of this Apple software
8 * constitutes acceptance of these terms. If you do not agree with these terms,
9 * please do not use, install, modify or redistribute this Apple software.
10 *
11 * In consideration of your agreement to abide by the following terms, and subject
12 * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
13 * copyrights in this original Apple software (the "Apple Software"), to use,
14 * reproduce, modify and redistribute the Apple Software, with or without
15 * modifications, in source and/or binary forms; provided that if you redistribute
16 * the Apple Software in its entirety and without modifications, you must retain
17 * this notice and the following text and disclaimers in all such redistributions of
18 * the Apple Software. Neither the name, trademarks, service marks or logos of
19 * Apple Inc. may be used to endorse or promote products derived from the
20 * Apple Software without specific prior written permission from Apple. Except as
21 * expressly stated in this notice, no other rights or licenses, express or implied,
22 * are granted by Apple herein, including but not limited to any patent rights that
23 * may be infringed by your derivative works or by other works in which the Apple
24 * Software may be incorporated.
25 *
26 * The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
27 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
28 * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
30 * COMBINATION WITH YOUR PRODUCTS.
31 *
32 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
34 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
36 * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
37 * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
38 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 To build this tool, copy and paste the following into a command line:
41
42 OS X:
43 gcc dns-sd.c -o dns-sd
44
45 POSIX systems:
46 gcc dns-sd.c -o dns-sd -I../mDNSShared -ldns_sd
47
48 Windows:
49 cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
50 (may require that you run a Visual Studio script such as vsvars32.bat first)
51 */
52
53 // For testing changes to dnssd_clientstub.c, uncomment this line and the code will be compiled
54 // with an embedded copy of the client stub instead of linking the system library version at runtime.
55 // This also useful to work around link errors when you're working on an older version of Mac OS X,
56 // and trying to build a newer version of the "dns-sd" command which uses new API entry points that
57 // aren't in the system's /usr/lib/libSystem.dylib.
58 //#define TEST_NEW_CLIENTSTUB 1
59
60 #include <ctype.h>
61 #include <stdio.h> // For stdout, stderr
62 #include <stdlib.h> // For exit()
63 #include <string.h> // For strlen(), strcpy()
64 #include <errno.h> // For errno, EINTR
65 #include <time.h>
66 #include <sys/types.h> // For u_char
67
68 #ifdef _WIN32
69 #include <winsock2.h>
70 #include <ws2tcpip.h>
71 #include <Iphlpapi.h>
72 #include <process.h>
73 typedef int pid_t;
74 #define getpid _getpid
75 #define strcasecmp _stricmp
76 #define snprintf _snprintf
77 static const char kFilePathSep = '\\';
78 #ifndef HeapEnableTerminationOnCorruption
79 # define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
80 #endif
81 #if !defined(IFNAMSIZ)
82 #define IFNAMSIZ 16
83 #endif
84 #define if_nametoindex if_nametoindex_win
85 #define if_indextoname if_indextoname_win
86
87 typedef PCHAR (WINAPI * if_indextoname_funcptr_t)(ULONG index, PCHAR name);
88 typedef ULONG (WINAPI * if_nametoindex_funcptr_t)(PCSTR name);
89
90 unsigned if_nametoindex_win(const char *ifname)
91 {
92 HMODULE library;
93 unsigned index = 0;
94
95 // Try and load the IP helper library dll
96 if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
97 {
98 if_nametoindex_funcptr_t if_nametoindex_funcptr;
99
100 // On Vista and above there is a Posix like implementation of if_nametoindex
101 if ((if_nametoindex_funcptr = (if_nametoindex_funcptr_t) GetProcAddress(library, "if_nametoindex")) != NULL )
102 {
103 index = if_nametoindex_funcptr(ifname);
104 }
105
106 FreeLibrary(library);
107 }
108
109 return index;
110 }
111
112 char * if_indextoname_win( unsigned ifindex, char *ifname)
113 {
114 HMODULE library;
115 char * name = NULL;
116
117 // Try and load the IP helper library dll
118 if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
119 {
120 if_indextoname_funcptr_t if_indextoname_funcptr;
121
122 // On Vista and above there is a Posix like implementation of if_indextoname
123 if ((if_indextoname_funcptr = (if_indextoname_funcptr_t) GetProcAddress(library, "if_indextoname")) != NULL )
124 {
125 name = if_indextoname_funcptr(ifindex, ifname);
126 }
127
128 FreeLibrary(library);
129 }
130
131 return name;
132 }
133
134 static size_t _sa_len(const struct sockaddr *addr)
135 {
136 if (addr->sa_family == AF_INET) return (sizeof(struct sockaddr_in));
137 else if (addr->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6));
138 else return (sizeof(struct sockaddr));
139 }
140
141 # define SA_LEN(addr) (_sa_len(addr))
142
143 #else
144 #include <unistd.h> // For getopt() and optind
145 #include <netdb.h> // For getaddrinfo()
146 #include <sys/time.h> // For struct timeval
147 #include <sys/socket.h> // For AF_INET
148 #include <netinet/in.h> // For struct sockaddr_in()
149 #include <arpa/inet.h> // For inet_addr()
150 #include <net/if.h> // For if_nametoindex()
151 static const char kFilePathSep = '/';
152 // #ifndef NOT_HAVE_SA_LEN
153 // #define SA_LEN(addr) ((addr)->sa_len)
154 // #else
155 #define SA_LEN(addr) (((addr)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
156 // #endif
157 #endif
158
159 #if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
160 #define __APPLE_API_PRIVATE 1
161 #endif
162
163 // DNSServiceSetDispatchQueue is not supported on 10.6 & prior
164 #if !TEST_NEW_CLIENTSTUB && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ % 10) <= 1060)
165 #undef _DNS_SD_LIBDISPATCH
166 #endif
167 #include "dns_sd.h"
168 #include "ClientCommon.h"
169
170 #if TEST_NEW_CLIENTSTUB
171 #include "../mDNSShared/dnssd_ipc.c"
172 #include "../mDNSShared/dnssd_clientlib.c"
173 #include "../mDNSShared/dnssd_clientstub.c"
174 #endif
175
176 #if _DNS_SD_LIBDISPATCH
177 #include <dispatch/private.h>
178 #endif
179
180 //*************************************************************************************************************
181 // Globals
182
183 #define DS_FIXED_SIZE 4
184 typedef struct
185 {
186 unsigned short keyTag;
187 unsigned char alg;
188 unsigned char digestType;
189 unsigned char *digest;
190 } rdataDS;
191
192 #define DNSKEY_FIXED_SIZE 4
193 typedef struct
194 {
195 unsigned short flags;
196 unsigned char proto;
197 unsigned char alg;
198 unsigned char *data;
199 } rdataDNSKey;
200
201 //size of rdataRRSIG excluding signerName and signature (which are variable fields)
202 #define RRSIG_FIXED_SIZE 18
203 typedef struct
204 {
205 unsigned short typeCovered;
206 unsigned char alg;
207 unsigned char labels;
208 unsigned int origTTL;
209 unsigned int sigExpireTime;
210 unsigned int sigInceptTime;
211 unsigned short keyTag;
212 char signerName[256];
213 //unsigned char *signature
214 } rdataRRSig;
215
216 #define RR_TYPE_SIZE 16
217
218 typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
219
220 static int operation;
221 static uint32_t opinterface = kDNSServiceInterfaceIndexAny;
222 static DNSServiceRef client = NULL;
223 static DNSServiceRef client_pa = NULL; // DNSServiceRef for RegisterProxyAddressRecord
224 static DNSServiceRef sc1, sc2, sc3; // DNSServiceRefs for kDNSServiceFlagsShareConnection testing
225
226 static int num_printed;
227 static char addtest = 0;
228 static DNSRecordRef record = NULL;
229 static char myhinfoW[14] = "\002PC\012Windows XP";
230 static char myhinfoX[ 9] = "\003Mac\004OS X";
231 static char updatetest[3] = "\002AA";
232 static char bigNULL[8192]; // 8K is maximum rdata we support
233
234 #if _DNS_SD_LIBDISPATCH
235 dispatch_queue_t main_queue;
236 dispatch_source_t timer_source;
237 #endif
238
239 // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
240 #define LONG_TIME 100000000
241
242 static volatile int stopNow = 0;
243 static volatile int timeOut = LONG_TIME;
244
245 #if _DNS_SD_LIBDISPATCH
246 #define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E) \
247 if (main_queue && (E) == kDNSServiceErr_ServiceNotRunning) { fprintf(stderr, "Error code %d\n", (E)); exit(0); }
248 #else
249 #define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E)
250 #endif
251
252 //*************************************************************************************************************
253 // Supporting Utility Functions
254 static uint16_t GetRRClass(const char *s)
255 {
256 if (!strcasecmp(s, "IN"))
257 return kDNSServiceClass_IN;
258 else
259 return(atoi(s));
260 }
261
262 static uint16_t GetRRType(const char *s)
263 {
264 if (!strcasecmp(s, "A" )) return(kDNSServiceType_A);
265 else if (!strcasecmp(s, "NS" )) return(kDNSServiceType_NS);
266 else if (!strcasecmp(s, "MD" )) return(kDNSServiceType_MD);
267 else if (!strcasecmp(s, "MF" )) return(kDNSServiceType_MF);
268 else if (!strcasecmp(s, "CNAME" )) return(kDNSServiceType_CNAME);
269 else if (!strcasecmp(s, "SOA" )) return(kDNSServiceType_SOA);
270 else if (!strcasecmp(s, "MB" )) return(kDNSServiceType_MB);
271 else if (!strcasecmp(s, "MG" )) return(kDNSServiceType_MG);
272 else if (!strcasecmp(s, "MR" )) return(kDNSServiceType_MR);
273 else if (!strcasecmp(s, "NULL" )) return(kDNSServiceType_NULL);
274 else if (!strcasecmp(s, "WKS" )) return(kDNSServiceType_WKS);
275 else if (!strcasecmp(s, "PTR" )) return(kDNSServiceType_PTR);
276 else if (!strcasecmp(s, "HINFO" )) return(kDNSServiceType_HINFO);
277 else if (!strcasecmp(s, "MINFO" )) return(kDNSServiceType_MINFO);
278 else if (!strcasecmp(s, "MX" )) return(kDNSServiceType_MX);
279 else if (!strcasecmp(s, "TXT" )) return(kDNSServiceType_TXT);
280 else if (!strcasecmp(s, "RP" )) return(kDNSServiceType_RP);
281 else if (!strcasecmp(s, "AFSDB" )) return(kDNSServiceType_AFSDB);
282 else if (!strcasecmp(s, "X25" )) return(kDNSServiceType_X25);
283 else if (!strcasecmp(s, "ISDN" )) return(kDNSServiceType_ISDN);
284 else if (!strcasecmp(s, "RT" )) return(kDNSServiceType_RT);
285 else if (!strcasecmp(s, "NSAP" )) return(kDNSServiceType_NSAP);
286 else if (!strcasecmp(s, "NSAP_PTR")) return(kDNSServiceType_NSAP_PTR);
287 else if (!strcasecmp(s, "SIG" )) return(kDNSServiceType_SIG);
288 else if (!strcasecmp(s, "KEY" )) return(kDNSServiceType_KEY);
289 else if (!strcasecmp(s, "PX" )) return(kDNSServiceType_PX);
290 else if (!strcasecmp(s, "GPOS" )) return(kDNSServiceType_GPOS);
291 else if (!strcasecmp(s, "AAAA" )) return(kDNSServiceType_AAAA);
292 else if (!strcasecmp(s, "LOC" )) return(kDNSServiceType_LOC);
293 else if (!strcasecmp(s, "NXT" )) return(kDNSServiceType_NXT);
294 else if (!strcasecmp(s, "EID" )) return(kDNSServiceType_EID);
295 else if (!strcasecmp(s, "NIMLOC" )) return(kDNSServiceType_NIMLOC);
296 else if (!strcasecmp(s, "SRV" )) return(kDNSServiceType_SRV);
297 else if (!strcasecmp(s, "ATMA" )) return(kDNSServiceType_ATMA);
298 else if (!strcasecmp(s, "NAPTR" )) return(kDNSServiceType_NAPTR);
299 else if (!strcasecmp(s, "KX" )) return(kDNSServiceType_KX);
300 else if (!strcasecmp(s, "CERT" )) return(kDNSServiceType_CERT);
301 else if (!strcasecmp(s, "A6" )) return(kDNSServiceType_A6);
302 else if (!strcasecmp(s, "DNAME" )) return(kDNSServiceType_DNAME);
303 else if (!strcasecmp(s, "SINK" )) return(kDNSServiceType_SINK);
304 else if (!strcasecmp(s, "OPT" )) return(kDNSServiceType_OPT);
305 else if (!strcasecmp(s, "TKEY" )) return(kDNSServiceType_TKEY);
306 else if (!strcasecmp(s, "TSIG" )) return(kDNSServiceType_TSIG);
307 else if (!strcasecmp(s, "IXFR" )) return(kDNSServiceType_IXFR);
308 else if (!strcasecmp(s, "AXFR" )) return(kDNSServiceType_AXFR);
309 else if (!strcasecmp(s, "MAILB" )) return(kDNSServiceType_MAILB);
310 else if (!strcasecmp(s, "MAILA" )) return(kDNSServiceType_MAILA);
311 else if (!strcasecmp(s, "dnskey" )) return(kDNSServiceType_DNSKEY);
312 else if (!strcasecmp(s, "ds" )) return(kDNSServiceType_DS);
313 else if (!strcasecmp(s, "rrsig" )) return(kDNSServiceType_RRSIG);
314 else if (!strcasecmp(s, "nsec" )) return(kDNSServiceType_NSEC);
315 else if (!strcasecmp(s, "ANY" )) return(kDNSServiceType_ANY);
316 else return(atoi(s));
317 }
318
319 static char *DNSTypeName(unsigned short rr_type)
320 {
321 switch (rr_type)
322 {
323 case kDNSServiceType_A: return("Addr");
324 case kDNSServiceType_NS: return("NS");
325 case kDNSServiceType_MD: return("MD");
326 case kDNSServiceType_MF: return("MF");
327 case kDNSServiceType_CNAME: return("CNAME");
328 case kDNSServiceType_SOA: return("SOA");
329 case kDNSServiceType_MB: return("MB");
330 case kDNSServiceType_MG: return("MG");
331 case kDNSServiceType_MR: return("MR");
332 case kDNSServiceType_NULL: return("NULL");
333 case kDNSServiceType_WKS: return("WKS");
334 case kDNSServiceType_PTR: return("PTR");
335 case kDNSServiceType_HINFO: return("HINFO");
336 case kDNSServiceType_MINFO: return("MINFO");
337 case kDNSServiceType_MX: return("MX");
338 case kDNSServiceType_TXT: return("TXT");
339 case kDNSServiceType_RP: return("RP");
340 case kDNSServiceType_AFSDB: return("AFSDB");
341 case kDNSServiceType_X25: return("X25");
342 case kDNSServiceType_ISDN: return("ISDN");
343 case kDNSServiceType_RT: return("RT");
344 case kDNSServiceType_NSAP: return("NSAP");
345 case kDNSServiceType_NSAP_PTR: return("NSAP_PTR");
346 case kDNSServiceType_SIG: return("SIG");
347 case kDNSServiceType_KEY: return("KEY");
348 case kDNSServiceType_PX: return("PX");
349 case kDNSServiceType_GPOS: return("GPOS");
350 case kDNSServiceType_AAAA: return("AAAA");
351 case kDNSServiceType_LOC: return("LOC");
352 case kDNSServiceType_NXT: return("NXT");
353 case kDNSServiceType_EID: return("EID");
354 case kDNSServiceType_NIMLOC: return("NIMLOC");
355 case kDNSServiceType_SRV: return("SRV");
356 case kDNSServiceType_ATMA: return("ATMA");
357 case kDNSServiceType_NAPTR: return("NAPTR");
358 case kDNSServiceType_KX: return("KX");
359 case kDNSServiceType_CERT: return("CERT");
360 case kDNSServiceType_A6: return("A6");
361 case kDNSServiceType_DNAME: return("DNAME");
362 case kDNSServiceType_SINK: return("SINK");
363 case kDNSServiceType_OPT: return("OPT");
364 case kDNSServiceType_APL: return("APL");
365 case kDNSServiceType_DS: return("DS");
366 case kDNSServiceType_SSHFP: return("SSHFP");
367 case kDNSServiceType_IPSECKEY: return("IPSECKEY");
368 case kDNSServiceType_RRSIG: return("RRSIG");
369 case kDNSServiceType_NSEC: return("NSEC");
370 case kDNSServiceType_DNSKEY: return("DNSKEY");
371 case kDNSServiceType_DHCID: return("DHCID");
372 case kDNSServiceType_NSEC3: return("NSEC3");
373 case kDNSServiceType_NSEC3PARAM: return("NSEC3PARAM");
374 case kDNSServiceType_HIP: return("HIP");
375 case kDNSServiceType_SPF: return("SPF");
376 case kDNSServiceType_UINFO: return("UINFO");
377 case kDNSServiceType_UID: return("UID");
378 case kDNSServiceType_GID: return("GID");
379 case kDNSServiceType_UNSPEC: return("UNSPEC");
380 case kDNSServiceType_TKEY: return("TKEY");
381 case kDNSServiceType_TSIG: return("TSIG");
382 case kDNSServiceType_IXFR: return("IXFR");
383 case kDNSServiceType_AXFR: return("AXFR");
384 case kDNSServiceType_MAILB: return("MAILB");
385 case kDNSServiceType_MAILA: return("MAILA");
386 case kDNSServiceType_ANY: return("ANY");
387 default:
388 {
389 static char buffer[RR_TYPE_SIZE];
390 snprintf(buffer, sizeof(buffer), "TYPE%d", rr_type);
391 return(buffer);
392 }
393 }
394 }
395
396 static unsigned short swap16(unsigned short x)
397 {
398 unsigned char *ptr = (unsigned char *)&x;
399 return (unsigned short)((unsigned short)ptr[0] << 8 | ptr[1]);
400 }
401
402 static unsigned int swap32(unsigned int x)
403 {
404 unsigned char *ptr = (unsigned char *)&x;
405 return (unsigned int)((unsigned int)ptr[0] << 24 | (unsigned int)ptr[1] << 16 | (unsigned int)ptr[2] << 8 | ptr[3]);
406 }
407 static unsigned int keytag(unsigned char *key, unsigned int keysize)
408 {
409 unsigned long ac;
410 unsigned int i;
411
412 for (ac = 0, i = 0; i < keysize; ++i)
413 ac += (i & 1) ? key[i] : key[i] << 8;
414 ac += (ac >> 16) & 0xFFFF;
415 return ac & 0xFFFF;
416 }
417
418 static void base64Encode(char *buffer, int buflen, void *rdata, unsigned int rdlen)
419 {
420 #if _DNS_SD_LIBDISPATCH
421 const void *result = NULL;
422 size_t size;
423 dispatch_data_t src_data = NULL, dest_data = NULL, null_str = NULL, data = NULL, map = NULL;
424
425 src_data = dispatch_data_create(rdata, rdlen, dispatch_get_global_queue(0, 0), ^{});
426 if (!src_data)
427 goto done;
428
429 dest_data = dispatch_data_create_with_transform(src_data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64);
430 if (!dest_data)
431 goto done;
432
433 null_str = dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{});
434 if (!null_str)
435 goto done;
436
437 data = dispatch_data_create_concat(dest_data, null_str);
438 if (!data)
439 goto done;
440
441 map = dispatch_data_create_map(data, &result, &size);
442 if (!map)
443 goto done;
444
445 snprintf(buffer, buflen, " %s", (char *)result);
446
447 done:
448 if (src_data) dispatch_release(src_data);
449 if (dest_data) dispatch_release(dest_data);
450 if (data) dispatch_release(data);
451 if (null_str) dispatch_release(null_str);
452 if (map) dispatch_release(map);
453 return;
454 #else //_DNS_SD_LIBDISPATCH
455 snprintf(buffer, buflen, " %s", ".");
456 return;
457 #endif //_DNS_SD_LIBDISPATCH
458 }
459
460 static DNSServiceProtocol GetProtocol(const char *s)
461 {
462 if (!strcasecmp(s, "v4" )) return(kDNSServiceProtocol_IPv4);
463 else if (!strcasecmp(s, "v6" )) return(kDNSServiceProtocol_IPv6);
464 else if (!strcasecmp(s, "v4v6" )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
465 else if (!strcasecmp(s, "v6v4" )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
466 else if (!strcasecmp(s, "udp" )) return(kDNSServiceProtocol_UDP);
467 else if (!strcasecmp(s, "tcp" )) return(kDNSServiceProtocol_TCP);
468 else if (!strcasecmp(s, "udptcp" )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
469 else if (!strcasecmp(s, "tcpudp" )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
470 else return(atoi(s));
471 }
472
473
474 //*************************************************************************************************************
475 // Sample callback functions for each of the operation types
476
477 #define printtimestamp() printtimestamp_F(stdout)
478
479 static void printtimestamp_F(FILE *outstream)
480 {
481 struct tm tm;
482 int ms;
483 static char date[16];
484 static char new_date[16];
485 #ifdef _WIN32
486 SYSTEMTIME sysTime;
487 time_t uct = time(NULL);
488 tm = *localtime(&uct);
489 GetLocalTime(&sysTime);
490 ms = sysTime.wMilliseconds;
491 #else
492 struct timeval tv;
493 gettimeofday(&tv, NULL);
494 localtime_r((time_t*)&tv.tv_sec, &tm);
495 ms = tv.tv_usec/1000;
496 #endif
497 strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
498 if (strncmp(date, new_date, sizeof(new_date)))
499 {
500 fprintf(outstream, "DATE: ---%s---\n", new_date); //display date only if it has changed
501 strncpy(date, new_date, sizeof(date));
502 }
503 fprintf(outstream, "%2d:%02d:%02d.%03d ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
504 }
505
506 // formating time to RFC 4034 format
507 static void FormatTime(unsigned long te, unsigned char *buf, int bufsize)
508 {
509 struct tm tmTime;
510 #ifdef _WIN32
511 __time32_t t = (__time32_t) te;
512 _gmtime32_s(&tmTime, &t);
513 #else
514 // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
515 // gmtime_r first and then use strftime
516 time_t t = (time_t)te;
517 gmtime_r(&t, &tmTime);
518 #endif
519 strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
520 }
521
522 static void print_usage(const char *arg0, int print_all)
523 {
524 // Print the commonly used command line options. These are listed in "the order they have been in historically".
525 fprintf(stderr, "%s -E (Enumerate recommended registration domains)\n", arg0);
526 fprintf(stderr, "%s -F (Enumerate recommended browsing domains)\n", arg0);
527 fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...] (Register a service)\n", arg0);
528 fprintf(stderr, "%s -B <Type> <Domain> (Browse for service instances)\n", arg0);
529 fprintf(stderr, "%s -L <Name> <Type> <Domain> (Resolve a service instance)\n", arg0);
530 fprintf(stderr, "%s -Q <name> <rrtype> <rrclass> (Generic query for any record type)\n", arg0);
531 fprintf(stderr, "%s -Z <Type> <Domain> (Output results in Zone File format)\n", arg0);
532 fprintf(stderr, "%s -G v4/v6/v4v6 <name> (Get address information for hostname)\n", arg0);
533 fprintf(stderr, "%s -H (Print usage for complete command list)\n", arg0);
534 fprintf(stderr, "%s -V (Get version of currently running daemon / system service)\n", arg0);
535
536 if (print_all) // Print all available options for dns-sd tool. Keep these in alphabetical order for easier maintenance.
537 {
538 fprintf(stderr, "\n");
539 fprintf(stderr, "%s -A (Test Adding/Updating/Deleting a record)\n", arg0);
540 fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass> (Query; reconfirming each result)\n", arg0);
541 fprintf(stderr, "%s -D <name> <rrtype> <rrclass>(Validate query for any record type with DNSSEC)\n", arg0);
542 fprintf(stderr, "%s -I (Test registering and then immediately updating TXT record)\n", arg0);
543 fprintf(stderr, "%s -N (Test adding a large NULL record)\n", arg0);
544 fprintf(stderr, "%s -M (Test creating a registration with multiple TXT records)\n", arg0);
545 fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Proxy)\n", arg0);
546 fprintf(stderr, "%s -S (Test multiple operations on a shared socket)\n", arg0);
547 fprintf(stderr, "%s -T (Test creating a large TXT record)\n", arg0);
548 fprintf(stderr, "%s -U (Test updating a TXT record)\n", arg0);
549 fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL> (NAT Port Mapping)\n", arg0);
550 fprintf(stderr, "%s -ble (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
551 fprintf(stderr, "%s -g v4/v6/v4v6 <name> (Validate address info for hostname with DNSSEC)\n", arg0);
552 fprintf(stderr, "%s -i <Interface> (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
553 fprintf(stderr, "%s -includep2p (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
554 fprintf(stderr, "%s -includeAWDL (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
555 fprintf(stderr, "%s -intermediates (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
556 fprintf(stderr, "%s -ku (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
557 fprintf(stderr, "%s -lo (Run dns-sd cmd using local only interface)\n", arg0);
558 fprintf(stderr, "%s -optional (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
559 fprintf(stderr, "%s -p2p (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
560 fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Equivalent to -Q with kDNSServiceFlagsSuppressUnusable set)\n", arg0);
561 fprintf(stderr, "%s -tc (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
562 fprintf(stderr, "%s -test (Run basic API input range tests)\n", arg0);
563 fprintf(stderr, "%s -t1 (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
564 fprintf(stderr, "%s -tFinder (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
565 fprintf(stderr, "%s -timeout (Set kDNSServiceFlagsTimeout flag)\n", arg0);
566 fprintf(stderr, "%s -unicastResponse (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
567 fprintf(stderr, "%s -autoTrigger (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
568 }
569 }
570
571 #define DomainMsg(X) (((X) &kDNSServiceFlagsDefault) ? "(Default)" : \
572 ((X) &kDNSServiceFlagsAdd) ? "Added" : "Removed")
573
574 #define MAX_LABELS 128
575
576 static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex,
577 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
578 {
579 DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
580 int labels = 0, depth = 0, i, initial = 0;
581 char text[64];
582 const char *label[MAX_LABELS];
583
584 (void)sdref; // Unused
585 (void)ifIndex; // Unused
586 (void)context; // Unused
587 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
588
589 // 1. Print the header
590 if (num_printed++ == 0) printf("Timestamp Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
591 printtimestamp();
592 if (errorCode)
593 printf("Error code %d\n", errorCode);
594 else if (!*replyDomain)
595 printf("Error: No reply domain\n");
596 else
597 {
598 printf("%-10s", DomainMsg(flags));
599 printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
600 if (partialflags) printf("Flags: %4X ", partialflags);
601 else printf(" ");
602
603 // 2. Count the labels
604 while (replyDomain && *replyDomain && labels < MAX_LABELS)
605 {
606 label[labels++] = replyDomain;
607 replyDomain = GetNextLabel(replyDomain, text);
608 }
609
610 // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
611 if (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
612 else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
613 else initial = 1;
614 labels -= initial;
615
616 // 4. Print the initial one-, two- or three-label clump
617 for (i=0; i<initial; i++)
618 {
619 GetNextLabel(label[labels+i], text);
620 if (i>0) printf(".");
621 printf("%s", text);
622 }
623 printf("\n");
624
625 // 5. Print the remainder of the hierarchy
626 for (depth=0; depth<labels; depth++)
627 {
628 printf(" ");
629 for (i=0; i<=depth; i++) printf("- ");
630 GetNextLabel(label[labels-1-depth], text);
631 printf("> %s\n", text);
632 }
633 }
634
635 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
636 }
637
638 static int CopyLabels(char *dst, const char *lim, const char **srcp, int labels)
639 {
640 const char *src = *srcp;
641 while (*src != '.' || --labels > 0)
642 {
643 if (*src == '\\') *dst++ = *src++; // Make sure "\." doesn't confuse us
644 if (!*src || dst >= lim) return -1;
645 *dst++ = *src++;
646 if (!*src || dst >= lim) return -1;
647 }
648 *dst++ = 0;
649 *srcp = src + 1; // skip over final dot
650 return 0;
651 }
652
653 static void DNSSD_API zonedata_resolve(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
654 const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txt, void *context)
655 {
656 union { uint16_t s; u_char b[2]; } port = { opaqueport };
657 uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
658
659 const char *p = fullname;
660 char n[kDNSServiceMaxDomainName];
661 char t[kDNSServiceMaxDomainName];
662
663 const unsigned char *max = txt + txtLen;
664
665 (void)sdref; // Unused
666 (void)ifIndex; // Unused
667 (void)context; // Unused
668
669 //if (!(flags & kDNSServiceFlagsAdd)) return;
670 if (errorCode) { printf("Error code %d\n", errorCode); return; }
671
672 if (CopyLabels(n, n + kDNSServiceMaxDomainName, &p, 3)) return; // Fetch name+type
673 p = fullname;
674 if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 1)) return; // Skip first label
675 if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 2)) return; // Fetch next two labels (service type)
676
677 if (num_printed++ == 0)
678 {
679 printf("\n");
680 printf("; To direct clients to browse a different domain, substitute that domain in place of '@'\n");
681 printf("%-47s PTR %s\n", "lb._dns-sd._udp", "@");
682 printf("\n");
683 printf("; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.\n");
684 printf("; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local\n");
685 printf("; names with the correct fully-qualified (unicast) domain name of the target host offering the service.\n");
686 }
687
688 printf("\n");
689 printf("%-47s PTR %s\n", t, n);
690 printf("%-47s SRV 0 0 %d %s ; Replace with unicast FQDN of target host\n", n, PortAsNumber, hosttarget);
691 printf("%-47s TXT ", n);
692
693 while (txt < max)
694 {
695 const unsigned char *const end = txt + 1 + txt[0];
696 txt++; // Skip over length byte
697 printf(" \"");
698 while (txt<end)
699 {
700 if (*txt == '\\' || *txt == '\"') printf("\\");
701 printf("%c", *txt++);
702 }
703 printf("\"");
704 }
705 printf("\n");
706
707 DNSServiceRefDeallocate(sdref);
708 free(context);
709
710 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
711 }
712
713 static void DNSSD_API zonedata_browse(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
714 const char *replyName, const char *replyType, const char *replyDomain, void *context)
715 {
716 DNSServiceRef *newref;
717
718 (void)sdref; // Unused
719 (void)context; // Unused
720 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
721
722 if (!(flags & kDNSServiceFlagsAdd)) return;
723 if (errorCode) { printf("Error code %d\n", errorCode); return; }
724
725 newref = malloc(sizeof(*newref));
726 *newref = client;
727 DNSServiceResolve(newref, kDNSServiceFlagsShareConnection, ifIndex, replyName, replyType, replyDomain, zonedata_resolve, newref);
728 }
729
730 static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
731 const char *replyName, const char *replyType, const char *replyDomain, void *context)
732 {
733 char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
734 (void)sdref; // Unused
735 (void)context; // Unused
736 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
737
738 if (num_printed++ == 0) printf("Timestamp A/R Flags if %-20s %-20s %s\n", "Domain", "Service Type", "Instance Name");
739 printtimestamp();
740 if (errorCode)
741 printf("Error code %d\n", errorCode);
742 else
743 printf("%s %8X %3d %-20s %-20s %s\n",
744 op, flags, ifIndex, replyDomain, replyType, replyName);
745 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
746
747 // To test selective cancellation of operations of shared sockets,
748 // cancel the current operation when we've got a multiple of five results
749 //if (operation == 'S' && num_printed % 5 == 0) DNSServiceRefDeallocate(sdref);
750 }
751
752 static void ShowTXTRecord(uint16_t txtLen, const unsigned char *txtRecord)
753 {
754 const unsigned char *ptr = txtRecord;
755 const unsigned char *max = txtRecord + txtLen;
756 while (ptr < max)
757 {
758 const unsigned char *const end = ptr + 1 + ptr[0];
759 if (end > max) { printf("<< invalid data >>"); break; }
760 if (++ptr < end) printf(" "); // As long as string is non-empty, begin with a space
761 while (ptr<end)
762 {
763 // We'd like the output to be shell-friendly, so that it can be copied and pasted unchanged into a "dns-sd -R" command.
764 // However, this is trickier than it seems. Enclosing a string in double quotes doesn't necessarily make it
765 // shell-safe, because shells still expand variables like $foo even when they appear inside quoted strings.
766 // Enclosing a string in single quotes is better, but when using single quotes even backslash escapes are ignored,
767 // meaning there's simply no way to represent a single quote (or apostrophe) inside a single-quoted string.
768 // The only remaining solution is not to surround the string with quotes at all, but instead to use backslash
769 // escapes to encode spaces and all other known shell metacharacters.
770 // (If we've missed any known shell metacharacters, please let us know.)
771 // In addition, non-printing ascii codes (0-31) are displayed as \xHH, using a two-digit hex value.
772 // Because '\' is itself a shell metacharacter (the shell escape character), it has to be escaped as "\\" to survive
773 // the round-trip to the shell and back. This means that a single '\' is represented here as EIGHT backslashes:
774 // The C compiler eats half of them, resulting in four appearing in the output.
775 // The shell parses those four as a pair of "\\" sequences, passing two backslashes to the "dns-sd -R" command.
776 // The "dns-sd -R" command interprets this single "\\" pair as an escaped literal backslash. Sigh.
777 if (strchr(" &;`'\"|*?~<>^()[]{}$", *ptr)) printf("\\");
778 if (*ptr == '\\') printf("\\\\\\\\");
779 else if (*ptr >= ' ' ) printf("%c", *ptr);
780 else printf("\\\\x%02X", *ptr);
781 ptr++;
782 }
783 }
784 }
785
786 static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
787 const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txtRecord, void *context)
788 {
789 union { uint16_t s; u_char b[2]; } port = { opaqueport };
790 uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
791
792 (void)sdref; // Unused
793 (void)ifIndex; // Unused
794 (void)context; // Unused
795 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
796
797 printtimestamp();
798
799 printf("%s ", fullname);
800
801 if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record");
802 else if (errorCode) printf("error code %d\n", errorCode);
803 else printf("can be reached at %s:%u (interface %d)", hosttarget, PortAsNumber, ifIndex);
804
805 if (flags) printf(" Flags: %X", flags);
806
807 // Don't show degenerate TXT records containing nothing but a single empty string
808 if (!errorCode && txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); }
809
810 printf("\n");
811
812 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
813 }
814
815 static void myTimerCallBack(void)
816 {
817 DNSServiceErrorType err = kDNSServiceErr_Unknown;
818
819 switch (operation)
820 {
821 case 'A':
822 {
823 switch (addtest)
824 {
825 case 0: printf("Adding Test HINFO record\n");
826 err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_HINFO, sizeof(myhinfoW), &myhinfoW[0], 0);
827 addtest = 1;
828 break;
829 case 1: printf("Updating Test HINFO record\n");
830 err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 0);
831 addtest = 2;
832 break;
833 case 2: printf("Removing Test HINFO record\n");
834 err = DNSServiceRemoveRecord(client, record, 0);
835 addtest = 0;
836 break;
837 }
838 }
839 break;
840
841 case 'U':
842 {
843 if (updatetest[1] != 'Z') updatetest[1]++;
844 else updatetest[1] = 'A';
845 // The following line toggles the string length between 1 and 2 characters.
846 updatetest[0] = 3 - updatetest[0];
847 updatetest[2] = updatetest[1];
848 printtimestamp();
849 printf("Updating Test TXT record to %c\n", updatetest[1]);
850 err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0);
851 }
852 break;
853
854 case 'N':
855 {
856 printf("Adding big NULL record\n");
857 err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
858 if (err) printf("Failed: %d\n", err);else printf("Succeeded\n");
859 timeOut = LONG_TIME;
860 #if _DNS_SD_LIBDISPATCH
861 if (timer_source)
862 dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
863 (uint64_t)timeOut * NSEC_PER_SEC, 0);
864 #endif
865 }
866 break;
867 }
868
869 if (err != kDNSServiceErr_NoError)
870 {
871 fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err);
872 stopNow = 1;
873 }
874 }
875
876 static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
877 const char *name, const char *regtype, const char *domain, void *context)
878 {
879 (void)sdref; // Unused
880 (void)flags; // Unused
881 (void)context; // Unused
882 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
883
884 printtimestamp();
885 printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
886
887 if (errorCode == kDNSServiceErr_NoError)
888 {
889 if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n");
890 else printf("Name registration removed\n");
891 if (operation == 'A' || operation == 'U' || operation == 'N')
892 {
893 timeOut = 5;
894 #if _DNS_SD_LIBDISPATCH
895 if (timer_source)
896 dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
897 (uint64_t)timeOut * NSEC_PER_SEC, 0);
898 #endif
899 }
900 }
901 else if (errorCode == kDNSServiceErr_NameConflict)
902 {
903 printf("Name in use, please choose another\n");
904 exit(-1);
905 }
906 else
907 printf("Error %d\n", errorCode);
908
909 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
910 }
911
912 // Output the wire-format domainname pointed to by rd
913 static int snprintd(char *p, int max, const unsigned char **rd)
914 {
915 const char *const buf = p;
916 const char *const end = p + max;
917 while (**rd)
918 {
919 p += snprintf(p, end-p, "%.*s.", **rd, *rd+1);
920 *rd += 1 + **rd;
921 }
922 *rd += 1; // Advance over the final zero byte
923 return(p-buf);
924 }
925
926 static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, char *p, unsigned const char *rd, uint16_t rdlen)
927 {
928 int rdb_size = 1000;
929 switch (rrtype)
930 {
931 case kDNSServiceType_DS:
932 {
933 unsigned char *ptr;
934 int i;
935 rdataDS *rrds = (rdataDS *)rd;
936 p += snprintf(p, rdb + rdb_size - p, "%d %d %d ",
937 rrds->alg, swap16(rrds->keyTag), rrds->digestType);
938 ptr = (unsigned char *)(rd + DS_FIXED_SIZE);
939 for (i = 0; i < (rdlen - DS_FIXED_SIZE); i++)
940 p += snprintf(p, rdb + rdb_size - p, "%x", ptr[i]);
941 break;
942 }
943
944 case kDNSServiceType_DNSKEY:
945 {
946 rdataDNSKey *rrkey = (rdataDNSKey *)rd;
947 p += snprintf(p, rdb + rdb_size - p, "%d %d %d %u", swap16(rrkey->flags), rrkey->proto,
948 rrkey->alg, (unsigned int)keytag((unsigned char *)rrkey, rdlen));
949 base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + DNSKEY_FIXED_SIZE), rdlen - DNSKEY_FIXED_SIZE);
950 break;
951 }
952
953 case kDNSServiceType_NSEC:
954 {
955 unsigned char *next = (unsigned char *)rd;
956 int len, bitmaplen;
957 int win, wlen, type;
958 unsigned char *bmap;
959 char *l = NULL;
960
961 l = p;
962 p += snprintd(p, rdb + rdb_size - p, &rd);
963 len = p - l + 1;
964
965 bitmaplen = rdlen - len;
966 bmap = (unsigned char *)((unsigned char *)next + len);
967
968 while (bitmaplen > 0)
969 {
970 int i;
971
972 if (bitmaplen < 3)
973 {
974 printf("Case NSEC: malformed nsec, bitmaplen %d short\n", bitmaplen);
975 break;
976 }
977
978 win = *bmap++;
979 wlen = *bmap++;
980 bitmaplen -= 2;
981 if (bitmaplen < wlen || wlen < 1 || wlen > 32)
982 {
983 printf("Case NSEC: malformed nsec, bitmaplen %d wlen %d\n", bitmaplen, wlen);
984 break;
985 }
986 if (win < 0 || win >= 256)
987 {
988 printf("Case NSEC: malformed nsec, bad window win %d\n", win);
989 break;
990 }
991 type = win * 256;
992 for (i = 0; i < wlen * 8; i++)
993 {
994 if (bmap[i>>3] & (128 >> (i&7)))
995 p += snprintf(p, rdb + rdb_size - p, " %s ", DNSTypeName(type + i));
996 }
997 bmap += wlen;
998 bitmaplen -= wlen;
999 }
1000 break;
1001 }
1002
1003 case kDNSServiceType_RRSIG:
1004 {
1005 rdataRRSig *rrsig = (rdataRRSig *)rd;
1006 unsigned char expTimeBuf[64];
1007 unsigned char inceptTimeBuf[64];
1008 unsigned long inceptClock;
1009 unsigned long expClock;
1010 const unsigned char *q = NULL;
1011 char *k = NULL;
1012 int len;
1013
1014 expClock = (unsigned long)swap32(rrsig->sigExpireTime);
1015 FormatTime(expClock, expTimeBuf, sizeof(expTimeBuf));
1016
1017 inceptClock = (unsigned long)swap32(rrsig->sigInceptTime);
1018 FormatTime(inceptClock, inceptTimeBuf, sizeof(inceptTimeBuf));
1019
1020 p += snprintf(p, rdb + rdb_size - p, " %-7s %d %d %d %s %s %7d ",
1021 DNSTypeName(swap16(rrsig->typeCovered)), rrsig->alg, rrsig->labels, swap32(rrsig->origTTL),
1022 expTimeBuf, inceptTimeBuf, swap16(rrsig->keyTag));
1023
1024 q = (const unsigned char *)&rrsig->signerName;
1025 k = p;
1026 p += snprintd(p, rdb + rdb_size - p, &q);
1027 len = p - k + 1;
1028
1029 base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + len + RRSIG_FIXED_SIZE), rdlen - (len + RRSIG_FIXED_SIZE));
1030 break;
1031 }
1032 }
1033 return;
1034 }
1035
1036 static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
1037 const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
1038 {
1039 char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
1040 const unsigned char *rd = rdata;
1041 const unsigned char *end = (const unsigned char *) rdata + rdlen;
1042 char rdb[1000] = "0.0.0.0", *p = rdb;
1043 int unknowntype = 0;
1044 char dnssec_status[15] = "Unknown";
1045 char rr_type[RR_TYPE_SIZE];
1046 char rr_class[3];
1047 DNSServiceFlags check_flags = flags;//local flags for dnssec status checking
1048
1049 (void)sdref; // Unused
1050 (void)ifIndex; // Unused
1051 (void)ttl; // Unused
1052 (void)context; // Unused
1053 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1054
1055 if (num_printed++ == 0)
1056 {
1057 if (operation == 'D')
1058 printf("Timestamp A/R if %-30s%-6s%-7s%-18s Rdata\n", "Name", "Type", "Class", "DNSSECStatus");
1059 else
1060 printf("Timestamp A/R Flags if %-30s%-6s%-7s Rdata\n", "Name", "Type", "Class");
1061 }
1062 printtimestamp();
1063
1064 switch (rrclass)
1065 {
1066 case kDNSServiceClass_IN:
1067 strncpy(rr_class, "IN", sizeof(rr_class));
1068 break;
1069 default:
1070 snprintf(rr_class, sizeof(rr_class), "%d", rrclass);
1071 break;
1072 }
1073 strncpy(rr_type, DNSTypeName(rrtype), sizeof(rr_type));
1074
1075 if (!errorCode) //to avoid printing garbage in rdata
1076 {
1077 if (!(check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
1078 {
1079 switch (rrtype)
1080 {
1081 case kDNSServiceType_A:
1082 snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
1083 break;
1084
1085 case kDNSServiceType_NS:
1086 case kDNSServiceType_CNAME:
1087 case kDNSServiceType_PTR:
1088 case kDNSServiceType_DNAME:
1089 snprintd(p, sizeof(rdb), &rd);
1090 break;
1091
1092 case kDNSServiceType_SOA:
1093 p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // mname
1094 p += snprintf(p, rdb + sizeof(rdb) - p, " ");
1095 p += snprintd(p, rdb + sizeof(rdb) - p, &rd); // rname
1096 snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
1097 ntohl(((uint32_t*)rd)[0]), ntohl(((uint32_t*)rd)[1]), ntohl(((uint32_t*)rd)[2]), ntohl(((uint32_t*)rd)[3]), ntohl(((uint32_t*)rd)[4]));
1098 break;
1099
1100 case kDNSServiceType_AAAA:
1101 snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1102 rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
1103 rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
1104 break;
1105
1106 case kDNSServiceType_SRV:
1107 p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ", // priority, weight, port
1108 ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
1109 rd += 6;
1110 snprintd(p, rdb + sizeof(rdb) - p, &rd); // target host
1111 break;
1112
1113 case kDNSServiceType_DS:
1114 case kDNSServiceType_DNSKEY:
1115 case kDNSServiceType_NSEC:
1116 case kDNSServiceType_RRSIG:
1117 ParseDNSSECRecords(rrtype, rdb, p, rd, rdlen);
1118 break;
1119
1120 default:
1121 snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : "");
1122 unknowntype = 1;
1123 break;
1124 }
1125 }
1126 else
1127 {
1128 strncpy(rdb, "----", sizeof(rdb));
1129 //Clear all o/p bits, and then check for dnssec status
1130 check_flags &= ~kDNSServiceOutputFlags;
1131 if (check_flags & kDNSServiceFlagsSecure)
1132 strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
1133 else if (check_flags & kDNSServiceFlagsInsecure)
1134 strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
1135 else if (check_flags & kDNSServiceFlagsIndeterminate)
1136 strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
1137 else if (check_flags & kDNSServiceFlagsBogus)
1138 strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
1139 }
1140 }
1141
1142 if (operation == 'D')
1143 printf("%s%3d %-30s%-6s%-7s%-18s %s", op, ifIndex, fullname, rr_type, rr_class, dnssec_status, rdb);
1144 else
1145 printf("%s%6X%3d %-30s%-7s%-6s %s", op, flags, ifIndex, fullname, rr_type, rr_class, rdb);
1146 if (unknowntype)
1147 {
1148 while (rd < end)
1149 printf(" %02X", *rd++);
1150 }
1151 if (errorCode)
1152 {
1153 if (errorCode == kDNSServiceErr_NoSuchRecord)
1154 printf(" No Such Record");
1155 else if (errorCode == kDNSServiceErr_Timeout)
1156 {
1157 printf(" No Such Record\n");
1158 printf("Query Timed Out\n");
1159 exit(1);
1160 }
1161 }
1162 printf("\n");
1163
1164 if (operation == 'C')
1165 if (flags & kDNSServiceFlagsAdd)
1166 DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);
1167
1168 if (!(flags & kDNSServiceFlagsMoreComing))
1169 fflush(stdout);
1170 }
1171
1172 static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
1173 {
1174 (void)sdref; // Unused
1175 (void)flags; // Unused
1176 (void)context; // Unused
1177 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1178
1179 if (num_printed++ == 0) printf("Timestamp if %-20s %-15s %-15s %-15s %-6s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
1180 printtimestamp();
1181 if (errorCode && errorCode != kDNSServiceErr_DoubleNAT) printf("Error code %d\n", errorCode);
1182 else
1183 {
1184 const unsigned char *digits = (const unsigned char *)&publicAddress;
1185 char addr[256];
1186
1187 snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
1188 printf("%-4d %-20s %-15d %-15d %-15d %-6d%s\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl, errorCode == kDNSServiceErr_DoubleNAT ? " Double NAT" : "");
1189 }
1190
1191 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
1192 }
1193
1194 static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context)
1195 {
1196 char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
1197 char addr[256] = "";
1198 char dnssec_status[15] = "Unknown";
1199 DNSServiceFlags check_flags = flags;
1200 (void) sdref;
1201 (void) context;
1202
1203 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1204
1205 if (num_printed++ == 0)
1206 {
1207 if (operation == 'g')
1208 printf("Timestamp A/R if %-25s %-44s %-18s\n", "Hostname", "Address", "DNSSECStatus");
1209 else
1210 printf("Timestamp A/R Flags if %-38s %-44s %s\n", "Hostname", "Address", "TTL");
1211 }
1212 printtimestamp();
1213
1214 if (address && address->sa_family == AF_INET)
1215 {
1216 const unsigned char *b = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr;
1217 snprintf(addr, sizeof(addr), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
1218 }
1219 else if (address && address->sa_family == AF_INET6)
1220 {
1221 char if_name[IFNAMSIZ]; // Older Linux distributions don't define IF_NAMESIZE
1222 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)address;
1223 const unsigned char *b = (const unsigned char * )&s6->sin6_addr;
1224 if (!if_indextoname(s6->sin6_scope_id, if_name))
1225 snprintf(if_name, sizeof(if_name), "<%d>", s6->sin6_scope_id);
1226 snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
1227 b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
1228 b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF], if_name);
1229 }
1230
1231 //go through this only if you have a dnssec validation status
1232 if (!errorCode && (check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
1233 {
1234 strncpy(addr, "----", sizeof(addr));
1235 //Clear all o/p bits, and then check for dnssec status
1236 check_flags &= ~kDNSServiceOutputFlags;
1237 if (check_flags & kDNSServiceFlagsSecure)
1238 strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
1239 else if (check_flags & kDNSServiceFlagsInsecure)
1240 strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
1241 else if (check_flags & kDNSServiceFlagsIndeterminate)
1242 strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
1243 else if (check_flags & kDNSServiceFlagsBogus)
1244 strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
1245 }
1246
1247 if (operation == 'g')
1248 printf("%s%3d %-25s %-44s %-18s", op, interfaceIndex, hostname, addr, dnssec_status);
1249 else
1250 printf("%s%6X%3d %-38s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl);
1251 if (errorCode)
1252 {
1253 if (errorCode == kDNSServiceErr_NoSuchRecord)
1254 printf(" No Such Record");
1255 else
1256 printf(" Error code %d", errorCode);
1257 }
1258 printf("\n");
1259
1260 if (!(flags & kDNSServiceFlagsMoreComing))
1261 fflush(stdout);
1262 }
1263
1264 //*************************************************************************************************************
1265 // The main test function
1266
1267 static void HandleEvents(void)
1268 #if _DNS_SD_LIBDISPATCH
1269 {
1270 main_queue = dispatch_get_main_queue();
1271 if (client) DNSServiceSetDispatchQueue(client, main_queue);
1272 if (client_pa) DNSServiceSetDispatchQueue(client_pa, main_queue);
1273 if (operation == 'A' || operation == 'U' || operation == 'N')
1274 {
1275 timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_queue);
1276 if (timer_source)
1277 {
1278 // Start the timer "timeout" seconds into the future and repeat it every "timeout" seconds
1279 dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
1280 (uint64_t)timeOut * NSEC_PER_SEC, 0);
1281 dispatch_source_set_event_handler(timer_source, ^{myTimerCallBack();});
1282 dispatch_resume(timer_source);
1283 }
1284 }
1285 dispatch_main();
1286 }
1287 #else
1288 {
1289 int dns_sd_fd = client ? DNSServiceRefSockFD(client ) : -1;
1290 int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
1291 int nfds = dns_sd_fd + 1;
1292 fd_set readfds;
1293 struct timeval tv;
1294 int result;
1295
1296 if (dns_sd_fd2 > dns_sd_fd) nfds = dns_sd_fd2 + 1;
1297
1298 while (!stopNow)
1299 {
1300 // 1. Set up the fd_set as usual here.
1301 // This example client has no file descriptors of its own,
1302 // but a real application would call FD_SET to add them to the set here
1303 FD_ZERO(&readfds);
1304
1305 // 2. Add the fd for our client(s) to the fd_set
1306 if (client ) FD_SET(dns_sd_fd, &readfds);
1307 if (client_pa) FD_SET(dns_sd_fd2, &readfds);
1308
1309 // 3. Set up the timeout.
1310 tv.tv_sec = timeOut;
1311 tv.tv_usec = 0;
1312
1313 result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1314 if (result > 0)
1315 {
1316 DNSServiceErrorType err = kDNSServiceErr_NoError;
1317 if (client && FD_ISSET(dns_sd_fd, &readfds)) err = DNSServiceProcessResult(client );
1318 else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa);
1319 if (err) { printtimestamp_F(stderr); fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; }
1320 }
1321 else if (result == 0)
1322 myTimerCallBack();
1323 else
1324 {
1325 printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
1326 if (errno != EINTR) stopNow = 1;
1327 }
1328 }
1329 }
1330 #endif
1331
1332 static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
1333 // Return the recognized option in optstr and the option index of the next arg.
1334 #if NOT_HAVE_GETOPT
1335 {
1336 int i;
1337 for (i=1; i < argc; i++)
1338 {
1339 if (argv[i][0] == '-' && &argv[i][1] &&
1340 NULL != strchr(optstr, argv[i][1]))
1341 {
1342 *pOptInd = i + 1;
1343 return argv[i][1];
1344 }
1345 }
1346 return -1;
1347 }
1348 #else
1349 {
1350 int o = getopt(argc, (char *const *)argv, optstr);
1351 *pOptInd = optind;
1352 return o;
1353 }
1354 #endif
1355
1356 static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef rec, const DNSServiceFlags flags,
1357 DNSServiceErrorType errorCode, void *context)
1358 {
1359 char *name = (char *)context;
1360
1361 (void)service; // Unused
1362 (void)rec; // Unused
1363 (void)flags; // Unused
1364 EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1365
1366 printtimestamp();
1367 printf("Got a reply for record %s: ", name);
1368
1369 switch (errorCode)
1370 {
1371 case kDNSServiceErr_NoError: printf("Name now registered and active\n"); break;
1372 case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
1373 default: printf("Error %d\n", errorCode); break;
1374 }
1375 if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
1376 }
1377
1378 static void getip(const char *const name, struct sockaddr_storage *result)
1379 {
1380 struct addrinfo *addrs = NULL;
1381 int err = getaddrinfo(name, NULL, NULL, &addrs);
1382 if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name);
1383 else memcpy(result, addrs->ai_addr, SA_LEN(addrs->ai_addr));
1384 if (addrs) freeaddrinfo(addrs);
1385 }
1386
1387 static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip, DNSServiceFlags flags)
1388 {
1389 // Call getip() after the call DNSServiceCreateConnection().
1390 // On the Win32 platform, WinSock must be initialized for getip() to succeed.
1391 // Any DNSService* call will initialize WinSock for us, so we make sure
1392 // DNSServiceCreateConnection() is called before getip() is.
1393 struct sockaddr_storage hostaddr;
1394 memset(&hostaddr, 0, sizeof(hostaddr));
1395 getip(ip, &hostaddr);
1396 flags |= kDNSServiceFlagsUnique;
1397 if (hostaddr.ss_family == AF_INET)
1398 return(DNSServiceRegisterRecord(sdref, &record, flags, opinterface, host,
1399 kDNSServiceType_A, kDNSServiceClass_IN, 4, &((struct sockaddr_in *)&hostaddr)->sin_addr, 240, MyRegisterRecordCallback, (void*)host));
1400 else if (hostaddr.ss_family == AF_INET6)
1401 return(DNSServiceRegisterRecord(sdref, &record, flags, opinterface, host,
1402 kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &((struct sockaddr_in6*)&hostaddr)->sin6_addr, 240, MyRegisterRecordCallback, (void*)host));
1403 else return(kDNSServiceErr_BadParam);
1404 }
1405
1406 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0' ) : \
1407 ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) : \
1408 ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : 0)
1409
1410 #define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
1411
1412 static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
1413 const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv, DNSServiceFlags flags)
1414 {
1415 uint16_t PortAsNumber = atoi(port);
1416 Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
1417 unsigned char txt[2048] = "";
1418 unsigned char *ptr = txt;
1419 int i;
1420
1421 if (nam[0] == '.' && nam[1] == 0) nam = ""; // We allow '.' on the command line as a synonym for empty string
1422 if (dom[0] == '.' && dom[1] == 0) dom = ""; // We allow '.' on the command line as a synonym for empty string
1423
1424 printf("Registering Service %s.%s%s%s", nam[0] ? nam : "<<Default>>", typ, dom[0] ? "." : "", dom);
1425 if (host && *host) printf(" host %s", host);
1426 printf(" port %s", port);
1427
1428 if (argc)
1429 {
1430 for (i = 0; i < argc; i++)
1431 {
1432 const char *p = argv[i];
1433 *ptr = 0;
1434 while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
1435 {
1436 if (p[0] != '\\' || p[1] == 0) { ptr[++*ptr] = *p; p+=1; }
1437 else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; }
1438 else { ptr[++*ptr] = p[1]; p+=2; }
1439 }
1440 ptr += 1 + *ptr;
1441 }
1442 printf(" TXT");
1443 ShowTXTRecord(ptr-txt, txt);
1444 }
1445 printf("\n");
1446
1447 //flags |= kDNSServiceFlagsAllowRemoteQuery;
1448 //flags |= kDNSServiceFlagsNoAutoRename;
1449
1450 return(DNSServiceRegister(sdref, flags, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, (uint16_t) (ptr-txt), txt, reg_reply, NULL));
1451 }
1452
1453 #define TypeBufferSize 80
1454 static char *gettype(char *buffer, char *typ)
1455 {
1456 if (!typ || !*typ || (typ[0] == '.' && typ[1] == 0)) typ = "_http._tcp";
1457 if (!strchr(typ, '.')) { snprintf(buffer, TypeBufferSize, "%s._tcp", typ); typ = buffer; }
1458 return(typ);
1459 }
1460
1461 // Do some basic tests to verify API handles > 63 byte strings gracefully with
1462 // a returned error code.
1463
1464 #define STRING_64_BYTES "_123456789012345678901234567890123456789012345678901234567890123"
1465
1466 static int API_string_limit_test()
1467 {
1468 const char * regtype;
1469 DNSServiceRef sdRef = NULL;
1470 const char * longHost = STRING_64_BYTES ".local";
1471 const char * longDomain = "hostname." STRING_64_BYTES;
1472
1473 printf("Testing for error returns when various strings are > 63 bytes.\n");
1474
1475 printf("DNSServiceGetAddrInfo(), hostname = %s\n", longHost);
1476 if (DNSServiceGetAddrInfo(&sdRef, 0, 0, 0, longHost, addrinfo_reply, 0) == 0)
1477 {
1478 printf("DNSServiceGetAddrInfo(): expected error return\n");
1479 return 1;
1480 };
1481
1482 printf("DNSServiceGetAddrInfo(), hostname = %s\n", longDomain);
1483 if (DNSServiceGetAddrInfo(&sdRef, 0, 0, 0, longDomain, addrinfo_reply, 0) == 0)
1484 {
1485 printf("DNSServiceGetAddrInfo(): expected error return\n");
1486 return 1;
1487 };
1488
1489 printf("DNSServiceResolve(), name = %s\n", STRING_64_BYTES);
1490 if (DNSServiceResolve(&sdRef, 0, 0, STRING_64_BYTES, "_test._tcp", "local", resolve_reply, NULL) == 0)
1491 {
1492 printf("DNSServiceResolve(): expected error return\n");
1493 return 1;
1494 };
1495
1496 regtype = STRING_64_BYTES "._tcp";
1497 printf("DNSServiceResolve(), regtype = %s\n", regtype);
1498 if (DNSServiceResolve(&sdRef, 0, 0, "instanceName", regtype, "local", resolve_reply, NULL) == 0)
1499 {
1500 printf("DNSServiceResolve(): expected error return\n");
1501 return 1;
1502 };
1503
1504 printf("DNSServiceResolve(), domain = %s\n", STRING_64_BYTES);
1505 if (DNSServiceResolve(&sdRef, 0, 0, "instanceName", "_test._tcp", STRING_64_BYTES, resolve_reply, NULL) == 0)
1506 {
1507 printf("DNSServiceResolve(): expected error return\n");
1508 return 1;
1509 };
1510
1511 printf("Testing for error returns when various strings are > 63 bytes: PASSED\n");
1512 return 0;
1513 }
1514
1515 // local prototypes for routines that don't have prototypes in dns_sd.h
1516 #if APPLE_OSX_mDNSResponder
1517 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
1518 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid);
1519 #endif
1520
1521 static int API_NULL_input_test()
1522 {
1523 printf("Running basic API input range tests with all parameters set to 0:\n");
1524
1525 // Test that API's handle NULL pointers by returning an error when appropriate.
1526 printf("DNSServiceRefSockFD()\n");
1527 if (DNSServiceRefSockFD(0) != -1)
1528 {
1529 printf("DNSServiceRefSockFD(): expected dnssd_InvalidSocket return\n");
1530 return 1;
1531 };
1532
1533 printf("DNSServiceProcessResult()\n");
1534 if (DNSServiceProcessResult(0) == 0)
1535 {
1536 printf("DNSServiceProcessResult(): expected error return\n");
1537 return 1;
1538 };
1539
1540 // no return value, just verify it doesn't crash
1541 printf("DNSServiceRefDeallocate()\n");
1542 DNSServiceRefDeallocate(0);
1543
1544 printf("DNSServiceGetProperty()\n");
1545 if (DNSServiceGetProperty(0, 0, 0) == 0)
1546 {
1547 printf("DNSServiceGetProperty(): expected error return\n");
1548 return 1;
1549 };
1550
1551 printf("DNSServiceResolve()\n");
1552 if (DNSServiceResolve(0, 0, 0, 0, 0, 0, 0, 0) == 0)
1553 {
1554 printf("DNSServiceResolve(): expected error return\n");
1555 return 1;
1556 };
1557
1558 printf("DNSServiceQueryRecord()\n");
1559 if (DNSServiceQueryRecord(0, 0, 0, 0, 0, 0, 0, 0) == 0)
1560 {
1561 printf("DNSServiceQueryRecord(): expected error return\n");
1562 return 1;
1563 };
1564
1565 printf("DNSServiceGetAddrInfo()\n");
1566 if (DNSServiceGetAddrInfo(0, 0, 0, 0, 0, 0, 0) == 0)
1567 {
1568 printf("DNSServiceGetAddrInfo(): expected error return\n");
1569 return 1;
1570 };
1571
1572 printf("DNSServiceBrowse()\n");
1573 if (DNSServiceBrowse(0, 0, 0, 0, 0, 0, 0) == 0)
1574 {
1575 printf("DNSServiceBrowse(): expected error return\n");
1576 return 1;
1577 };
1578
1579 #if APPLE_OSX_mDNSResponder
1580 printf("DNSServiceSetDefaultDomainForUser()\n");
1581 if (DNSServiceSetDefaultDomainForUser(0, 0) == 0)
1582 {
1583 printf("DNSServiceSetDefaultDomainForUser(): expected error return\n");
1584 return 1;
1585 };
1586 #endif
1587
1588 printf("DNSServiceRegister()\n");
1589 if (DNSServiceRegister(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 0)
1590 {
1591 printf("DNSServiceRegister(): expected error return\n");
1592 return 1;
1593 };
1594
1595 printf("DNSServiceEnumerateDomains()\n");
1596 if (DNSServiceEnumerateDomains(0, 0, 0, 0, 0) == 0)
1597 {
1598 printf("DNSServiceEnumerateDomains(): expected error return\n");
1599 return 1;
1600 };
1601
1602 printf("DNSServiceCreateConnection()\n");
1603 if (DNSServiceCreateConnection(0) == 0)
1604 {
1605 printf("DNSServiceCreateConnection(): expected error return\n");
1606 return 1;
1607 };
1608
1609 #if APPLE_OSX_mDNSResponder
1610 printf("DNSServiceCreateDelegateConnection()\n");
1611 if (DNSServiceCreateDelegateConnection(0, 0, 0) == 0)
1612 {
1613 printf("DNSServiceCreateDelegateConnection(): expected error return\n");
1614 return 1;
1615 };
1616 #endif
1617
1618 printf("DNSServiceRegisterRecord()\n");
1619 if (DNSServiceRegisterRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 0)
1620 {
1621 printf("DNSServiceRegisterRecord(): expected error return\n");
1622 return 1;
1623 };
1624
1625 printf("DNSServiceAddRecord()\n");
1626 if (DNSServiceAddRecord(0, 0, 0, 0, 0, 0, 0) == 0)
1627 {
1628 printf("DNSServiceAddRecord(): expected error return\n");
1629 return 1;
1630 };
1631
1632 printf("DNSServiceUpdateRecord()\n");
1633 if (DNSServiceUpdateRecord(0, 0, 0, 0, 0, 0) == 0)
1634 {
1635 printf("DNSServiceUpdateRecord(): expected error return\n");
1636 return 1;
1637 };
1638
1639 printf("DNSServiceRemoveRecord()\n");
1640 if (DNSServiceRemoveRecord(0, 0, 0) == 0)
1641 {
1642 printf("DNSServiceRemoveRecord(): expected error return\n");
1643 return 1;
1644 };
1645
1646 printf("DNSServiceReconfirmRecord()\n");
1647 if (DNSServiceReconfirmRecord(0, 0, 0, 0, 0, 0, 0) == 0)
1648 {
1649 printf("DNSServiceReconfirmRecord(): expected error return\n");
1650 return 1;
1651 };
1652
1653
1654 printf("Basic API input range tests with all parameters set to 0: PASSED\n");
1655 return 0;
1656 }
1657
1658 static int API_input_range_test()
1659 {
1660
1661 if (API_string_limit_test())
1662 return 1;
1663
1664 if (API_NULL_input_test())
1665 return 1;
1666
1667 return 0;
1668 }
1669
1670 int main(int argc, char **argv)
1671 {
1672 DNSServiceErrorType err;
1673 char buffer[TypeBufferSize], *typ, *dom;
1674 int opi;
1675 DNSServiceFlags flags = 0;
1676 int optional = 0;
1677
1678 // Extract the program name from argv[0], which by convention contains the path to this executable.
1679 // Note that this is just a voluntary convention, not enforced by the kernel --
1680 // the process calling exec() can pass bogus data in argv[0] if it chooses to.
1681 const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
1682 if (a0 == (const char *)1) a0 = argv[0];
1683
1684 #if defined(_WIN32)
1685 HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
1686 #endif
1687
1688 #if TEST_NEW_CLIENTSTUB
1689 printf("Using embedded copy of dnssd_clientstub instead of system library\n");
1690 if (sizeof(argv) == 8) printf("Running in 64-bit mode\n");
1691 #endif
1692
1693 // Test code for TXTRecord functions
1694 //TXTRecordRef txtRecord;
1695 //TXTRecordCreate(&txtRecord, 0, NULL);
1696 //TXTRecordSetValue(&txtRecord, "aaa", 1, "b");
1697 //printf("%d\n", TXTRecordContainsKey(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), "Aaa"));
1698
1699 while (argc > 1)
1700 {
1701 int entryCount;
1702
1703 // record current argc to see if we process an argument in this pass
1704 entryCount = argc;
1705
1706 if (argc > 1 && !strcmp(argv[1], "-test"))
1707 {
1708 argc--;
1709 argv++;
1710 return API_input_range_test();
1711 }
1712
1713 if (argc > 1 && !strcmp(argv[1], "-lo"))
1714 {
1715 argc--;
1716 argv++;
1717 opinterface = kDNSServiceInterfaceIndexLocalOnly;
1718 printf("Using LocalOnly\n");
1719 }
1720
1721 if (argc > 1 && (!strcasecmp(argv[1], "-p2p")))
1722 {
1723 argc--;
1724 argv++;
1725 opinterface = kDNSServiceInterfaceIndexP2P;
1726 }
1727
1728 if (argc > 1 && (!strcasecmp(argv[1], "-ble")))
1729 {
1730 argc--;
1731 argv++;
1732 opinterface = kDNSServiceInterfaceIndexBLE;
1733 }
1734
1735 if (argc > 1 && !strcasecmp(argv[1], "-includep2p"))
1736 {
1737 argc--;
1738 argv++;
1739 flags |= kDNSServiceFlagsIncludeP2P;
1740 printf("Setting kDNSServiceFlagsIncludeP2P\n");
1741 }
1742
1743 if (argc > 1 && !strcasecmp(argv[1], "-includeAWDL"))
1744 {
1745 argc--;
1746 argv++;
1747 flags |= kDNSServiceFlagsIncludeAWDL;
1748 printf("Setting kDNSServiceFlagsIncludeAWDL\n");
1749 }
1750
1751 if (argc > 1 && !strcasecmp(argv[1], "-intermediates"))
1752 {
1753 argc--;
1754 argv++;
1755 flags |= kDNSServiceFlagsReturnIntermediates;
1756 printf("Setting kDNSServiceFlagsReturnIntermediates\n");
1757 }
1758
1759 if (argc > 1 && !strcasecmp(argv[1], "-tc"))
1760 {
1761 argc--;
1762 argv++;
1763 flags |= kDNSServiceFlagsBackgroundTrafficClass;
1764 printf("Setting kDNSServiceFlagsBackgroundTrafficClass\n");
1765 }
1766
1767 if (argc > 1 && !strcasecmp(argv[1], "-t1"))
1768 {
1769 argc--;
1770 argv++;
1771 flags |= kDNSServiceFlagsThresholdOne;
1772 printf("Setting kDNSServiceFlagsThresholdOne\n");
1773 }
1774
1775 if (argc > 1 && !strcasecmp(argv[1], "-tFinder"))
1776 {
1777 argc--;
1778 argv++;
1779 flags |= kDNSServiceFlagsThresholdFinder;
1780 printf("Setting kDNSServiceFlagsThresholdFinder\n");
1781 }
1782
1783 if (argc > 1 && !strcasecmp(argv[1], "-wo"))
1784 {
1785 argc--;
1786 argv++;
1787 flags |= kDNSServiceFlagsWakeOnlyService;
1788 printf("Setting kDNSServiceFlagsWakeOnlyService\n");
1789 }
1790
1791 if (argc > 1 && !strcasecmp(argv[1], "-ku"))
1792 {
1793 argc--;
1794 argv++;
1795 flags |= kDNSServiceFlagsKnownUnique;
1796 printf("Setting kDNSServiceFlagsKnownUnique\n");
1797 }
1798
1799 if (argc > 1 && !strcasecmp(argv[1], "-unicastResponse"))
1800 {
1801 argc--;
1802 argv++;
1803 flags |= kDNSServiceFlagsUnicastResponse;
1804 printf("Setting kDNSServiceFlagsUnicastResponse\n");
1805 }
1806
1807 if (argc > 1 && !strcasecmp(argv[1], "-timeout"))
1808 {
1809 argc--;
1810 argv++;
1811 flags |= kDNSServiceFlagsTimeout;
1812 printf("Setting kDNSServiceFlagsTimeout\n");
1813 }
1814
1815 if (argc > 1 && !strcasecmp(argv[1], "-autoTrigger"))
1816 {
1817 argc--;
1818 argv++;
1819 flags |= kDNSServiceFlagsAutoTrigger;
1820 printf("Setting kDNSServiceFlagsAutoTrigger\n");
1821 }
1822
1823 if (argc > 1 && !strcasecmp(argv[1], "-optional"))
1824 {
1825 argc--;
1826 argv++;
1827 optional = 1;
1828 printf("Setting DNSSEC optional flag\n");
1829 }
1830
1831 if (argc > 2 && !strcmp(argv[1], "-i"))
1832 {
1833 opinterface = if_nametoindex(argv[2]);
1834 if (!opinterface) opinterface = atoi(argv[2]);
1835 if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; }
1836 argc -= 2;
1837 argv += 2;
1838 }
1839
1840 // Exit loop if if we didn't match one of the multi character options.
1841 if (argc == entryCount)
1842 break;
1843 }
1844
1845 if (argc < 2) goto Fail; // Minimum command line is the command name and one argument
1846 operation = getfirstoption(argc, argv, "ABCDEFHILMNPQRSTUVZhlq"
1847 "X"
1848 "Gg"
1849 , &opi);
1850 if (operation == -1) goto Fail;
1851
1852 if (opinterface) printf("Using interface %d\n", opinterface);
1853
1854 switch (operation)
1855 {
1856 case 'E': printf("Looking for recommended registration domains:\n");
1857 err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, opinterface, enum_reply, NULL);
1858 break;
1859
1860 case 'F': printf("Looking for recommended browsing domains:\n");
1861 err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, opinterface, enum_reply, NULL);
1862 //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "nicta.com.au.", NULL);
1863 //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "bonjour.nicta.com.au.", NULL);
1864 //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "ibm.com.", NULL);
1865 //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL);
1866 break;
1867
1868 case 'B': typ = (argc < opi+1) ? "" : argv[opi+0];
1869 dom = (argc < opi+2) ? "" : argv[opi+1]; // Missing domain argument is the same as empty string i.e. use system default(s)
1870 typ = gettype(buffer, typ);
1871 if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
1872 printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
1873 err = DNSServiceBrowse(&client, flags, opinterface, typ, dom, browse_reply, NULL);
1874 break;
1875
1876 case 'Z': typ = (argc < opi+1) ? "" : argv[opi+0];
1877 dom = (argc < opi+2) ? "" : argv[opi+1]; // Missing domain argument is the same as empty string i.e. use system default(s)
1878 typ = gettype(buffer, typ);
1879 if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
1880 printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
1881 err = DNSServiceCreateConnection(&client);
1882 if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
1883 sc1 = client;
1884 err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, typ, dom, zonedata_browse, NULL);
1885 break;
1886
1887 case 'l':
1888 case 'L': {
1889 if (argc < opi+2) goto Fail;
1890 typ = (argc < opi+2) ? "" : argv[opi+1];
1891 dom = (argc < opi+3) ? "local" : argv[opi+2];
1892 typ = gettype(buffer, typ);
1893 if (dom[0] == '.' && dom[1] == 0) dom = "local"; // We allow '.' on the command line as a synonym for "local"
1894 printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom);
1895 if (operation == 'l') flags |= kDNSServiceFlagsWakeOnResolve;
1896 err = DNSServiceResolve(&client, flags, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL);
1897 break;
1898 }
1899
1900 case 'R': if (argc < opi+4) goto Fail;
1901 typ = (argc < opi+2) ? "" : argv[opi+1];
1902 dom = (argc < opi+3) ? "" : argv[opi+2];
1903 typ = gettype(buffer, typ);
1904 if (dom[0] == '.' && dom[1] == 0) dom[0] = 0; // We allow '.' on the command line as a synonym for empty string
1905 err = RegisterService(&client, argv[opi+0], typ, dom, NULL, argv[opi+3], argc-(opi+4), argv+(opi+4), flags);
1906 break;
1907
1908
1909 case 'P': if (argc < opi+6) goto Fail;
1910 err = DNSServiceCreateConnection(&client_pa);
1911 if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
1912 err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5], flags);
1913 if (err) break;
1914 err = RegisterService(&client, argv[opi+0], gettype(buffer, argv[opi+1]), argv[opi+2], argv[opi+4], argv[opi+3], argc-(opi+6), argv+(opi+6), flags);
1915 break;
1916
1917 case 'D':
1918 case 'q':
1919 case 'Q':
1920 case 'C': {
1921 uint16_t rrtype, rrclass;
1922 flags |= kDNSServiceFlagsReturnIntermediates;
1923 if (operation == 'q')
1924 flags |= kDNSServiceFlagsSuppressUnusable;
1925 if (argc < opi+1)
1926 goto Fail;
1927 rrtype = (argc <= opi+1) ? kDNSServiceType_A : GetRRType(argv[opi+1]);
1928 rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : GetRRClass(argv[opi+2]);
1929 if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR)
1930 flags |= kDNSServiceFlagsLongLivedQuery;
1931 if (operation == 'D')
1932 {
1933 flags |= kDNSServiceFlagsSuppressUnusable;
1934 if (optional)
1935 flags |= kDNSServiceFlagsValidateOptional;
1936 else
1937 flags |= kDNSServiceFlagsValidate;
1938 }
1939 err = DNSServiceQueryRecord(&client, flags, opinterface, argv[opi+0], rrtype, rrclass, qr_reply, NULL);
1940 break;
1941 }
1942
1943 case 'A':
1944 case 'U':
1945 case 'N': {
1946 Opaque16 registerPort = { { 0x12, 0x34 } };
1947 static const char TXT[] = "\xC" "First String" "\xD" "Second String" "\xC" "Third String";
1948 printf("Registering Service Test._testupdate._tcp.local.\n");
1949 err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testupdate._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT)-1, TXT, reg_reply, NULL);
1950 break;
1951 }
1952
1953 case 'T': {
1954 Opaque16 registerPort = { { 0x23, 0x45 } };
1955 char TXT[1024];
1956 unsigned int i;
1957 for (i=0; i<sizeof(TXT); i++)
1958 if ((i & 0x1F) == 0) TXT[i] = 0x1F;else TXT[i] = 'A' + (i >> 5);
1959 printf("Registering Service Test._testlargetxt._tcp.local.\n");
1960 err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testlargetxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT), TXT, reg_reply, NULL);
1961 break;
1962 }
1963
1964 case 'M': {
1965 pid_t pid = getpid();
1966 Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
1967 static const char TXT1[] = "\xC" "First String" "\xD" "Second String" "\xC" "Third String";
1968 static const char TXT2[] = "\xD" "Fourth String" "\xC" "Fifth String" "\xC" "Sixth String";
1969 printf("Registering Service Test._testdualtxt._tcp.local.\n");
1970 err = DNSServiceRegister(&client, flags, opinterface, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
1971 if (!err) err = DNSServiceAddRecord(client, &record, flags, kDNSServiceType_TXT, sizeof(TXT2)-1, TXT2, 0);
1972 break;
1973 }
1974
1975 case 'I': {
1976 pid_t pid = getpid();
1977 Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
1978 static const char TXT[] = "\x09" "Test Data";
1979 printf("Registering Service Test._testtxt._tcp.local.\n");
1980 err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testtxt._tcp.", "", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
1981 if (!err) err = DNSServiceUpdateRecord(client, NULL, 0, sizeof(TXT)-1, TXT, 0);
1982 break;
1983 }
1984
1985 case 'X': {
1986 if (argc == opi) // If no arguments, just fetch IP address
1987 err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL);
1988 else if (argc >= opi+2 && atoi(argv[opi+0]) == 0)
1989 {
1990 DNSServiceProtocol prot = GetProtocol(argv[opi+0]); // Must specify TCP or UDP
1991 uint16_t IntPortAsNumber = atoi(argv[opi+1]); // Must specify internal port
1992 uint16_t ExtPortAsNumber = (argc < opi+3) ? 0 : atoi(argv[opi+2]); // Optional desired external port
1993 uint32_t ttl = (argc < opi+4) ? 0 : atoi(argv[opi+3]); // Optional desired lease lifetime
1994 Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } };
1995 Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } };
1996 err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL);
1997 }
1998 else goto Fail;
1999 break;
2000 }
2001
2002 case 'g':
2003 case 'G': {
2004 flags |= kDNSServiceFlagsReturnIntermediates;
2005 if (operation == 'g')
2006 {
2007 flags |= kDNSServiceFlagsSuppressUnusable;
2008 if (optional)
2009 flags |= kDNSServiceFlagsValidateOptional;
2010 else
2011 flags |= kDNSServiceFlagsValidate;
2012 }
2013 if (argc != opi+2)
2014 goto Fail;
2015 else
2016 err = DNSServiceGetAddrInfo(&client, flags, opinterface, GetProtocol(argv[opi+0]), argv[opi+1], addrinfo_reply, NULL);
2017 break;
2018 }
2019
2020 case 'S': {
2021 Opaque16 registerPort = { { 0x23, 0x45 } }; // 9029 decimal
2022 unsigned char txtrec[16] = "\xF" "/path=test.html";
2023 DNSRecordRef rec;
2024 unsigned char nulrec[4] = "1234";
2025
2026 err = DNSServiceCreateConnection(&client);
2027 if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); }
2028
2029 sc1 = client;
2030 err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, "_http._tcp", "", browse_reply, NULL);
2031 if (err) { fprintf(stderr, "DNSServiceBrowse _http._tcp failed %ld\n", (long int)err); return (-1); }
2032
2033 sc2 = client;
2034 err = DNSServiceBrowse(&sc2, kDNSServiceFlagsShareConnection, opinterface, "_ftp._tcp", "", browse_reply, NULL);
2035 if (err) { fprintf(stderr, "DNSServiceBrowse _ftp._tcp failed %ld\n", (long int)err); return (-1); }
2036
2037 sc3 = client;
2038 err = DNSServiceRegister(&sc3, kDNSServiceFlagsShareConnection, opinterface, "kDNSServiceFlagsShareConnection",
2039 "_http._tcp", "local", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
2040 if (err) { fprintf(stderr, "SharedConnection DNSServiceRegister failed %ld\n", (long int)err); return (-1); }
2041
2042 err = DNSServiceUpdateRecord(sc3, NULL, 0, sizeof(txtrec), txtrec, 0);
2043 if (err) { fprintf(stderr, "SharedConnection DNSServiceUpdateRecord failed %ld\n", (long int)err); return (-1); }
2044
2045 err = DNSServiceAddRecord(sc3, &rec, 0, kDNSServiceType_NULL, sizeof(nulrec), nulrec, 0);
2046 if (err) { fprintf(stderr, "SharedConnection DNSServiceAddRecord failed %ld\n", (long int)err); return (-1); }
2047
2048 err = DNSServiceRemoveRecord(sc3, rec, 0);
2049 if (err) { fprintf(stderr, "SharedConnection DNSServiceRemoveRecord failed %ld\n", (long int)err); return (-1); }
2050
2051 break;
2052 }
2053
2054 case 'V': {
2055 uint32_t v;
2056 uint32_t size = sizeof(v);
2057 err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &v, &size);
2058 if (err) fprintf(stderr, "DNSServiceGetProperty failed %ld\n", (long int)err);
2059 else printf("Currently running daemon (system service) is version %d.%d.%d\n", v / 10000, v / 100 % 100, v % 100);
2060 exit(0);
2061 }
2062
2063 case 'H': goto Fail;
2064
2065 default: goto Fail;
2066 }
2067
2068 if (!client || err != kDNSServiceErr_NoError)
2069 {
2070 fprintf(stderr, "DNSService call failed %ld%s\n", (long int)err,
2071 (err == kDNSServiceErr_ServiceNotRunning) ? " (Service Not Running)" : "");
2072 return (-1);
2073 }
2074 printtimestamp();
2075 printf("...STARTING...\n");
2076 HandleEvents();
2077
2078 // Be sure to deallocate the DNSServiceRef when you're finished
2079 if (client ) DNSServiceRefDeallocate(client );
2080 if (client_pa) DNSServiceRefDeallocate(client_pa);
2081 return 0;
2082
2083 Fail:
2084 if (operation == 'H') print_usage(a0,1);
2085 else print_usage(a0,0);
2086 return 0;
2087
2088 }
2089
2090 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
2091 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
2092 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
2093 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
2094 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
2095
2096 // NOT static -- otherwise the compiler may optimize it out
2097 // The "@(#) " pattern is a special prefix the "what" command looks for
2098 const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
2099
2100 #if _BUILDING_XCODE_PROJECT_
2101 // If the process crashes, then this string will be magically included in the automatically-generated crash log
2102 const char *__crashreporter_info__ = VersionString_SCCS + 5;
2103 asm (".desc ___crashreporter_info__, 0x10");
2104 #endif