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