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