xref: /illumos-gate/usr/src/contrib/mDNSResponder/Clients/dns-sd.c (revision a92282e44f968185a6bba094d1e5fece2da819cf)
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 #ifndef MDNS_VERSIONSTR_NODTS
2285 const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
2286 #else
2287 const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion);
2288 #endif
2289 
2290 #if _BUILDING_XCODE_PROJECT_
2291 // If the process crashes, then this string will be magically included in the automatically-generated crash log
2292 const char *__crashreporter_info__ = VersionString_SCCS + 5;
2293 asm (".desc ___crashreporter_info__, 0x10");
2294 #endif
2295