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