source: rtems-libbsd/mDNSResponder/Clients/dns-sd.c @ f761b29

55-freebsd-126-freebsd-12
Last change on this file since f761b29 was f761b29, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:52:21

mDNSResponder: Update to v625.41.2

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-625.41.2.tar.gz

Update #3522.

  • Property mode set to 100644
File size: 73.0 KB
Line 
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 "ClientCommon.h"
169
170#if TEST_NEW_CLIENTSTUB
171#include "../mDNSShared/dnssd_ipc.c"
172#include "../mDNSShared/dnssd_clientlib.c"
173#include "../mDNSShared/dnssd_clientstub.c"
174#endif
175
176#if _DNS_SD_LIBDISPATCH
177#include <dispatch/private.h>
178#endif
179
180//*************************************************************************************************************
181// Globals
182
183#define DS_FIXED_SIZE   4
184typedef struct
185{
186    unsigned short keyTag;
187    unsigned char alg;
188    unsigned char digestType;
189    unsigned char  *digest;
190} rdataDS;
191
192#define DNSKEY_FIXED_SIZE    4
193typedef struct
194{
195    unsigned short flags;
196    unsigned char proto;
197    unsigned char alg;
198    unsigned char *data;
199} rdataDNSKey;
200
201//size of rdataRRSIG excluding signerName and signature (which are variable fields)
202#define RRSIG_FIXED_SIZE      18
203typedef struct
204{
205    unsigned short typeCovered;
206    unsigned char alg;
207    unsigned char labels;
208    unsigned int origTTL;
209    unsigned int sigExpireTime;
210    unsigned int sigInceptTime;
211    unsigned short keyTag;
212    char signerName[256];
213    //unsigned char *signature
214} rdataRRSig;
215
216#define RR_TYPE_SIZE 16
217
218typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
219
220static int operation;
221static uint32_t opinterface = kDNSServiceInterfaceIndexAny;
222static DNSServiceRef client    = NULL;
223static DNSServiceRef client_pa = NULL;  // DNSServiceRef for RegisterProxyAddressRecord
224static DNSServiceRef sc1, sc2, sc3;     // DNSServiceRefs for kDNSServiceFlagsShareConnection testing
225
226static int num_printed;
227static char addtest = 0;
228static DNSRecordRef record = NULL;
229static char myhinfoW[14] = "\002PC\012Windows XP";
230static char myhinfoX[ 9] = "\003Mac\004OS X";
231static char updatetest[3] = "\002AA";
232static char bigNULL[8192];  // 8K is maximum rdata we support
233
234#if _DNS_SD_LIBDISPATCH
235dispatch_queue_t main_queue;
236dispatch_source_t timer_source;
237#endif
238
239// Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
240#define LONG_TIME 100000000
241
242static volatile int stopNow = 0;
243static volatile int timeOut = LONG_TIME;
244
245#if _DNS_SD_LIBDISPATCH
246#define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E) \
247    if (main_queue && (E) == kDNSServiceErr_ServiceNotRunning) { fprintf(stderr, "Error code %d\n", (E)); exit(0); }
248#else
249#define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E)
250#endif
251
252//*************************************************************************************************************
253// Supporting Utility Functions
254static uint16_t GetRRClass(const char *s)   
255{
256    if (!strcasecmp(s, "IN"))
257        return kDNSServiceClass_IN;
258    else
259        return(atoi(s));
260}     
261
262static uint16_t GetRRType(const char *s)
263{
264    if      (!strcasecmp(s, "A"       )) return(kDNSServiceType_A);
265    else if (!strcasecmp(s, "NS"      )) return(kDNSServiceType_NS);
266    else if (!strcasecmp(s, "MD"      )) return(kDNSServiceType_MD);
267    else if (!strcasecmp(s, "MF"      )) return(kDNSServiceType_MF);
268    else if (!strcasecmp(s, "CNAME"   )) return(kDNSServiceType_CNAME);
269    else if (!strcasecmp(s, "SOA"     )) return(kDNSServiceType_SOA);
270    else if (!strcasecmp(s, "MB"      )) return(kDNSServiceType_MB);
271    else if (!strcasecmp(s, "MG"      )) return(kDNSServiceType_MG);
272    else if (!strcasecmp(s, "MR"      )) return(kDNSServiceType_MR);
273    else if (!strcasecmp(s, "NULL"    )) return(kDNSServiceType_NULL);
274    else if (!strcasecmp(s, "WKS"     )) return(kDNSServiceType_WKS);
275    else if (!strcasecmp(s, "PTR"     )) return(kDNSServiceType_PTR);
276    else if (!strcasecmp(s, "HINFO"   )) return(kDNSServiceType_HINFO);
277    else if (!strcasecmp(s, "MINFO"   )) return(kDNSServiceType_MINFO);
278    else if (!strcasecmp(s, "MX"      )) return(kDNSServiceType_MX);
279    else if (!strcasecmp(s, "TXT"     )) return(kDNSServiceType_TXT);
280    else if (!strcasecmp(s, "RP"      )) return(kDNSServiceType_RP);
281    else if (!strcasecmp(s, "AFSDB"   )) return(kDNSServiceType_AFSDB);
282    else if (!strcasecmp(s, "X25"     )) return(kDNSServiceType_X25);
283    else if (!strcasecmp(s, "ISDN"    )) return(kDNSServiceType_ISDN);
284    else if (!strcasecmp(s, "RT"      )) return(kDNSServiceType_RT);
285    else if (!strcasecmp(s, "NSAP"    )) return(kDNSServiceType_NSAP);
286    else if (!strcasecmp(s, "NSAP_PTR")) return(kDNSServiceType_NSAP_PTR);
287    else if (!strcasecmp(s, "SIG"     )) return(kDNSServiceType_SIG);
288    else if (!strcasecmp(s, "KEY"     )) return(kDNSServiceType_KEY);
289    else if (!strcasecmp(s, "PX"      )) return(kDNSServiceType_PX);
290    else if (!strcasecmp(s, "GPOS"    )) return(kDNSServiceType_GPOS);
291    else if (!strcasecmp(s, "AAAA"    )) return(kDNSServiceType_AAAA);
292    else if (!strcasecmp(s, "LOC"     )) return(kDNSServiceType_LOC);
293    else if (!strcasecmp(s, "NXT"     )) return(kDNSServiceType_NXT);
294    else if (!strcasecmp(s, "EID"     )) return(kDNSServiceType_EID);
295    else if (!strcasecmp(s, "NIMLOC"  )) return(kDNSServiceType_NIMLOC);
296    else if (!strcasecmp(s, "SRV"     )) return(kDNSServiceType_SRV);
297    else if (!strcasecmp(s, "ATMA"    )) return(kDNSServiceType_ATMA);
298    else if (!strcasecmp(s, "NAPTR"   )) return(kDNSServiceType_NAPTR);
299    else if (!strcasecmp(s, "KX"      )) return(kDNSServiceType_KX);
300    else if (!strcasecmp(s, "CERT"    )) return(kDNSServiceType_CERT);
301    else if (!strcasecmp(s, "A6"      )) return(kDNSServiceType_A6);
302    else if (!strcasecmp(s, "DNAME"   )) return(kDNSServiceType_DNAME);
303    else if (!strcasecmp(s, "SINK"    )) return(kDNSServiceType_SINK);
304    else if (!strcasecmp(s, "OPT"     )) return(kDNSServiceType_OPT);
305    else if (!strcasecmp(s, "TKEY"    )) return(kDNSServiceType_TKEY);
306    else if (!strcasecmp(s, "TSIG"    )) return(kDNSServiceType_TSIG);
307    else if (!strcasecmp(s, "IXFR"    )) return(kDNSServiceType_IXFR);
308    else if (!strcasecmp(s, "AXFR"    )) return(kDNSServiceType_AXFR);
309    else if (!strcasecmp(s, "MAILB"   )) return(kDNSServiceType_MAILB);
310    else if (!strcasecmp(s, "MAILA"   )) return(kDNSServiceType_MAILA);
311    else if (!strcasecmp(s, "dnskey"  )) return(kDNSServiceType_DNSKEY);
312    else if (!strcasecmp(s, "ds"      )) return(kDNSServiceType_DS);
313    else if (!strcasecmp(s, "rrsig"   )) return(kDNSServiceType_RRSIG);
314    else if (!strcasecmp(s, "nsec"    )) return(kDNSServiceType_NSEC);
315    else if (!strcasecmp(s, "ANY"     )) return(kDNSServiceType_ANY);
316    else return(atoi(s));
317}
318
319static char *DNSTypeName(unsigned short rr_type)
320{
321    switch (rr_type)
322    {
323        case kDNSServiceType_A:         return("Addr");
324        case kDNSServiceType_NS:        return("NS");
325        case kDNSServiceType_MX:        return("MX");
326        case kDNSServiceType_CNAME:     return("CNAME");
327        case kDNSServiceType_SOA:       return("SOA");
328        case kDNSServiceType_PTR:       return("PTR");
329        case kDNSServiceType_AAAA:      return("AAAA");
330        case kDNSServiceType_NSEC:      return("NSEC");
331        case kDNSServiceType_TSIG:      return("TSIG");
332        case kDNSServiceType_RRSIG:     return("RRSIG");
333        case kDNSServiceType_DNSKEY:    return("DNSKEY");
334        case kDNSServiceType_DS:        return("DS");
335        default:           
336        {
337            static char buffer[RR_TYPE_SIZE];
338            snprintf(buffer, sizeof(buffer), "TYPE%d", rr_type);
339            return(buffer);
340        }
341    }
342}
343
344static unsigned short swap16(unsigned short x)
345{
346    unsigned char *ptr = (unsigned char *)&x;
347    return (unsigned short)((unsigned short)ptr[0] << 8 | ptr[1]);
348}
349
350static unsigned int swap32(unsigned int x)
351{
352    unsigned char *ptr = (unsigned char *)&x;
353    return (unsigned int)((unsigned int)ptr[0] << 24 | (unsigned int)ptr[1] << 16 | (unsigned int)ptr[2] << 8 | ptr[3]);
354}
355static unsigned int keytag(unsigned char *key, unsigned int keysize) 
356{
357    unsigned long ac;
358    unsigned int i;
359
360    for (ac = 0, i = 0; i < keysize; ++i)
361        ac += (i & 1) ? key[i] : key[i] << 8;
362    ac += (ac >> 16) & 0xFFFF;
363    return ac & 0xFFFF;
364}
365
366static void base64Encode(char *buffer, int buflen, void *rdata, unsigned int rdlen)
367{
368#if _DNS_SD_LIBDISPATCH
369    const void *result = NULL;
370    size_t size;
371    dispatch_data_t src_data = NULL, dest_data = NULL, null_str = NULL, data = NULL, map = NULL;
372
373    src_data = dispatch_data_create(rdata, rdlen, dispatch_get_global_queue(0, 0), ^{});
374    if (!src_data)
375        goto done;
376
377    dest_data = dispatch_data_create_with_transform(src_data, DISPATCH_DATA_FORMAT_TYPE_NONE, DISPATCH_DATA_FORMAT_TYPE_BASE64);
378    if (!dest_data)
379        goto done;
380
381    null_str = dispatch_data_create("", 1, dispatch_get_global_queue(0, 0), ^{});
382    if (!null_str)
383        goto done;
384 
385    data = dispatch_data_create_concat(dest_data, null_str);
386    if (!data)
387        goto done;   
388
389    map = dispatch_data_create_map(data, &result, &size);   
390    if (!map)
391        goto done;
392
393    snprintf(buffer, buflen, " %s", (char *)result);
394   
395done:
396    if (src_data) dispatch_release(src_data);
397    if (dest_data) dispatch_release(dest_data);
398    if (data)     dispatch_release(data);
399    if (null_str) dispatch_release(null_str);
400    if (map)      dispatch_release(map);
401    return;
402#else  //_DNS_SD_LIBDISPATCH
403    snprintf(buffer, buflen, " %s", ".");
404    return;
405#endif //_DNS_SD_LIBDISPATCH
406}
407
408static DNSServiceProtocol GetProtocol(const char *s)
409{
410    if      (!strcasecmp(s, "v4"      )) return(kDNSServiceProtocol_IPv4);
411    else if (!strcasecmp(s, "v6"      )) return(kDNSServiceProtocol_IPv6);
412    else if (!strcasecmp(s, "v4v6"    )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
413    else if (!strcasecmp(s, "v6v4"    )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
414    else if (!strcasecmp(s, "udp"     )) return(kDNSServiceProtocol_UDP);
415    else if (!strcasecmp(s, "tcp"     )) return(kDNSServiceProtocol_TCP);
416    else if (!strcasecmp(s, "udptcp"  )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
417    else if (!strcasecmp(s, "tcpudp"  )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
418    else return(atoi(s));
419}
420
421
422//*************************************************************************************************************
423// Sample callback functions for each of the operation types
424
425static void printtimestamp(void)
426{
427    struct tm tm;
428    int ms;
429    static char date[16];
430    static char new_date[16];
431#ifdef _WIN32
432    SYSTEMTIME sysTime;
433    time_t uct = time(NULL);
434    tm = *localtime(&uct);
435    GetLocalTime(&sysTime);
436    ms = sysTime.wMilliseconds;
437#else
438    struct timeval tv;
439    gettimeofday(&tv, NULL);
440    localtime_r((time_t*)&tv.tv_sec, &tm);
441    ms = tv.tv_usec/1000;
442#endif
443    strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
444    if (strncmp(date, new_date, sizeof(new_date)))
445    {
446        printf("DATE: ---%s---\n", new_date); //display date only if it has changed
447        strncpy(date, new_date, sizeof(date));
448    }
449    printf("%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
450}
451
452// formating time to RFC 4034 format
453static void FormatTime(unsigned long te, unsigned char *buf, int bufsize)
454{
455    struct tm tmTime;
456#ifdef _WIN32
457        __time32_t t = (__time32_t) te;
458        _gmtime32_s(&tmTime, &t);
459#else
460    // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
461    // gmtime_r first and then use strftime
462        time_t t = (time_t)te;
463        gmtime_r(&t, &tmTime);
464#endif
465    strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
466}
467
468static void print_usage(const char *arg0, int print_all)
469{
470    fprintf(stderr, "%s -E                              (Enumerate recommended registration domains)\n", arg0);
471    fprintf(stderr, "%s -F                                  (Enumerate recommended browsing domains)\n", arg0);
472    fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...]             (Register a service)\n", arg0);
473    fprintf(stderr, "%s -B        <Type> <Domain>                    (Browse for services instances)\n", arg0);
474    fprintf(stderr, "%s -L <Name> <Type> <Domain>                       (Look up a service instance)\n", arg0);
475    fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]              (Proxy)\n", arg0);
476    fprintf(stderr, "%s -q <name> <rrtype> <rrclass>             (Generic query for any record type)\n", arg0);
477    fprintf(stderr, "%s -D <name> <rrtype> <rrclass>(Validate query for any record type with DNSSEC)\n", arg0);
478    fprintf(stderr, "%s -Z        <Type> <Domain>               (Output results in Zone File format)\n", arg0);
479    fprintf(stderr, "%s -G     v4/v6/v4v6 <name>              (Get address information for hostname)\n", arg0);
480    fprintf(stderr, "%s -g v4/v6/v4v6 <name>        (Validate address info for hostname with DNSSEC)\n", arg0);
481    fprintf(stderr, "%s -V                (Get version of currently running daemon / system service)\n", arg0);
482
483    if (print_all)  //Print all available options for dns-sd tool
484    {
485        fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass>               (Query; reconfirming each result)\n", arg0);
486        fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL>               (NAT Port Mapping)\n", arg0);
487        fprintf(stderr, "%s -A                                  (Test Adding/Updating/Deleting a record)\n", arg0);
488        fprintf(stderr, "%s -U                                              (Test updating a TXT record)\n", arg0);
489        fprintf(stderr, "%s -N                                         (Test adding a large NULL record)\n", arg0);
490        fprintf(stderr, "%s -T                                        (Test creating a large TXT record)\n", arg0);
491        fprintf(stderr, "%s -M                  (Test creating a registration with multiple TXT records)\n", arg0);
492        fprintf(stderr, "%s -I               (Test registering and then immediately updating TXT record)\n", arg0);
493        fprintf(stderr, "%s -S                             (Test multiple operations on a shared socket)\n", arg0);
494        fprintf(stderr, "%s -i <Interface>             (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
495        fprintf(stderr, "%s -lo                              (Run dns-sd cmd using local only interface)\n", arg0);
496        fprintf(stderr, "%s -p2p                                      (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
497        fprintf(stderr, "%s -includep2p                            (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
498        fprintf(stderr, "%s -includeAWDL                          (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
499        fprintf(stderr, "%s -optional                        (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
500        fprintf(stderr, "%s -tc                        (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
501        fprintf(stderr, "%s -unicastResponse                  (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
502        fprintf(stderr, "%s -t1                                  (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
503        fprintf(stderr, "%s -tFinder                          (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
504        fprintf(stderr, "%s -timeout                                  (Set kDNSServiceFlagsTimeout flag)\n", arg0);
505    }
506}
507
508#define DomainMsg(X) (((X) &kDNSServiceFlagsDefault) ? "(Default)" : \
509                      ((X) &kDNSServiceFlagsAdd)     ? "Added"     : "Removed")
510
511#define MAX_LABELS 128
512
513static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex,
514                                 DNSServiceErrorType errorCode, const char *replyDomain, void *context)
515{
516    DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
517    int labels = 0, depth = 0, i, initial = 0;
518    char text[64];
519    const char *label[MAX_LABELS];
520
521    (void)sdref;        // Unused
522    (void)ifIndex;      // Unused
523    (void)context;      // Unused
524    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
525
526    // 1. Print the header
527    if (num_printed++ == 0) printf("Timestamp     Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
528    printtimestamp();
529    if (errorCode)
530        printf("Error code %d\n", errorCode);
531    else if (!*replyDomain)
532        printf("Error: No reply domain\n");
533    else
534    {
535        printf("%-10s", DomainMsg(flags));
536        printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
537        if (partialflags) printf("Flags: %4X  ", partialflags);
538        else printf("             ");
539
540        // 2. Count the labels
541        while (replyDomain && *replyDomain && labels < MAX_LABELS)
542        {
543            label[labels++] = replyDomain;
544            replyDomain = GetNextLabel(replyDomain, text);
545        }
546
547        // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
548        if      (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
549        else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
550        else initial = 1;
551        labels -= initial;
552
553        // 4. Print the initial one-, two- or three-label clump
554        for (i=0; i<initial; i++)
555        {
556            GetNextLabel(label[labels+i], text);
557            if (i>0) printf(".");
558            printf("%s", text);
559        }
560        printf("\n");
561
562        // 5. Print the remainder of the hierarchy
563        for (depth=0; depth<labels; depth++)
564        {
565            printf("                                             ");
566            for (i=0; i<=depth; i++) printf("- ");
567            GetNextLabel(label[labels-1-depth], text);
568            printf("> %s\n", text);
569        }
570    }
571
572    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
573}
574
575static int CopyLabels(char *dst, const char *lim, const char **srcp, int labels)
576{
577    const char *src = *srcp;
578    while (*src != '.' || --labels > 0)
579    {
580        if (*src == '\\') *dst++ = *src++;  // Make sure "\." doesn't confuse us
581        if (!*src || dst >= lim) return -1;
582        *dst++ = *src++;
583        if (!*src || dst >= lim) return -1;
584    }
585    *dst++ = 0;
586    *srcp = src + 1;    // skip over final dot
587    return 0;
588}
589
590static void DNSSD_API zonedata_resolve(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
591                                       const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txt, void *context)
592{
593    union { uint16_t s; u_char b[2]; } port = { opaqueport };
594    uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
595
596    const char *p = fullname;
597    char n[kDNSServiceMaxDomainName];
598    char t[kDNSServiceMaxDomainName];
599
600    const unsigned char *max = txt + txtLen;
601
602    (void)sdref;        // Unused
603    (void)ifIndex;      // Unused
604    (void)context;      // Unused
605
606    //if (!(flags & kDNSServiceFlagsAdd)) return;
607    if (errorCode) { printf("Error code %d\n", errorCode); return; }
608
609    if (CopyLabels(n, n + kDNSServiceMaxDomainName, &p, 3)) return;     // Fetch name+type
610    p = fullname;
611    if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 1)) return;     // Skip first label
612    if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 2)) return;     // Fetch next two labels (service type)
613
614    if (num_printed++ == 0)
615    {
616        printf("\n");
617        printf("; To direct clients to browse a different domain, substitute that domain in place of '@'\n");
618        printf("%-47s PTR     %s\n", "lb._dns-sd._udp", "@");
619        printf("\n");
620        printf("; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.\n");
621        printf("; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local\n");
622        printf("; names with the correct fully-qualified (unicast) domain name of the target host offering the service.\n");
623    }
624
625    printf("\n");
626    printf("%-47s PTR     %s\n", t, n);
627    printf("%-47s SRV     0 0 %d %s ; Replace with unicast FQDN of target host\n", n, PortAsNumber, hosttarget);
628    printf("%-47s TXT    ", n);
629
630    while (txt < max)
631    {
632        const unsigned char *const end = txt + 1 + txt[0];
633        txt++;      // Skip over length byte
634        printf(" \"");
635        while (txt<end)
636        {
637            if (*txt == '\\' || *txt == '\"') printf("\\");
638            printf("%c", *txt++);
639        }
640        printf("\"");
641    }
642    printf("\n");
643
644    DNSServiceRefDeallocate(sdref);
645    free(context);
646
647    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
648}
649
650static void DNSSD_API zonedata_browse(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
651                                      const char *replyName, const char *replyType, const char *replyDomain, void *context)
652{
653    DNSServiceRef *newref;
654
655    (void)sdref;        // Unused
656    (void)context;      // Unused
657    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
658
659    if (!(flags & kDNSServiceFlagsAdd)) return;
660    if (errorCode) { printf("Error code %d\n", errorCode); return; }
661
662    newref = malloc(sizeof(*newref));
663    *newref = client;
664    DNSServiceResolve(newref, kDNSServiceFlagsShareConnection, ifIndex, replyName, replyType, replyDomain, zonedata_resolve, newref);
665}
666
667static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
668                                   const char *replyName, const char *replyType, const char *replyDomain, void *context)
669{
670    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
671    (void)sdref;        // Unused
672    (void)context;      // Unused
673    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
674
675    if (num_printed++ == 0) printf("Timestamp     A/R    Flags  if %-20s %-20s %s\n", "Domain", "Service Type", "Instance Name");
676    printtimestamp();
677    if (errorCode)
678        printf("Error code %d\n", errorCode);
679    else
680        printf("%s %8X %3d %-20s %-20s %s\n",
681                op, flags, ifIndex, replyDomain, replyType, replyName);
682    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
683
684    // To test selective cancellation of operations of shared sockets,
685    // cancel the current operation when we've got a multiple of five results
686    //if (operation == 'S' && num_printed % 5 == 0) DNSServiceRefDeallocate(sdref);
687}
688
689static void ShowTXTRecord(uint16_t txtLen, const unsigned char *txtRecord)
690{
691    const unsigned char *ptr = txtRecord;
692    const unsigned char *max = txtRecord + txtLen;
693    while (ptr < max)
694    {
695        const unsigned char *const end = ptr + 1 + ptr[0];
696        if (end > max) { printf("<< invalid data >>"); break; }
697        if (++ptr < end) printf(" ");   // As long as string is non-empty, begin with a space
698        while (ptr<end)
699        {
700            // We'd like the output to be shell-friendly, so that it can be copied and pasted unchanged into a "dns-sd -R" command.
701            // However, this is trickier than it seems. Enclosing a string in double quotes doesn't necessarily make it
702            // shell-safe, because shells still expand variables like $foo even when they appear inside quoted strings.
703            // Enclosing a string in single quotes is better, but when using single quotes even backslash escapes are ignored,
704            // meaning there's simply no way to represent a single quote (or apostrophe) inside a single-quoted string.
705            // The only remaining solution is not to surround the string with quotes at all, but instead to use backslash
706            // escapes to encode spaces and all other known shell metacharacters.
707            // (If we've missed any known shell metacharacters, please let us know.)
708            // In addition, non-printing ascii codes (0-31) are displayed as \xHH, using a two-digit hex value.
709            // Because '\' is itself a shell metacharacter (the shell escape character), it has to be escaped as "\\" to survive
710            // the round-trip to the shell and back. This means that a single '\' is represented here as EIGHT backslashes:
711            // The C compiler eats half of them, resulting in four appearing in the output.
712            // The shell parses those four as a pair of "\\" sequences, passing two backslashes to the "dns-sd -R" command.
713            // The "dns-sd -R" command interprets this single "\\" pair as an escaped literal backslash. Sigh.
714            if (strchr(" &;`'\"|*?~<>^()[]{}$", *ptr)) printf("\\");
715            if      (*ptr == '\\') printf("\\\\\\\\");
716            else if (*ptr >= ' ' ) printf("%c",        *ptr);
717            else printf("\\\\x%02X", *ptr);
718            ptr++;
719        }
720    }
721}
722
723static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
724                                    const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txtRecord, void *context)
725{
726    union { uint16_t s; u_char b[2]; } port = { opaqueport };
727    uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
728
729    (void)sdref;        // Unused
730    (void)ifIndex;      // Unused
731    (void)context;      // Unused
732    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
733
734    if (errorCode)
735        printf("Error code %d\n", errorCode);
736    else
737    {
738        printtimestamp();
739        printf("%s can be reached at %s:%u (interface %d)", fullname, hosttarget, PortAsNumber, ifIndex);
740        if (flags) printf(" Flags: %X", flags);
741        // Don't show degenerate TXT records containing nothing but a single empty string
742        if (txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); }
743        printf("\n");
744    }
745
746    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
747}
748
749static void myTimerCallBack(void)
750{
751    DNSServiceErrorType err = kDNSServiceErr_Unknown;
752
753    switch (operation)
754    {
755    case 'A':
756    {
757        switch (addtest)
758        {
759        case 0: printf("Adding Test HINFO record\n");
760            err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_HINFO, sizeof(myhinfoW), &myhinfoW[0], 0);
761            addtest = 1;
762            break;
763        case 1: printf("Updating Test HINFO record\n");
764            err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 0);
765            addtest = 2;
766            break;
767        case 2: printf("Removing Test HINFO record\n");
768            err = DNSServiceRemoveRecord(client, record, 0);
769            addtest = 0;
770            break;
771        }
772    }
773    break;
774
775    case 'U':
776    {
777        if (updatetest[1] != 'Z') updatetest[1]++;
778        else updatetest[1] = 'A';
779        updatetest[0] = 3 - updatetest[0];
780        updatetest[2] = updatetest[1];
781        printtimestamp();
782        printf("Updating Test TXT record to %c\n", updatetest[1]);
783        err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0);
784    }
785    break;
786
787    case 'N':
788    {
789        printf("Adding big NULL record\n");
790        err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
791        if (err) printf("Failed: %d\n", err);else printf("Succeeded\n");
792        timeOut = LONG_TIME;
793#if _DNS_SD_LIBDISPATCH
794        if (timer_source)
795            dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
796                                      (uint64_t)timeOut * NSEC_PER_SEC, 0);
797#endif
798    }
799    break;
800    }
801
802    if (err != kDNSServiceErr_NoError)
803    {
804        fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err);
805        stopNow = 1;
806    }
807}
808
809static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
810                                const char *name, const char *regtype, const char *domain, void *context)
811{
812    (void)sdref;    // Unused
813    (void)flags;    // Unused
814    (void)context;  // Unused
815    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
816
817    printtimestamp();
818    printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
819
820    if (errorCode == kDNSServiceErr_NoError)
821    {
822        if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n");
823        else printf("Name registration removed\n");
824        if (operation == 'A' || operation == 'U' || operation == 'N')
825        {
826            timeOut = 5;
827#if _DNS_SD_LIBDISPATCH
828            if (timer_source)
829                dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
830                                          (uint64_t)timeOut * NSEC_PER_SEC, 0);
831#endif
832        }
833    }
834    else if (errorCode == kDNSServiceErr_NameConflict)
835    {
836        printf("Name in use, please choose another\n");
837        exit(-1);
838    }
839    else
840        printf("Error %d\n", errorCode);
841
842    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
843}
844
845// Output the wire-format domainname pointed to by rd
846static int snprintd(char *p, int max, const unsigned char **rd)
847{
848    const char *const buf = p;
849    const char *const end = p + max;
850    while (**rd)
851    {
852        p += snprintf(p, end-p, "%.*s.", **rd, *rd+1);
853        *rd += 1 + **rd;
854    }
855    *rd += 1;   // Advance over the final zero byte
856    return(p-buf);
857}
858
859static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, char *p, unsigned const char *rd, uint16_t rdlen)
860{
861    int rdb_size = 1000;
862    switch (rrtype)
863    {
864        case kDNSServiceType_DS:
865        {
866            unsigned char *ptr;
867            int i;
868            rdataDS *rrds = (rdataDS *)rd;
869            p += snprintf(p, rdb + rdb_size - p, "%d  %d  %d  ",
870                          rrds->alg, swap16(rrds->keyTag), rrds->digestType);
871            ptr = (unsigned char *)(rd + DS_FIXED_SIZE);
872            for (i = 0; i < (rdlen - DS_FIXED_SIZE); i++)
873                p += snprintf(p, rdb + rdb_size - p, "%x", ptr[i]);   
874            break;
875        }
876           
877        case kDNSServiceType_DNSKEY:
878        {
879            rdataDNSKey *rrkey = (rdataDNSKey *)rd;
880            p += snprintf(p, rdb + rdb_size - p, "%d  %d  %d  %u", swap16(rrkey->flags), rrkey->proto,
881                          rrkey->alg, (unsigned int)keytag((unsigned char *)rrkey, rdlen));
882            base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + DNSKEY_FIXED_SIZE), rdlen - DNSKEY_FIXED_SIZE);
883            break;
884        }
885           
886        case kDNSServiceType_NSEC:
887        {
888            unsigned char *next = (unsigned char *)rd;
889            int len, bitmaplen;
890            int win, wlen, type;
891            unsigned char *bmap;
892            char *l = NULL;
893           
894            l = p;
895            p += snprintd(p, rdb + rdb_size - p, &rd);
896            len = p - l + 1;
897           
898            bitmaplen = rdlen - len;
899            bmap = (unsigned char *)((unsigned char *)next + len);
900           
901            while (bitmaplen > 0)
902            {
903                int i;
904               
905                if (bitmaplen < 3)
906                {
907                    printf("Case NSEC: malformed nsec, bitmaplen %d short\n", bitmaplen);
908                    break;
909                }   
910               
911                win = *bmap++;
912                wlen = *bmap++;
913                bitmaplen -= 2;
914                if (bitmaplen < wlen || wlen < 1 || wlen > 32)
915                {
916                    printf("Case NSEC: malformed nsec, bitmaplen %d wlen %d\n", bitmaplen, wlen);
917                    break;
918                }
919                if (win < 0 || win >= 256)
920                {
921                    printf("Case NSEC: malformed nsec, bad window win %d\n", win);
922                    break;
923                }
924                type = win * 256;
925                for (i = 0; i < wlen * 8; i++)
926                {
927                    if (bmap[i>>3] & (128 >> (i&7)))
928                        p += snprintf(p, rdb + rdb_size - p, " %s ", DNSTypeName(type + i));
929                }
930                bmap += wlen;
931                bitmaplen -= wlen;
932            }
933            break;
934        }
935           
936        case kDNSServiceType_RRSIG:   
937        {
938            rdataRRSig *rrsig = (rdataRRSig *)rd;
939            unsigned char expTimeBuf[64];
940            unsigned char inceptTimeBuf[64];
941            unsigned long inceptClock;
942            unsigned long expClock;
943            const unsigned char *q = NULL;
944            char *k = NULL;
945            int len;
946           
947            expClock = (unsigned long)swap32(rrsig->sigExpireTime);
948            FormatTime(expClock, expTimeBuf, sizeof(expTimeBuf));
949           
950            inceptClock = (unsigned long)swap32(rrsig->sigInceptTime);
951            FormatTime(inceptClock, inceptTimeBuf, sizeof(inceptTimeBuf));
952           
953            p += snprintf(p, rdb + rdb_size - p, " %-7s  %d  %d  %d  %s  %s  %7d  ",
954                          DNSTypeName(swap16(rrsig->typeCovered)), rrsig->alg, rrsig->labels, swap32(rrsig->origTTL),
955                          expTimeBuf, inceptTimeBuf, swap16(rrsig->keyTag));
956           
957            q = (const unsigned char *)&rrsig->signerName;
958            k = p;
959            p += snprintd(p, rdb + rdb_size - p, &q);
960            len = p - k + 1;
961           
962            base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + len + RRSIG_FIXED_SIZE), rdlen - (len + RRSIG_FIXED_SIZE));
963            break;
964        }
965    }
966    return;                           
967}
968
969static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
970                               const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
971{
972    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
973    const unsigned char *rd  = rdata;
974    const unsigned char *end = (const unsigned char *) rdata + rdlen;
975    char rdb[1000] = "0.0.0.0", *p = rdb;
976    int unknowntype = 0;
977    char dnssec_status[15] = "Unknown";
978    char rr_type[RR_TYPE_SIZE];
979    char rr_class[3];
980    DNSServiceFlags check_flags = flags;//local flags for dnssec status checking
981
982    (void)sdref;    // Unused
983    (void)ifIndex;  // Unused
984    (void)ttl;      // Unused
985    (void)context;  // Unused
986    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
987
988    if (num_printed++ == 0)
989    {
990        if (operation == 'D')
991            printf("Timestamp     A/R if %-30s%-6s%-7s%-18s Rdata\n", "Name", "Type", "Class", "DNSSECStatus");
992        else     
993            printf("Timestamp     A/R Flags if %-30s%-6s%-7s Rdata\n", "Name", "Type", "Class");
994    }
995    printtimestamp();
996
997    switch (rrclass)
998    {
999        case kDNSServiceClass_IN:
1000            strncpy(rr_class, "IN", sizeof(rr_class));
1001            break;
1002        default:
1003            snprintf(rr_class, sizeof(rr_class), "%d", rrclass);
1004            break;
1005    }
1006    strncpy(rr_type, DNSTypeName(rrtype), sizeof(rr_type));
1007
1008    if (!errorCode) //to avoid printing garbage in rdata
1009    {
1010        if (!(check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
1011        {
1012            switch (rrtype)
1013            {
1014                case kDNSServiceType_A:
1015                    snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
1016                    break;
1017   
1018                case kDNSServiceType_NS:
1019                case kDNSServiceType_CNAME:
1020                case kDNSServiceType_PTR:
1021                case kDNSServiceType_DNAME:
1022                    snprintd(p, sizeof(rdb), &rd);
1023                    break;
1024
1025                case kDNSServiceType_SOA:
1026                    p += snprintd(p, rdb + sizeof(rdb) - p, &rd);           // mname
1027                    p += snprintf(p, rdb + sizeof(rdb) - p, " ");
1028                    p += snprintd(p, rdb + sizeof(rdb) - p, &rd);           // rname
1029                         snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
1030                             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]));
1031                    break;
1032
1033                case kDNSServiceType_AAAA:
1034                    snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
1035                        rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
1036                        rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
1037                    break;
1038
1039                case kDNSServiceType_SRV:
1040                    p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ",        // priority, weight, port
1041                             ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
1042                    rd += 6;
1043                         snprintd(p, rdb + sizeof(rdb) - p, &rd);               // target host
1044                    break;
1045
1046                case kDNSServiceType_DS:
1047                case kDNSServiceType_DNSKEY:
1048                case kDNSServiceType_NSEC:
1049                case kDNSServiceType_RRSIG:
1050                    ParseDNSSECRecords(rrtype, rdb, p, rd, rdlen);
1051                    break;
1052
1053                default:
1054                    snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : "");
1055                    unknowntype = 1;
1056                    break;
1057            }   
1058        }   
1059        else
1060        {
1061            strncpy(rdb, "----", sizeof(rdb));
1062            //Clear all o/p bits, and then check for dnssec status
1063            check_flags &= ~kDNSServiceOutputFlags;
1064            if (check_flags & kDNSServiceFlagsSecure)
1065                strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
1066            else if (check_flags & kDNSServiceFlagsInsecure)
1067                strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
1068            else if (check_flags & kDNSServiceFlagsIndeterminate)
1069                strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
1070            else if (check_flags & kDNSServiceFlagsBogus)
1071                strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
1072        }
1073    }
1074
1075    if (operation == 'D')
1076        printf("%s%3d %-30s%-6s%-7s%-18s %s", op, ifIndex, fullname, rr_type, rr_class, dnssec_status, rdb);
1077    else
1078        printf("%s%6X%3d %-30s%-7s%-6s %s", op, flags, ifIndex, fullname, rr_type, rr_class, rdb);
1079    if (unknowntype)
1080    {
1081        while (rd < end)
1082            printf(" %02X", *rd++);
1083    }
1084    if (errorCode)
1085    {
1086        if (errorCode == kDNSServiceErr_NoSuchRecord)
1087            printf("    No Such Record");
1088        else if (errorCode == kDNSServiceErr_Timeout)
1089        {
1090            printf("    No Such Record\n");
1091            printf("Query Timed Out\n");
1092            exit(1);
1093        }
1094    }
1095    printf("\n");
1096
1097    if (operation == 'C')
1098        if (flags & kDNSServiceFlagsAdd)
1099            DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);
1100
1101    if (!(flags & kDNSServiceFlagsMoreComing))
1102        fflush(stdout);
1103}
1104
1105static 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)
1106{
1107    (void)sdref;       // Unused
1108    (void)flags;       // Unused
1109    (void)context;     // Unused
1110    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1111
1112    if (num_printed++ == 0) printf("Timestamp     if   %-20s %-15s %-15s %-15s %-6s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
1113    printtimestamp();
1114    if (errorCode && errorCode != kDNSServiceErr_DoubleNAT) printf("Error code %d\n", errorCode);
1115    else
1116    {
1117        const unsigned char *digits = (const unsigned char *)&publicAddress;
1118        char addr[256];
1119
1120        snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
1121        printf("%-4d %-20s %-15d %-15d %-15d %-6d%s\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl, errorCode == kDNSServiceErr_DoubleNAT ? " Double NAT" : "");
1122    }
1123
1124    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
1125}
1126
1127static 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)
1128{
1129    char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
1130    char addr[256] = "";
1131    char dnssec_status[15] = "Unknown";
1132    DNSServiceFlags check_flags = flags;
1133        (void) sdref;
1134        (void) context;
1135
1136    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1137
1138    if (num_printed++ == 0)
1139    {
1140        if (operation == 'g')
1141            printf("Timestamp     A/R if %-25s %-44s %-18s\n", "Hostname", "Address", "DNSSECStatus");
1142        else 
1143            printf("Timestamp     A/R Flags if %-38s %-44s %s\n", "Hostname", "Address", "TTL");
1144    }
1145    printtimestamp();
1146   
1147    if (address && address->sa_family == AF_INET)
1148    {
1149        const unsigned char *b = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr;
1150        snprintf(addr, sizeof(addr), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
1151    }
1152    else if (address && address->sa_family == AF_INET6)
1153    {
1154        char if_name[IFNAMSIZ];     // Older Linux distributions don't define IF_NAMESIZE
1155        const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)address;
1156        const unsigned char       *b  = (const unsigned char *      )&s6->sin6_addr;
1157        if (!if_indextoname(s6->sin6_scope_id, if_name))
1158            snprintf(if_name, sizeof(if_name), "<%d>", s6->sin6_scope_id);
1159            snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
1160            b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
1161            b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF], if_name);
1162    }
1163
1164    //go through this only if you have a dnssec validation status
1165    if (!errorCode && (check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
1166    {
1167        strncpy(addr, "----", sizeof(addr));
1168        //Clear all o/p bits, and then check for dnssec status
1169        check_flags &= ~kDNSServiceOutputFlags;
1170        if (check_flags & kDNSServiceFlagsSecure)
1171            strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
1172        else if (check_flags & kDNSServiceFlagsInsecure)
1173            strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
1174        else if (check_flags & kDNSServiceFlagsIndeterminate)
1175            strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
1176        else if (check_flags & kDNSServiceFlagsBogus)
1177            strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
1178    }
1179   
1180    if (operation == 'g')
1181        printf("%s%3d %-25s %-44s %-18s", op, interfaceIndex, hostname, addr, dnssec_status);
1182    else
1183        printf("%s%6X%3d %-38s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl);
1184    if (errorCode)
1185    {
1186        if (errorCode == kDNSServiceErr_NoSuchRecord)
1187            printf("   No Such Record");
1188        else
1189            printf("   Error code %d", errorCode);
1190    }
1191    printf("\n");
1192
1193    if (!(flags & kDNSServiceFlagsMoreComing))
1194        fflush(stdout);
1195}
1196
1197//*************************************************************************************************************
1198// The main test function
1199
1200static void HandleEvents(void)
1201#if _DNS_SD_LIBDISPATCH
1202{
1203    main_queue = dispatch_get_main_queue();
1204    if (client) DNSServiceSetDispatchQueue(client, main_queue);
1205    if (client_pa) DNSServiceSetDispatchQueue(client_pa, main_queue);
1206    if (operation == 'A' || operation == 'U' || operation == 'N')
1207    {
1208        timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_queue);
1209        if (timer_source)
1210        {
1211            // Start the timer "timeout" seconds into the future and repeat it every "timeout" seconds
1212            dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
1213                                      (uint64_t)timeOut * NSEC_PER_SEC, 0);
1214            dispatch_source_set_event_handler(timer_source, ^{myTimerCallBack();});
1215            dispatch_resume(timer_source);
1216        }
1217    }
1218    dispatch_main();
1219}
1220#else
1221{
1222    int dns_sd_fd  = client    ? DNSServiceRefSockFD(client   ) : -1;
1223    int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
1224    int nfds = dns_sd_fd + 1;
1225    fd_set readfds;
1226    struct timeval tv;
1227    int result;
1228
1229    if (dns_sd_fd2 > dns_sd_fd) nfds = dns_sd_fd2 + 1;
1230
1231    while (!stopNow)
1232    {
1233        // 1. Set up the fd_set as usual here.
1234        // This example client has no file descriptors of its own,
1235        // but a real application would call FD_SET to add them to the set here
1236        FD_ZERO(&readfds);
1237
1238        // 2. Add the fd for our client(s) to the fd_set
1239        if (client   ) FD_SET(dns_sd_fd, &readfds);
1240        if (client_pa) FD_SET(dns_sd_fd2, &readfds);
1241
1242        // 3. Set up the timeout.
1243        tv.tv_sec  = timeOut;
1244        tv.tv_usec = 0;
1245
1246        result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
1247        if (result > 0)
1248        {
1249            DNSServiceErrorType err = kDNSServiceErr_NoError;
1250            if      (client    && FD_ISSET(dns_sd_fd, &readfds)) err = DNSServiceProcessResult(client   );
1251            else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa);
1252            if (err) { fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; }
1253        }
1254        else if (result == 0)
1255            myTimerCallBack();
1256        else
1257        {
1258            printf("select() returned %d errno %d %s\n", result, errno, strerror(errno));
1259            if (errno != EINTR) stopNow = 1;
1260        }
1261    }
1262}
1263#endif
1264
1265static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
1266// Return the recognized option in optstr and the option index of the next arg.
1267#if NOT_HAVE_GETOPT
1268{
1269    int i;
1270    for (i=1; i < argc; i++)
1271    {
1272        if (argv[i][0] == '-' && &argv[i][1] &&
1273            NULL != strchr(optstr, argv[i][1]))
1274        {
1275            *pOptInd = i + 1;
1276            return argv[i][1];
1277        }
1278    }
1279    return -1;
1280}
1281#else
1282{
1283    int o = getopt(argc, (char *const *)argv, optstr);
1284    *pOptInd = optind;
1285    return o;
1286}
1287#endif
1288
1289static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordRef rec, const DNSServiceFlags flags,
1290                                               DNSServiceErrorType errorCode, void *context)
1291{
1292    char *name = (char *)context;
1293
1294    (void)service;  // Unused
1295    (void)rec;      // Unused
1296    (void)flags;    // Unused
1297    EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
1298
1299    printtimestamp();
1300    printf("Got a reply for record %s: ", name);
1301
1302    switch (errorCode)
1303    {
1304    case kDNSServiceErr_NoError:      printf("Name now registered and active\n"); break;
1305    case kDNSServiceErr_NameConflict: printf("Name in use, please choose another\n"); exit(-1);
1306    default:                          printf("Error %d\n", errorCode); break;
1307    }
1308    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
1309    // DNSServiceRemoveRecord(service, rec, 0); to test record removal
1310
1311#if 0   // To test updating of individual records registered via DNSServiceRegisterRecord
1312    if (!errorCode)
1313    {
1314        int x = 0x11111111;
1315        printf("Updating\n");
1316        DNSServiceUpdateRecord(service, rec, 0, sizeof(x), &x, 0);
1317    }
1318#endif
1319
1320    if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
1321}
1322
1323static void getip(const char *const name, struct sockaddr_storage *result)
1324{
1325    struct addrinfo *addrs = NULL;
1326    int err = getaddrinfo(name, NULL, NULL, &addrs);
1327    if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name);
1328    else memcpy(result, addrs->ai_addr, SA_LEN(addrs->ai_addr));
1329    if (addrs) freeaddrinfo(addrs);
1330}
1331
1332static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip, DNSServiceFlags flags)
1333{
1334    // Call getip() after the call DNSServiceCreateConnection().
1335    // On the Win32 platform, WinSock must be initialized for getip() to succeed.
1336    // Any DNSService* call will initialize WinSock for us, so we make sure
1337    // DNSServiceCreateConnection() is called before getip() is.
1338    struct sockaddr_storage hostaddr;
1339    memset(&hostaddr, 0, sizeof(hostaddr));
1340    getip(ip, &hostaddr);
1341    flags |= kDNSServiceFlagsUnique;
1342    if (hostaddr.ss_family == AF_INET)
1343        return(DNSServiceRegisterRecord(sdref, &record, flags, opinterface, host,
1344                                        kDNSServiceType_A,    kDNSServiceClass_IN,  4, &((struct sockaddr_in *)&hostaddr)->sin_addr,  240, MyRegisterRecordCallback, (void*)host));
1345    else if (hostaddr.ss_family == AF_INET6)
1346        return(DNSServiceRegisterRecord(sdref, &record, flags, opinterface, host,
1347                                        kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &((struct sockaddr_in6*)&hostaddr)->sin6_addr, 240, MyRegisterRecordCallback, (void*)host));
1348    else return(kDNSServiceErr_BadParam);
1349}
1350
1351#define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0'     ) :  \
1352                    ((X) >= 'A' && (X) <= 'F') ? ((X) - 'A' + 10) :  \
1353                    ((X) >= 'a' && (X) <= 'f') ? ((X) - 'a' + 10) : 0)
1354
1355#define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
1356
1357static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
1358                                           const char *nam, const char *typ, const char *dom, const char *host, const char *port, int argc, char **argv, DNSServiceFlags flags)
1359{
1360    uint16_t PortAsNumber = atoi(port);
1361    Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
1362    unsigned char txt[2048] = "";
1363    unsigned char *ptr = txt;
1364    int i;
1365
1366    if (nam[0] == '.' && nam[1] == 0) nam = "";   // We allow '.' on the command line as a synonym for empty string
1367    if (dom[0] == '.' && dom[1] == 0) dom = "";   // We allow '.' on the command line as a synonym for empty string
1368
1369    printf("Registering Service %s.%s%s%s", nam[0] ? nam : "<<Default>>", typ, dom[0] ? "." : "", dom);
1370    if (host && *host) printf(" host %s", host);
1371    printf(" port %s", port);
1372
1373    if (argc)
1374    {
1375        for (i = 0; i < argc; i++)
1376        {
1377            const char *p = argv[i];
1378            *ptr = 0;
1379            while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
1380            {
1381                if      (p[0] != '\\' || p[1] == 0)                       { ptr[++*ptr] = *p;           p+=1; }
1382                else if (p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3])) { ptr[++*ptr] = HexPair(p+2); p+=4; }
1383                else                                                      { ptr[++*ptr] = p[1];         p+=2; }
1384            }
1385            ptr += 1 + *ptr;
1386        }
1387        printf(" TXT");
1388        ShowTXTRecord(ptr-txt, txt);
1389    }
1390    printf("\n");
1391
1392    //flags |= kDNSServiceFlagsAllowRemoteQuery;
1393    //flags |= kDNSServiceFlagsNoAutoRename;
1394
1395    return(DNSServiceRegister(sdref, flags, opinterface, nam, typ, dom, host, registerPort.NotAnInteger, (uint16_t) (ptr-txt), txt, reg_reply, NULL));
1396}
1397
1398#define TypeBufferSize 80
1399static char *gettype(char *buffer, char *typ)
1400{
1401    if (!typ || !*typ || (typ[0] == '.' && typ[1] == 0)) typ = "_http._tcp";
1402    if (!strchr(typ, '.')) { snprintf(buffer, TypeBufferSize, "%s._tcp", typ); typ = buffer; }
1403    return(typ);
1404}
1405
1406int main(int argc, char **argv)
1407{
1408    DNSServiceErrorType err;
1409    char buffer[TypeBufferSize], *typ, *dom;
1410    int opi;
1411    DNSServiceFlags flags = 0;
1412    int optional = 0;
1413
1414    // Extract the program name from argv[0], which by convention contains the path to this executable.
1415    // Note that this is just a voluntary convention, not enforced by the kernel --
1416    // the process calling exec() can pass bogus data in argv[0] if it chooses to.
1417    const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
1418    if (a0 == (const char *)1) a0 = argv[0];
1419
1420#if defined(_WIN32)
1421    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
1422#endif
1423
1424#if TEST_NEW_CLIENTSTUB
1425    printf("Using embedded copy of dnssd_clientstub instead of system library\n");
1426    if (sizeof(argv) == 8) printf("Running in 64-bit mode\n");
1427#endif
1428
1429    // Test code for TXTRecord functions
1430    //TXTRecordRef txtRecord;
1431    //TXTRecordCreate(&txtRecord, 0, NULL);
1432    //TXTRecordSetValue(&txtRecord, "aaa", 1, "b");
1433    //printf("%d\n", TXTRecordContainsKey(TXTRecordGetLength(&txtRecord), TXTRecordGetBytesPtr(&txtRecord), "Aaa"));
1434
1435    if (argc > 1 && !strcmp(argv[1], "-lo"))
1436    {
1437        argc--;
1438        argv++;
1439        opinterface = kDNSServiceInterfaceIndexLocalOnly;
1440        printf("Using LocalOnly\n");
1441    }
1442
1443    if (argc > 1 && (!strcmp(argv[1], "-p2p") || !strcmp(argv[1], "-P2P")))
1444    {
1445        argc--;
1446        argv++;
1447        opinterface = kDNSServiceInterfaceIndexP2P;
1448    }
1449
1450    if (argc > 1 && !strcasecmp(argv[1], "-includep2p"))
1451    {
1452        argc--;
1453        argv++;
1454        flags |= kDNSServiceFlagsIncludeP2P;
1455        printf("Setting kDNSServiceFlagsIncludeP2P\n");
1456    }
1457
1458    if (argc > 1 && !strcasecmp(argv[1], "-includeAWDL"))
1459    {
1460        argc--;
1461        argv++;
1462        flags |= kDNSServiceFlagsIncludeAWDL;
1463        printf("Setting kDNSServiceFlagsIncludeAWDL\n");
1464    }
1465
1466    if (argc > 1 && !strcasecmp(argv[1], "-tc"))
1467    {
1468        argc--;
1469        argv++;
1470        flags |= kDNSServiceFlagsBackgroundTrafficClass;
1471        printf("Setting kDNSServiceFlagsBackgroundTrafficClass\n");
1472    }
1473
1474    if (argc > 1 && !strcasecmp(argv[1], "-t1"))
1475    {
1476        argc--;
1477        argv++;
1478        flags |= kDNSServiceFlagsThresholdOne;
1479        printf("Setting kDNSServiceFlagsThresholdOne\n");
1480    }
1481
1482    if (argc > 1 && !strcasecmp(argv[1], "-tFinder"))
1483    {
1484        argc--;
1485        argv++;
1486        flags |= kDNSServiceFlagsThresholdFinder;
1487        printf("Setting kDNSServiceFlagsThresholdFinder\n");
1488    }
1489
1490    if (argc > 1 && !strcasecmp(argv[1], "-wo"))
1491    {
1492        argc--;
1493        argv++;
1494        flags |= kDNSServiceFlagsWakeOnlyService;
1495        printf("Setting kDNSServiceFlagsWakeOnlyService\n");
1496    }
1497
1498    if (argc > 1 && !strcasecmp(argv[1], "-unicastResponse"))
1499    {
1500        argc--;
1501        argv++;
1502        flags |= kDNSServiceFlagsUnicastResponse;
1503        printf("Setting kDNSServiceFlagsUnicastResponse\n");
1504    }
1505    if (argc > 1 && !strcasecmp(argv[1], "-timeout"))
1506    {
1507        argc--;
1508        argv++;
1509        flags |= kDNSServiceFlagsTimeout;
1510        printf("Setting kDNSServiceFlagsTimeout\n");
1511    }
1512    if (argc > 1 && !strcasecmp(argv[1], "-optional"))
1513    {
1514        argc--;
1515        argv++;
1516        optional = 1;
1517        printf("Setting DNSSEC optional flag\n");
1518    }
1519
1520    if (argc > 2 && !strcmp(argv[1], "-i"))
1521    {
1522        opinterface = if_nametoindex(argv[2]);
1523        if (!opinterface) opinterface = atoi(argv[2]);
1524        if (!opinterface) { fprintf(stderr, "Unknown interface %s\n", argv[2]); goto Fail; }
1525        argc -= 2;
1526        argv += 2;
1527    }
1528
1529    if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
1530    operation = getfirstoption(argc, argv, "EFBZLlRPQqCAUNTMISVHhD"
1531                               "X"
1532                               "Gg"
1533                               , &opi);
1534    if (operation == -1) goto Fail;
1535
1536    if (opinterface) printf("Using interface %d\n", opinterface);
1537
1538    switch (operation)
1539    {
1540    case 'E':   printf("Looking for recommended registration domains:\n");
1541        err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, opinterface, enum_reply, NULL);
1542        break;
1543
1544    case 'F':   printf("Looking for recommended browsing domains:\n");
1545        err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, opinterface, enum_reply, NULL);
1546        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "nicta.com.au.", NULL);
1547        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "bonjour.nicta.com.au.", NULL);
1548        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "ibm.com.", NULL);
1549        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "dns-sd.ibm.com.", NULL);
1550        break;
1551
1552    case 'B':   typ = (argc < opi+1) ? "" : argv[opi+0];
1553        dom = (argc < opi+2) ? "" : argv[opi+1];              // Missing domain argument is the same as empty string i.e. use system default(s)
1554        typ = gettype(buffer, typ);
1555        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;               // We allow '.' on the command line as a synonym for empty string
1556        printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
1557        err = DNSServiceBrowse(&client, flags, opinterface, typ, dom, browse_reply, NULL);
1558        break;
1559
1560    case 'Z':   typ = (argc < opi+1) ? "" : argv[opi+0];
1561        dom = (argc < opi+2) ? "" : argv[opi+1];              // Missing domain argument is the same as empty string i.e. use system default(s)
1562        typ = gettype(buffer, typ);
1563        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;               // We allow '.' on the command line as a synonym for empty string
1564        printf("Browsing for %s%s%s\n", typ, dom[0] ? "." : "", dom);
1565        err = DNSServiceCreateConnection(&client);
1566        if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
1567        sc1 = client;
1568        err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, typ, dom, zonedata_browse, NULL);
1569        break;
1570
1571    case 'l':
1572    case 'L':   {
1573        if (argc < opi+2) goto Fail;
1574        typ = (argc < opi+2) ? ""      : argv[opi+1];
1575        dom = (argc < opi+3) ? "local" : argv[opi+2];
1576        typ = gettype(buffer, typ);
1577        if (dom[0] == '.' && dom[1] == 0) dom = "local";               // We allow '.' on the command line as a synonym for "local"
1578        printf("Lookup %s.%s.%s\n", argv[opi+0], typ, dom);
1579        if (operation == 'l') flags |= kDNSServiceFlagsWakeOnResolve;
1580        err = DNSServiceResolve(&client, flags, opinterface, argv[opi+0], typ, dom, resolve_reply, NULL);
1581        break;
1582    }
1583
1584    case 'R':   if (argc < opi+4) goto Fail;
1585        typ = (argc < opi+2) ? "" : argv[opi+1];
1586        dom = (argc < opi+3) ? "" : argv[opi+2];
1587        typ = gettype(buffer, typ);
1588        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;               // We allow '.' on the command line as a synonym for empty string
1589        err = RegisterService(&client, argv[opi+0], typ, dom, NULL, argv[opi+3], argc-(opi+4), argv+(opi+4), flags);
1590        break;
1591
1592
1593    case 'P':   if (argc < opi+6) goto Fail;
1594        err = DNSServiceCreateConnection(&client_pa);
1595        if (err) { fprintf(stderr, "DNSServiceCreateConnection returned %d\n", err); return(err); }
1596        err = RegisterProxyAddressRecord(client_pa, argv[opi+4], argv[opi+5], flags);
1597        if (err) break;
1598        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);
1599        break;
1600
1601    case 'D':
1602    case 'q':
1603    case 'Q':
1604    case 'C':   {
1605        uint16_t rrtype, rrclass;
1606        flags |= kDNSServiceFlagsReturnIntermediates;
1607        if (operation == 'q')
1608            flags |= kDNSServiceFlagsSuppressUnusable;
1609        if (argc < opi+1)
1610            goto Fail;
1611        rrtype = (argc <= opi+1) ? kDNSServiceType_A  : GetRRType(argv[opi+1]);
1612        rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : GetRRClass(argv[opi+2]);
1613        if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR)
1614            flags |= kDNSServiceFlagsLongLivedQuery;
1615        if (operation == 'D')
1616        {
1617            flags |= kDNSServiceFlagsSuppressUnusable;
1618            if (optional)
1619                flags |= kDNSServiceFlagsValidateOptional;
1620            else
1621                flags |= kDNSServiceFlagsValidate;
1622        }
1623        err = DNSServiceQueryRecord(&client, flags, opinterface, argv[opi+0], rrtype, rrclass, qr_reply, NULL);
1624        break;
1625    }
1626
1627    case 'A':
1628    case 'U':
1629    case 'N':   {
1630        Opaque16 registerPort = { { 0x12, 0x34 } };
1631        static const char TXT[] = "\xC" "First String" "\xD" "Second String" "\xC" "Third String";
1632        printf("Registering Service Test._testupdate._tcp.local.\n");
1633        err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testupdate._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT)-1, TXT, reg_reply, NULL);
1634        break;
1635    }
1636
1637    case 'T':   {
1638        Opaque16 registerPort = { { 0x23, 0x45 } };
1639        char TXT[1024];
1640        unsigned int i;
1641        for (i=0; i<sizeof(TXT); i++)
1642            if ((i & 0x1F) == 0) TXT[i] = 0x1F;else TXT[i] = 'A' + (i >> 5);
1643        printf("Registering Service Test._testlargetxt._tcp.local.\n");
1644        err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testlargetxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT), TXT, reg_reply, NULL);
1645        break;
1646    }
1647
1648    case 'M':   {
1649        pid_t pid = getpid();
1650        Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
1651        static const char TXT1[] = "\xC" "First String"  "\xD" "Second String" "\xC" "Third String";
1652        static const char TXT2[] = "\xD" "Fourth String" "\xC" "Fifth String"  "\xC" "Sixth String";
1653        printf("Registering Service Test._testdualtxt._tcp.local.\n");
1654        err = DNSServiceRegister(&client, flags, opinterface, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
1655        if (!err) err = DNSServiceAddRecord(client, &record, flags, kDNSServiceType_TXT, sizeof(TXT2)-1, TXT2, 0);
1656        break;
1657    }
1658
1659    case 'I':   {
1660        pid_t pid = getpid();
1661        Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
1662        static const char TXT[] = "\x09" "Test Data";
1663        printf("Registering Service Test._testtxt._tcp.local.\n");
1664        err = DNSServiceRegister(&client, 0, opinterface, "Test", "_testtxt._tcp.", "", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
1665        if (!err) err = DNSServiceUpdateRecord(client, NULL, 0, sizeof(TXT)-1, TXT, 0);
1666        break;
1667    }
1668
1669    case 'X':   {
1670        if (argc == opi)                // If no arguments, just fetch IP address
1671            err = DNSServiceNATPortMappingCreate(&client, 0, 0, 0, 0, 0, 0, port_mapping_create_reply, NULL);
1672        else if (argc >= opi+2 && atoi(argv[opi+0]) == 0)
1673        {
1674            DNSServiceProtocol prot  = GetProtocol(argv[opi+0]);                                    // Must specify TCP or UDP
1675            uint16_t IntPortAsNumber = atoi(argv[opi+1]);                                       // Must specify internal port
1676            uint16_t ExtPortAsNumber = (argc < opi+3) ? 0 : atoi(argv[opi+2]);              // Optional desired external port
1677            uint32_t ttl             = (argc < opi+4) ? 0 : atoi(argv[opi+3]);              // Optional desired lease lifetime
1678            Opaque16 intp = { { IntPortAsNumber >> 8, IntPortAsNumber & 0xFF } };
1679            Opaque16 extp = { { ExtPortAsNumber >> 8, ExtPortAsNumber & 0xFF } };
1680            err = DNSServiceNATPortMappingCreate(&client, 0, 0, prot, intp.NotAnInteger, extp.NotAnInteger, ttl, port_mapping_create_reply, NULL);
1681        }
1682        else goto Fail;
1683        break;
1684    }
1685
1686    case 'g':
1687    case 'G':   {
1688        flags |= kDNSServiceFlagsReturnIntermediates;
1689        if (operation == 'g')
1690        {
1691            flags |= kDNSServiceFlagsSuppressUnusable;
1692            if (optional)
1693                flags |= kDNSServiceFlagsValidateOptional;
1694            else
1695                flags |= kDNSServiceFlagsValidate;
1696        }
1697        if (argc != opi+2)
1698            goto Fail;
1699        else
1700            err = DNSServiceGetAddrInfo(&client, flags, opinterface, GetProtocol(argv[opi+0]), argv[opi+1], addrinfo_reply, NULL);
1701        break;
1702    }
1703
1704    case 'S':   {
1705        Opaque16 registerPort = { { 0x23, 0x45 } };                 // 9029 decimal
1706        unsigned char txtrec[16] = "\xF" "/path=test.html";
1707        DNSRecordRef rec;
1708        unsigned char nulrec[4] = "1234";
1709
1710        err = DNSServiceCreateConnection(&client);
1711        if (err) { fprintf(stderr, "DNSServiceCreateConnection failed %ld\n", (long int)err); return (-1); }
1712
1713        sc1 = client;
1714        err = DNSServiceBrowse(&sc1, kDNSServiceFlagsShareConnection, opinterface, "_http._tcp", "", browse_reply, NULL);
1715        if (err) { fprintf(stderr, "DNSServiceBrowse _http._tcp failed %ld\n", (long int)err); return (-1); }
1716
1717        sc2 = client;
1718        err = DNSServiceBrowse(&sc2, kDNSServiceFlagsShareConnection, opinterface, "_ftp._tcp", "", browse_reply, NULL);
1719        if (err) { fprintf(stderr, "DNSServiceBrowse _ftp._tcp failed %ld\n", (long int)err); return (-1); }
1720
1721        sc3 = client;
1722        err = DNSServiceRegister(&sc3, kDNSServiceFlagsShareConnection, opinterface, "kDNSServiceFlagsShareConnection",
1723                                 "_http._tcp", "local", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
1724        if (err) { fprintf(stderr, "SharedConnection DNSServiceRegister failed %ld\n", (long int)err); return (-1); }
1725
1726        err = DNSServiceUpdateRecord(sc3, NULL, 0, sizeof(txtrec), txtrec, 0);
1727        if (err) { fprintf(stderr, "SharedConnection DNSServiceUpdateRecord failed %ld\n", (long int)err); return (-1); }
1728
1729        err = DNSServiceAddRecord(sc3, &rec, 0, kDNSServiceType_NULL, sizeof(nulrec), nulrec, 0);
1730        if (err) { fprintf(stderr, "SharedConnection DNSServiceAddRecord failed %ld\n", (long int)err); return (-1); }
1731
1732        err = DNSServiceRemoveRecord(sc3, rec, 0);
1733        if (err) { fprintf(stderr, "SharedConnection DNSServiceRemoveRecord failed %ld\n", (long int)err); return (-1); }
1734
1735        break;
1736    }
1737
1738    case 'V':   {
1739        uint32_t v;
1740        uint32_t size = sizeof(v);
1741        err = DNSServiceGetProperty(kDNSServiceProperty_DaemonVersion, &v, &size);
1742        if (err) fprintf(stderr, "DNSServiceGetProperty failed %ld\n", (long int)err);
1743        else printf("Currently running daemon (system service) is version %d.%d.%d\n",  v / 10000, v / 100 % 100, v % 100);
1744        exit(0);
1745    }
1746
1747    case 'H': goto Fail;
1748
1749    default: goto Fail;
1750    }
1751
1752    if (!client || err != kDNSServiceErr_NoError)
1753    {
1754        fprintf(stderr, "DNSService call failed %ld%s\n", (long int)err,
1755            (err == kDNSServiceErr_ServiceNotRunning) ? " (Service Not Running)" : "");
1756        return (-1);
1757    }
1758    printtimestamp();
1759    printf("...STARTING...\n");
1760    HandleEvents();
1761
1762    // Be sure to deallocate the DNSServiceRef when you're finished
1763    if (client   ) DNSServiceRefDeallocate(client   );
1764    if (client_pa) DNSServiceRefDeallocate(client_pa);
1765    return 0;
1766
1767Fail:
1768    if (operation == 'H') print_usage(a0,1);
1769    else print_usage(a0,0);
1770    return 0;
1771
1772}
1773
1774// Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
1775// e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
1776// To expand "version" to its value before making the string, use STRINGIFY(version) instead
1777#define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) # s
1778#define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
1779
1780// NOT static -- otherwise the compiler may optimize it out
1781// The "@(#) " pattern is a special prefix the "what" command looks for
1782const char VersionString_SCCS[] = "@(#) dns-sd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
1783
1784#if _BUILDING_XCODE_PROJECT_
1785// If the process crashes, then this string will be magically included in the automatically-generated crash log
1786const char *__crashreporter_info__ = VersionString_SCCS + 5;
1787asm (".desc ___crashreporter_info__, 0x10");
1788#endif
Note: See TracBrowser for help on using the repository browser.