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