15ffb0c9bSToomas Soome /* -*- Mode: C; tab-width: 4 -*-
25ffb0c9bSToomas Soome  *
3cda73f64SToomas Soome  * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
45ffb0c9bSToomas Soome  *
5cda73f64SToomas Soome  * Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Inc.
65ffb0c9bSToomas Soome  * ("Apple") in consideration of your agreement to the following terms, and your
75ffb0c9bSToomas Soome  * use, installation, modification or redistribution of this Apple software
85ffb0c9bSToomas Soome  * constitutes acceptance of these terms.  If you do not agree with these terms,
95ffb0c9bSToomas Soome  * please do not use, install, modify or redistribute this Apple software.
105ffb0c9bSToomas Soome  *
115ffb0c9bSToomas Soome  * In consideration of your agreement to abide by the following terms, and subject
125ffb0c9bSToomas Soome  * to these terms, Apple grants you a personal, non-exclusive license, under Apple's
135ffb0c9bSToomas Soome  * copyrights in this original Apple software (the "Apple Software"), to use,
145ffb0c9bSToomas Soome  * reproduce, modify and redistribute the Apple Software, with or without
155ffb0c9bSToomas Soome  * modifications, in source and/or binary forms; provided that if you redistribute
165ffb0c9bSToomas Soome  * the Apple Software in its entirety and without modifications, you must retain
175ffb0c9bSToomas Soome  * this notice and the following text and disclaimers in all such redistributions of
185ffb0c9bSToomas Soome  * the Apple Software.  Neither the name, trademarks, service marks or logos of
19cda73f64SToomas Soome  * Apple Inc. may be used to endorse or promote products derived from the
205ffb0c9bSToomas Soome  * Apple Software without specific prior written permission from Apple.  Except as
215ffb0c9bSToomas Soome  * expressly stated in this notice, no other rights or licenses, express or implied,
225ffb0c9bSToomas Soome  * are granted by Apple herein, including but not limited to any patent rights that
235ffb0c9bSToomas Soome  * may be infringed by your derivative works or by other works in which the Apple
245ffb0c9bSToomas Soome  * Software may be incorporated.
255ffb0c9bSToomas Soome  *
265ffb0c9bSToomas Soome  * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
315ffb0c9bSToomas Soome  *
395ffb0c9bSToomas Soome  *
405ffb0c9bSToomas Soome    To build this tool, copy and paste the following into a command line:
415ffb0c9bSToomas Soome 
425ffb0c9bSToomas Soome    OS X:
435ffb0c9bSToomas Soome    gcc dns-sd.c -o dns-sd
445ffb0c9bSToomas Soome 
455ffb0c9bSToomas Soome    POSIX systems:
465ffb0c9bSToomas Soome    gcc dns-sd.c -o dns-sd -I../mDNSShared -ldns_sd
475ffb0c9bSToomas Soome 
485ffb0c9bSToomas Soome    Windows:
495ffb0c9bSToomas Soome    cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Release\dnssd.lib
505ffb0c9bSToomas Soome    (may require that you run a Visual Studio script such as vsvars32.bat first)
515ffb0c9bSToomas Soome  */
525ffb0c9bSToomas Soome 
535ffb0c9bSToomas Soome // For testing changes to dnssd_clientstub.c, uncomment this line and the code will be compiled
545ffb0c9bSToomas Soome // with an embedded copy of the client stub instead of linking the system library version at runtime.
555ffb0c9bSToomas Soome // This also useful to work around link errors when you're working on an older version of Mac OS X,
565ffb0c9bSToomas Soome // and trying to build a newer version of the "dns-sd" command which uses new API entry points that
575ffb0c9bSToomas Soome // aren't in the system's /usr/lib/libSystem.dylib.
585ffb0c9bSToomas Soome //#define TEST_NEW_CLIENTSTUB 1
595ffb0c9bSToomas Soome 
605ffb0c9bSToomas Soome #include <ctype.h>
615ffb0c9bSToomas Soome #include <stdio.h>          // For stdout, stderr
625ffb0c9bSToomas Soome #include <stdlib.h>         // For exit()
635ffb0c9bSToomas Soome #include <string.h>         // For strlen(), strcpy()
645ffb0c9bSToomas Soome #include <errno.h>          // For errno, EINTR
655ffb0c9bSToomas Soome #include <time.h>
665ffb0c9bSToomas Soome #include <sys/types.h>      // For u_char
675ffb0c9bSToomas Soome 
685ffb0c9bSToomas Soome #ifdef _WIN32
695ffb0c9bSToomas Soome     #include <winsock2.h>
705ffb0c9bSToomas Soome     #include <ws2tcpip.h>
715ffb0c9bSToomas Soome     #include <Iphlpapi.h>
725ffb0c9bSToomas Soome     #include <process.h>
735ffb0c9bSToomas Soome typedef int pid_t;
745ffb0c9bSToomas Soome     #define getpid     _getpid
755ffb0c9bSToomas Soome     #define strcasecmp _stricmp
765ffb0c9bSToomas Soome     #define snprintf   _snprintf
775ffb0c9bSToomas Soome static const char kFilePathSep = '\\';
785ffb0c9bSToomas Soome     #ifndef HeapEnableTerminationOnCorruption
795ffb0c9bSToomas Soome     #     define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
805ffb0c9bSToomas Soome     #endif
815ffb0c9bSToomas Soome     #if !defined(IFNAMSIZ)
825ffb0c9bSToomas Soome      #define IFNAMSIZ 16
835ffb0c9bSToomas Soome     #endif
845ffb0c9bSToomas Soome     #define if_nametoindex if_nametoindex_win
855ffb0c9bSToomas Soome     #define if_indextoname if_indextoname_win
865ffb0c9bSToomas Soome 
875ffb0c9bSToomas Soome typedef PCHAR (WINAPI * if_indextoname_funcptr_t)(ULONG index, PCHAR name);
885ffb0c9bSToomas Soome typedef ULONG (WINAPI * if_nametoindex_funcptr_t)(PCSTR name);
895ffb0c9bSToomas Soome 
if_nametoindex_win(const char * ifname)905ffb0c9bSToomas Soome unsigned if_nametoindex_win(const char *ifname)
915ffb0c9bSToomas Soome {
925ffb0c9bSToomas Soome     HMODULE library;
935ffb0c9bSToomas Soome     unsigned index = 0;
945ffb0c9bSToomas Soome 
955ffb0c9bSToomas Soome     // Try and load the IP helper library dll
965ffb0c9bSToomas Soome     if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
975ffb0c9bSToomas Soome     {
985ffb0c9bSToomas Soome         if_nametoindex_funcptr_t if_nametoindex_funcptr;
995ffb0c9bSToomas Soome 
1005ffb0c9bSToomas Soome         // On Vista and above there is a Posix like implementation of if_nametoindex
1015ffb0c9bSToomas Soome         if ((if_nametoindex_funcptr = (if_nametoindex_funcptr_t) GetProcAddress(library, "if_nametoindex")) != NULL )
1025ffb0c9bSToomas Soome         {
1035ffb0c9bSToomas Soome             index = if_nametoindex_funcptr(ifname);
1045ffb0c9bSToomas Soome         }
1055ffb0c9bSToomas Soome 
1065ffb0c9bSToomas Soome         FreeLibrary(library);
1075ffb0c9bSToomas Soome     }
1085ffb0c9bSToomas Soome 
1095ffb0c9bSToomas Soome     return index;
1105ffb0c9bSToomas Soome }
1115ffb0c9bSToomas Soome 
if_indextoname_win(unsigned ifindex,char * ifname)1125ffb0c9bSToomas Soome char * if_indextoname_win( unsigned ifindex, char *ifname)
1135ffb0c9bSToomas Soome {
1145ffb0c9bSToomas Soome     HMODULE library;
1155ffb0c9bSToomas Soome     char * name = NULL;
1165ffb0c9bSToomas Soome 
1175ffb0c9bSToomas Soome     // Try and load the IP helper library dll
1185ffb0c9bSToomas Soome     if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
1195ffb0c9bSToomas Soome     {
1205ffb0c9bSToomas Soome         if_indextoname_funcptr_t if_indextoname_funcptr;
1215ffb0c9bSToomas Soome 
1225ffb0c9bSToomas Soome         // On Vista and above there is a Posix like implementation of if_indextoname
1235ffb0c9bSToomas Soome         if ((if_indextoname_funcptr = (if_indextoname_funcptr_t) GetProcAddress(library, "if_indextoname")) != NULL )
1245ffb0c9bSToomas Soome         {
1255ffb0c9bSToomas Soome             name = if_indextoname_funcptr(ifindex, ifname);
1265ffb0c9bSToomas Soome         }
1275ffb0c9bSToomas Soome 
1285ffb0c9bSToomas Soome         FreeLibrary(library);
1295ffb0c9bSToomas Soome     }
1305ffb0c9bSToomas Soome 
1315ffb0c9bSToomas Soome     return name;
1325ffb0c9bSToomas Soome }
1335ffb0c9bSToomas Soome 
_sa_len(const struct sockaddr * addr)1345ffb0c9bSToomas Soome static size_t _sa_len(const struct sockaddr *addr)
1355ffb0c9bSToomas Soome {
1365ffb0c9bSToomas Soome     if (addr->sa_family == AF_INET) return (sizeof(struct sockaddr_in));
1375ffb0c9bSToomas Soome     else if (addr->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6));
1385ffb0c9bSToomas Soome     else return (sizeof(struct sockaddr));
1395ffb0c9bSToomas Soome }
1405ffb0c9bSToomas Soome 
1415ffb0c9bSToomas Soome #   define SA_LEN(addr) (_sa_len(addr))
1425ffb0c9bSToomas Soome 
1435ffb0c9bSToomas Soome #else
1445ffb0c9bSToomas Soome     #include <unistd.h>         // For getopt() and optind
1455ffb0c9bSToomas Soome     #include <netdb.h>          // For getaddrinfo()
1465ffb0c9bSToomas Soome     #include <sys/time.h>       // For struct timeval
1475ffb0c9bSToomas Soome     #include <sys/socket.h>     // For AF_INET
1485ffb0c9bSToomas Soome     #include <netinet/in.h>     // For struct sockaddr_in()
1495ffb0c9bSToomas Soome     #include <arpa/inet.h>      // For inet_addr()
1505ffb0c9bSToomas Soome     #include <net/if.h>         // For if_nametoindex()
1515ffb0c9bSToomas Soome static const char kFilePathSep = '/';
1525ffb0c9bSToomas Soome // #ifndef NOT_HAVE_SA_LEN
1535ffb0c9bSToomas Soome //  #define SA_LEN(addr) ((addr)->sa_len)
1545ffb0c9bSToomas Soome // #else
1555ffb0c9bSToomas Soome     #define SA_LEN(addr) (((addr)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
1565ffb0c9bSToomas Soome // #endif
1575ffb0c9bSToomas Soome #endif
1585ffb0c9bSToomas Soome 
1595ffb0c9bSToomas Soome #if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
1605ffb0c9bSToomas Soome #define __APPLE_API_PRIVATE 1
1615ffb0c9bSToomas Soome #endif
1625ffb0c9bSToomas Soome 
1635ffb0c9bSToomas Soome // DNSServiceSetDispatchQueue is not supported on 10.6 & prior
1655ffb0c9bSToomas Soome #undef _DNS_SD_LIBDISPATCH
1665ffb0c9bSToomas Soome #endif
1675ffb0c9bSToomas Soome #include "dns_sd.h"
168c65ebfc7SToomas Soome #include "dns_sd_internal.h"
1695ffb0c9bSToomas Soome #include "ClientCommon.h"
1705ffb0c9bSToomas Soome 
1715ffb0c9bSToomas Soome #if TEST_NEW_CLIENTSTUB
1725ffb0c9bSToomas Soome #include "../mDNSShared/dnssd_ipc.c"
1735ffb0c9bSToomas Soome #include "../mDNSShared/dnssd_clientlib.c"
1745ffb0c9bSToomas Soome #include "../mDNSShared/dnssd_clientstub.c"
1755ffb0c9bSToomas Soome #endif
1765ffb0c9bSToomas Soome 
1775ffb0c9bSToomas Soome //*************************************************************************************************************
1785ffb0c9bSToomas Soome // Globals
1795ffb0c9bSToomas Soome 
1805ffb0c9bSToomas Soome #define DS_FIXED_SIZE   4
1815ffb0c9bSToomas Soome typedef struct
1825ffb0c9bSToomas Soome {
1835ffb0c9bSToomas Soome     unsigned short keyTag;
184c1de7575SRichard Lowe     unsigned char alg;
1855ffb0c9bSToomas Soome     unsigned char digestType;
1865ffb0c9bSToomas Soome     unsigned char  *digest;
1875ffb0c9bSToomas Soome } rdataDS;
1885ffb0c9bSToomas Soome 
1895ffb0c9bSToomas Soome #define DNSKEY_FIXED_SIZE    4
1905ffb0c9bSToomas Soome typedef struct
1915ffb0c9bSToomas Soome {
1925ffb0c9bSToomas Soome     unsigned short flags;
1935ffb0c9bSToomas Soome     unsigned char proto;
1945ffb0c9bSToomas Soome     unsigned char alg;
1955ffb0c9bSToomas Soome     unsigned char *data;
1965ffb0c9bSToomas Soome } rdataDNSKey;
1975ffb0c9bSToomas Soome 
198c1de7575SRichard Lowe //size of rdataRRSIG excluding signerName and signature (which are variable fields)
1995ffb0c9bSToomas Soome #define RRSIG_FIXED_SIZE      18
2005ffb0c9bSToomas Soome typedef struct
2015ffb0c9bSToomas Soome {
2025ffb0c9bSToomas Soome     unsigned short typeCovered;
203c1de7575SRichard Lowe     unsigned char alg;
2045ffb0c9bSToomas Soome     unsigned char labels;
2055ffb0c9bSToomas Soome     unsigned int origTTL;
2065ffb0c9bSToomas Soome     unsigned int sigExpireTime;
2075ffb0c9bSToomas Soome     unsigned int sigInceptTime;
2085ffb0c9bSToomas Soome     unsigned short keyTag;
2095ffb0c9bSToomas Soome     char signerName[256];
2105ffb0c9bSToomas Soome     //unsigned char *signature
2115ffb0c9bSToomas Soome } rdataRRSig;
2125ffb0c9bSToomas Soome 
2135ffb0c9bSToomas Soome #define RR_TYPE_SIZE 16
2145ffb0c9bSToomas Soome 
2155ffb0c9bSToomas Soome typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
2165ffb0c9bSToomas Soome 
2175ffb0c9bSToomas Soome static int operation;
2185ffb0c9bSToomas Soome static uint32_t opinterface = kDNSServiceInterfaceIndexAny;
2195ffb0c9bSToomas Soome static DNSServiceRef client    = NULL;
2205ffb0c9bSToomas Soome static DNSServiceRef client_pa = NULL;  // DNSServiceRef for RegisterProxyAddressRecord
2215ffb0c9bSToomas Soome static DNSServiceRef sc1, sc2, sc3;     // DNSServiceRefs for kDNSServiceFlagsShareConnection testing
2225ffb0c9bSToomas Soome 
2235ffb0c9bSToomas Soome static int num_printed;
2245ffb0c9bSToomas Soome static char addtest = 0;
2255ffb0c9bSToomas Soome static DNSRecordRef record = NULL;
2265ffb0c9bSToomas Soome static char myhinfoW[14] = "\002PC\012Windows XP";
2275ffb0c9bSToomas Soome static char myhinfoX[ 9] = "\003Mac\004OS X";
2285ffb0c9bSToomas Soome static char updatetest[3] = "\002AA";
2295ffb0c9bSToomas Soome static char bigNULL[8192];  // 8K is maximum rdata we support
2305ffb0c9bSToomas Soome 
2315ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
2325ffb0c9bSToomas Soome dispatch_queue_t main_queue;
2335ffb0c9bSToomas Soome dispatch_source_t timer_source;
2345ffb0c9bSToomas Soome #endif
2355ffb0c9bSToomas Soome 
2365ffb0c9bSToomas Soome // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
2375ffb0c9bSToomas Soome #define LONG_TIME 100000000
2385ffb0c9bSToomas Soome 
2395ffb0c9bSToomas Soome static volatile int stopNow = 0;
2405ffb0c9bSToomas Soome static volatile int timeOut = LONG_TIME;
2415ffb0c9bSToomas Soome 
2425ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
2435ffb0c9bSToomas Soome #define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E) \
2445ffb0c9bSToomas Soome     if (main_queue && (E) == kDNSServiceErr_ServiceNotRunning) { fprintf(stderr, "Error code %d\n", (E)); exit(0); }
2455ffb0c9bSToomas Soome #else
2465ffb0c9bSToomas Soome #define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E)
2475ffb0c9bSToomas Soome #endif
2485ffb0c9bSToomas Soome 
2495ffb0c9bSToomas Soome //*************************************************************************************************************
2505ffb0c9bSToomas Soome // Supporting Utility Functions
GetRRClass(const char * s)251c1de7575SRichard Lowe static uint16_t GetRRClass(const char *s)
2525ffb0c9bSToomas Soome {
253c1de7575SRichard Lowe     if (!strcasecmp(s, "IN"))
2545ffb0c9bSToomas Soome         return kDNSServiceClass_IN;
2555ffb0c9bSToomas Soome     else
2565ffb0c9bSToomas Soome         return(atoi(s));
257c1de7575SRichard Lowe }
2585ffb0c9bSToomas Soome 
GetRRType(const char * s)2595ffb0c9bSToomas Soome static uint16_t GetRRType(const char *s)
2605ffb0c9bSToomas Soome {
2615ffb0c9bSToomas Soome     if      (!strcasecmp(s, "A"       )) return(kDNSServiceType_A);
2625ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NS"      )) return(kDNSServiceType_NS);
2635ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MD"      )) return(kDNSServiceType_MD);
2645ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MF"      )) return(kDNSServiceType_MF);
2655ffb0c9bSToomas Soome     else if (!strcasecmp(s, "CNAME"   )) return(kDNSServiceType_CNAME);
2665ffb0c9bSToomas Soome     else if (!strcasecmp(s, "SOA"     )) return(kDNSServiceType_SOA);
2675ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MB"      )) return(kDNSServiceType_MB);
2685ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MG"      )) return(kDNSServiceType_MG);
2695ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MR"      )) return(kDNSServiceType_MR);
2705ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NULL"    )) return(kDNSServiceType_NULL);
2715ffb0c9bSToomas Soome     else if (!strcasecmp(s, "WKS"     )) return(kDNSServiceType_WKS);
2725ffb0c9bSToomas Soome     else if (!strcasecmp(s, "PTR"     )) return(kDNSServiceType_PTR);
2735ffb0c9bSToomas Soome     else if (!strcasecmp(s, "HINFO"   )) return(kDNSServiceType_HINFO);
2745ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MINFO"   )) return(kDNSServiceType_MINFO);
2755ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MX"      )) return(kDNSServiceType_MX);
2765ffb0c9bSToomas Soome     else if (!strcasecmp(s, "TXT"     )) return(kDNSServiceType_TXT);
2775ffb0c9bSToomas Soome     else if (!strcasecmp(s, "RP"      )) return(kDNSServiceType_RP);
2785ffb0c9bSToomas Soome     else if (!strcasecmp(s, "AFSDB"   )) return(kDNSServiceType_AFSDB);
2795ffb0c9bSToomas Soome     else if (!strcasecmp(s, "X25"     )) return(kDNSServiceType_X25);
2805ffb0c9bSToomas Soome     else if (!strcasecmp(s, "ISDN"    )) return(kDNSServiceType_ISDN);
2815ffb0c9bSToomas Soome     else if (!strcasecmp(s, "RT"      )) return(kDNSServiceType_RT);
2825ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NSAP"    )) return(kDNSServiceType_NSAP);
2835ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NSAP_PTR")) return(kDNSServiceType_NSAP_PTR);
2845ffb0c9bSToomas Soome     else if (!strcasecmp(s, "SIG"     )) return(kDNSServiceType_SIG);
2855ffb0c9bSToomas Soome     else if (!strcasecmp(s, "KEY"     )) return(kDNSServiceType_KEY);
2865ffb0c9bSToomas Soome     else if (!strcasecmp(s, "PX"      )) return(kDNSServiceType_PX);
2875ffb0c9bSToomas Soome     else if (!strcasecmp(s, "GPOS"    )) return(kDNSServiceType_GPOS);
2885ffb0c9bSToomas Soome     else if (!strcasecmp(s, "AAAA"    )) return(kDNSServiceType_AAAA);
2895ffb0c9bSToomas Soome     else if (!strcasecmp(s, "LOC"     )) return(kDNSServiceType_LOC);
2905ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NXT"     )) return(kDNSServiceType_NXT);
2915ffb0c9bSToomas Soome     else if (!strcasecmp(s, "EID"     )) return(kDNSServiceType_EID);
2925ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NIMLOC"  )) return(kDNSServiceType_NIMLOC);
2935ffb0c9bSToomas Soome     else if (!strcasecmp(s, "SRV"     )) return(kDNSServiceType_SRV);
2945ffb0c9bSToomas Soome     else if (!strcasecmp(s, "ATMA"    )) return(kDNSServiceType_ATMA);
2955ffb0c9bSToomas Soome     else if (!strcasecmp(s, "NAPTR"   )) return(kDNSServiceType_NAPTR);
2965ffb0c9bSToomas Soome     else if (!strcasecmp(s, "KX"      )) return(kDNSServiceType_KX);
2975ffb0c9bSToomas Soome     else if (!strcasecmp(s, "CERT"    )) return(kDNSServiceType_CERT);
2985ffb0c9bSToomas Soome     else if (!strcasecmp(s, "A6"      )) return(kDNSServiceType_A6);
2995ffb0c9bSToomas Soome     else if (!strcasecmp(s, "DNAME"   )) return(kDNSServiceType_DNAME);
3005ffb0c9bSToomas Soome     else if (!strcasecmp(s, "SINK"    )) return(kDNSServiceType_SINK);
3015ffb0c9bSToomas Soome     else if (!strcasecmp(s, "OPT"     )) return(kDNSServiceType_OPT);
3025ffb0c9bSToomas Soome     else if (!strcasecmp(s, "TKEY"    )) return(kDNSServiceType_TKEY);
3035ffb0c9bSToomas Soome     else if (!strcasecmp(s, "TSIG"    )) return(kDNSServiceType_TSIG);
3045ffb0c9bSToomas Soome     else if (!strcasecmp(s, "IXFR"    )) return(kDNSServiceType_IXFR);
3055ffb0c9bSToomas Soome     else if (!strcasecmp(s, "AXFR"    )) return(kDNSServiceType_AXFR);
3065ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MAILB"   )) return(kDNSServiceType_MAILB);
3075ffb0c9bSToomas Soome     else if (!strcasecmp(s, "MAILA"   )) return(kDNSServiceType_MAILA);
3085ffb0c9bSToomas Soome     else if (!strcasecmp(s, "dnskey"  )) return(kDNSServiceType_DNSKEY);
3095ffb0c9bSToomas Soome     else if (!strcasecmp(s, "ds"      )) return(kDNSServiceType_DS);
3105ffb0c9bSToomas Soome     else if (!strcasecmp(s, "rrsig"   )) return(kDNSServiceType_RRSIG);
3115ffb0c9bSToomas Soome     else if (!strcasecmp(s, "nsec"    )) return(kDNSServiceType_NSEC);
3125ffb0c9bSToomas Soome     else if (!strcasecmp(s, "ANY"     )) return(kDNSServiceType_ANY);
3135ffb0c9bSToomas Soome     else return(atoi(s));
3145ffb0c9bSToomas Soome }
3155ffb0c9bSToomas Soome 
DNSTypeName(unsigned short rr_type)3165ffb0c9bSToomas Soome static char *DNSTypeName(unsigned short rr_type)
3175ffb0c9bSToomas Soome {
3185ffb0c9bSToomas Soome     switch (rr_type)
3195ffb0c9bSToomas Soome     {
320c65ebfc7SToomas Soome         case kDNSServiceType_A:          return("Addr");
321c65ebfc7SToomas Soome         case kDNSServiceType_NS:         return("NS");
322c65ebfc7SToomas Soome         case kDNSServiceType_MD:         return("MD");
323c65ebfc7SToomas Soome         case kDNSServiceType_MF:         return("MF");
324c65ebfc7SToomas Soome         case kDNSServiceType_CNAME:      return("CNAME");
325c65ebfc7SToomas Soome         case kDNSServiceType_SOA:        return("SOA");
326c65ebfc7SToomas Soome         case kDNSServiceType_MB:         return("MB");
327c65ebfc7SToomas Soome         case kDNSServiceType_MG:         return("MG");
328c65ebfc7SToomas Soome         case kDNSServiceType_MR:         return("MR");
329c65ebfc7SToomas Soome         case kDNSServiceType_NULL:       return("NULL");
330c65ebfc7SToomas Soome         case kDNSServiceType_WKS:        return("WKS");
331c65ebfc7SToomas Soome         case kDNSServiceType_PTR:        return("PTR");
332c65ebfc7SToomas Soome         case kDNSServiceType_HINFO:      return("HINFO");
333c65ebfc7SToomas Soome         case kDNSServiceType_MINFO:      return("MINFO");
334c65ebfc7SToomas Soome         case kDNSServiceType_MX:         return("MX");
335c65ebfc7SToomas Soome         case kDNSServiceType_TXT:        return("TXT");
336c65ebfc7SToomas Soome         case kDNSServiceType_RP:         return("RP");
337c65ebfc7SToomas Soome         case kDNSServiceType_AFSDB:      return("AFSDB");
338c65ebfc7SToomas Soome         case kDNSServiceType_X25:        return("X25");
339c65ebfc7SToomas Soome         case kDNSServiceType_ISDN:       return("ISDN");
340c65ebfc7SToomas Soome         case kDNSServiceType_RT:         return("RT");
341c65ebfc7SToomas Soome         case kDNSServiceType_NSAP:       return("NSAP");
342c65ebfc7SToomas Soome         case kDNSServiceType_NSAP_PTR:   return("NSAP_PTR");
343c65ebfc7SToomas Soome         case kDNSServiceType_SIG:        return("SIG");
344c65ebfc7SToomas Soome         case kDNSServiceType_KEY:        return("KEY");
345c65ebfc7SToomas Soome         case kDNSServiceType_PX:         return("PX");
346c65ebfc7SToomas Soome         case kDNSServiceType_GPOS:       return("GPOS");
347c65ebfc7SToomas Soome         case kDNSServiceType_AAAA:       return("AAAA");
348c65ebfc7SToomas Soome         case kDNSServiceType_LOC:        return("LOC");
349c65ebfc7SToomas Soome         case kDNSServiceType_NXT:        return("NXT");
350c65ebfc7SToomas Soome         case kDNSServiceType_EID:        return("EID");
351c65ebfc7SToomas Soome         case kDNSServiceType_NIMLOC:     return("NIMLOC");
352c65ebfc7SToomas Soome         case kDNSServiceType_SRV:        return("SRV");
353c65ebfc7SToomas Soome         case kDNSServiceType_ATMA:       return("ATMA");
354c65ebfc7SToomas Soome         case kDNSServiceType_NAPTR:      return("NAPTR");
355c65ebfc7SToomas Soome         case kDNSServiceType_KX:         return("KX");
356c65ebfc7SToomas Soome         case kDNSServiceType_CERT:       return("CERT");
357c65ebfc7SToomas Soome         case kDNSServiceType_A6:         return("A6");
358c65ebfc7SToomas Soome         case kDNSServiceType_DNAME:      return("DNAME");
359c65ebfc7SToomas Soome         case kDNSServiceType_SINK:       return("SINK");
360c65ebfc7SToomas Soome         case kDNSServiceType_OPT:        return("OPT");
361c65ebfc7SToomas Soome         case kDNSServiceType_APL:        return("APL");
362c65ebfc7SToomas Soome         case kDNSServiceType_DS:         return("DS");
363c65ebfc7SToomas Soome         case kDNSServiceType_SSHFP:      return("SSHFP");
364c65ebfc7SToomas Soome         case kDNSServiceType_IPSECKEY:   return("IPSECKEY");
365c65ebfc7SToomas Soome         case kDNSServiceType_RRSIG:      return("RRSIG");
366c65ebfc7SToomas Soome         case kDNSServiceType_NSEC:       return("NSEC");
367c65ebfc7SToomas Soome         case kDNSServiceType_DNSKEY:     return("DNSKEY");
368c65ebfc7SToomas Soome         case kDNSServiceType_DHCID:      return("DHCID");
369c65ebfc7SToomas Soome         case kDNSServiceType_NSEC3:      return("NSEC3");
370c65ebfc7SToomas Soome         case kDNSServiceType_NSEC3PARAM: return("NSEC3PARAM");
371c65ebfc7SToomas Soome         case kDNSServiceType_HIP:        return("HIP");
372c65ebfc7SToomas Soome         case kDNSServiceType_SPF:        return("SPF");
373c65ebfc7SToomas Soome         case kDNSServiceType_UINFO:      return("UINFO");
374c65ebfc7SToomas Soome         case kDNSServiceType_UID:        return("UID");
375c65ebfc7SToomas Soome         case kDNSServiceType_GID:        return("GID");
376c65ebfc7SToomas Soome         case kDNSServiceType_UNSPEC:     return("UNSPEC");
377c65ebfc7SToomas Soome         case kDNSServiceType_TKEY:       return("TKEY");
378c65ebfc7SToomas Soome         case kDNSServiceType_TSIG:       return("TSIG");
379c65ebfc7SToomas Soome         case kDNSServiceType_IXFR:       return("IXFR");
380c65ebfc7SToomas Soome         case kDNSServiceType_AXFR:       return("AXFR");
381c65ebfc7SToomas Soome         case kDNSServiceType_MAILB:      return("MAILB");
382c65ebfc7SToomas Soome         case kDNSServiceType_MAILA:      return("MAILA");
383c65ebfc7SToomas Soome         case kDNSServiceType_ANY:        return("ANY");
384c1de7575SRichard Lowe         default:
3855ffb0c9bSToomas Soome         {
3865ffb0c9bSToomas Soome             static char buffer[RR_TYPE_SIZE];
3875ffb0c9bSToomas Soome             snprintf(buffer, sizeof(buffer), "TYPE%d", rr_type);
3885ffb0c9bSToomas Soome             return(buffer);
3895ffb0c9bSToomas Soome         }
3905ffb0c9bSToomas Soome     }
3915ffb0c9bSToomas Soome }
3925ffb0c9bSToomas Soome 
swap16(unsigned short x)3935ffb0c9bSToomas Soome static unsigned short swap16(unsigned short x)
3945ffb0c9bSToomas Soome {
3955ffb0c9bSToomas Soome     unsigned char *ptr = (unsigned char *)&x;
3965ffb0c9bSToomas Soome     return (unsigned short)((unsigned short)ptr[0] << 8 | ptr[1]);
3975ffb0c9bSToomas Soome }
3985ffb0c9bSToomas Soome 
swap32(unsigned int x)399c1de7575SRichard Lowe static unsigned int swap32(unsigned int x)
4005ffb0c9bSToomas Soome {
4015ffb0c9bSToomas Soome     unsigned char *ptr = (unsigned char *)&x;
4025ffb0c9bSToomas Soome     return (unsigned int)((unsigned int)ptr[0] << 24 | (unsigned int)ptr[1] << 16 | (unsigned int)ptr[2] << 8 | ptr[3]);
4035ffb0c9bSToomas Soome }
keytag(unsigned char * key,unsigned int keysize)404c1de7575SRichard Lowe static unsigned int keytag(unsigned char *key, unsigned int keysize)
4055ffb0c9bSToomas Soome {
4065ffb0c9bSToomas Soome     unsigned long ac;
4075ffb0c9bSToomas Soome     unsigned int i;
4085ffb0c9bSToomas Soome 
4095ffb0c9bSToomas Soome     for (ac = 0, i = 0; i < keysize; ++i)
4105ffb0c9bSToomas Soome         ac += (i & 1) ? key[i] : key[i] << 8;
4115ffb0c9bSToomas Soome     ac += (ac >> 16) & 0xFFFF;
4125ffb0c9bSToomas Soome     return ac & 0xFFFF;
4135ffb0c9bSToomas Soome }
4145ffb0c9bSToomas Soome 
415*3b436d06SToomas Soome // Base 64 encoding according to <https://tools.ietf.org/html/rfc4648#section-4>.
416*3b436d06SToomas Soome #define kBase64EncodingTable "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
417*3b436d06SToomas Soome 
base64Encode(char * buffer,size_t buflen,void * rdata,size_t rdlen)418*3b436d06SToomas Soome static void base64Encode(char *buffer, size_t buflen, void *rdata, size_t rdlen)
4195ffb0c9bSToomas Soome {
420*3b436d06SToomas Soome     const uint8_t *src = (const uint8_t *)rdata;
421*3b436d06SToomas Soome     const uint8_t *const end = &src[rdlen];
422*3b436d06SToomas Soome     char *dst = buffer;
423*3b436d06SToomas Soome     const char *lim;
424*3b436d06SToomas Soome 
425*3b436d06SToomas Soome     if (buflen == 0) return;
426*3b436d06SToomas Soome     lim = &buffer[buflen - 1];
427*3b436d06SToomas Soome     while ((src < end) && (dst < lim))
428*3b436d06SToomas Soome     {
429*3b436d06SToomas Soome         uint32_t i;
430*3b436d06SToomas Soome         const size_t rem = (size_t)(end - src);
431*3b436d06SToomas Soome 
432*3b436d06SToomas Soome         // Form a 24-bit input group. If less than 24 bits remain, pad with zero bits.
433*3b436d06SToomas Soome         if (     rem >= 3) i = (src[0] << 16) | (src[1] << 8) | src[2]; // 24 bits are equal to 4 6-bit groups.
434*3b436d06SToomas Soome         else if (rem == 2) i = (src[0] << 16) | (src[1] << 8);          // 16 bits are treated as 3 6-bit groups + 1 pad
435*3b436d06SToomas Soome         else               i =  src[0] << 16;                           //  8 bits are treated as 2 6-bit groups + 2 pads
436*3b436d06SToomas Soome 
437*3b436d06SToomas Soome         // Encode each 6-bit group.
438*3b436d06SToomas Soome                        *dst++ =              kBase64EncodingTable[(i >> 18) & 0x3F];
439*3b436d06SToomas Soome         if (dst < lim) *dst++ =              kBase64EncodingTable[(i >> 12) & 0x3F];
440*3b436d06SToomas Soome         if (dst < lim) *dst++ = (rem >= 2) ? kBase64EncodingTable[(i >>  6) & 0x3F] : '=';
441*3b436d06SToomas Soome         if (dst < lim) *dst++ = (rem >= 3) ? kBase64EncodingTable[ i        & 0x3F] : '=';
442*3b436d06SToomas Soome         src += (rem > 3) ? 3 : rem;
443*3b436d06SToomas Soome     }
444*3b436d06SToomas Soome     *dst = '\0';
4455ffb0c9bSToomas Soome }
4465ffb0c9bSToomas Soome 
GetProtocol(const char * s)4475ffb0c9bSToomas Soome static DNSServiceProtocol GetProtocol(const char *s)
4485ffb0c9bSToomas Soome {
4495ffb0c9bSToomas Soome     if      (!strcasecmp(s, "v4"      )) return(kDNSServiceProtocol_IPv4);
4505ffb0c9bSToomas Soome     else if (!strcasecmp(s, "v6"      )) return(kDNSServiceProtocol_IPv6);
4515ffb0c9bSToomas Soome     else if (!strcasecmp(s, "v4v6"    )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
4525ffb0c9bSToomas Soome     else if (!strcasecmp(s, "v6v4"    )) return(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
4535ffb0c9bSToomas Soome     else if (!strcasecmp(s, "udp"     )) return(kDNSServiceProtocol_UDP);
4545ffb0c9bSToomas Soome     else if (!strcasecmp(s, "tcp"     )) return(kDNSServiceProtocol_TCP);
4555ffb0c9bSToomas Soome     else if (!strcasecmp(s, "udptcp"  )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
4565ffb0c9bSToomas Soome     else if (!strcasecmp(s, "tcpudp"  )) return(kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP);
4575ffb0c9bSToomas Soome     else return(atoi(s));
4585ffb0c9bSToomas Soome }
4595ffb0c9bSToomas Soome 
4605ffb0c9bSToomas Soome 
4615ffb0c9bSToomas Soome //*************************************************************************************************************
4625ffb0c9bSToomas Soome // Sample callback functions for each of the operation types
4635ffb0c9bSToomas Soome 
464c65ebfc7SToomas Soome #define printtimestamp() printtimestamp_F(stdout)
465c65ebfc7SToomas Soome 
printtimestamp_F(FILE * outstream)466c65ebfc7SToomas Soome static void printtimestamp_F(FILE *outstream)
4675ffb0c9bSToomas Soome {
4685ffb0c9bSToomas Soome     struct tm tm;
4695ffb0c9bSToomas Soome     int ms;
4705ffb0c9bSToomas Soome     static char date[16];
4715ffb0c9bSToomas Soome     static char new_date[16];
4725ffb0c9bSToomas Soome #ifdef _WIN32
4735ffb0c9bSToomas Soome     SYSTEMTIME sysTime;
4745ffb0c9bSToomas Soome     time_t uct = time(NULL);
4755ffb0c9bSToomas Soome     tm = *localtime(&uct);
4765ffb0c9bSToomas Soome     GetLocalTime(&sysTime);
4775ffb0c9bSToomas Soome     ms = sysTime.wMilliseconds;
4785ffb0c9bSToomas Soome #else
4795ffb0c9bSToomas Soome     struct timeval tv;
4805ffb0c9bSToomas Soome     gettimeofday(&tv, NULL);
4815ffb0c9bSToomas Soome     localtime_r((time_t*)&tv.tv_sec, &tm);
4825ffb0c9bSToomas Soome     ms = tv.tv_usec/1000;
4835ffb0c9bSToomas Soome #endif
4845ffb0c9bSToomas Soome     strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
4855ffb0c9bSToomas Soome     if (strncmp(date, new_date, sizeof(new_date)))
4865ffb0c9bSToomas Soome     {
487c65ebfc7SToomas Soome         fprintf(outstream, "DATE: ---%s---\n", new_date); //display date only if it has changed
4885ffb0c9bSToomas Soome         strncpy(date, new_date, sizeof(date));
4895ffb0c9bSToomas Soome     }
490c65ebfc7SToomas Soome     fprintf(outstream, "%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
4915ffb0c9bSToomas Soome }
4925ffb0c9bSToomas Soome 
4935ffb0c9bSToomas Soome // formating time to RFC 4034 format
FormatTime(unsigned long te,unsigned char * buf,int bufsize)494c1de7575SRichard Lowe static void FormatTime(unsigned long te, unsigned char *buf, int bufsize)
4955ffb0c9bSToomas Soome {
4965ffb0c9bSToomas Soome     struct tm tmTime;
4975ffb0c9bSToomas Soome #ifdef _WIN32
4985ffb0c9bSToomas Soome 	__time32_t t = (__time32_t) te;
4995ffb0c9bSToomas Soome 	_gmtime32_s(&tmTime, &t);
5005ffb0c9bSToomas Soome #else
5015ffb0c9bSToomas Soome     // Time since epoch : strftime takes "tm". Convert seconds to "tm" using
5025ffb0c9bSToomas Soome     // gmtime_r first and then use strftime
5035ffb0c9bSToomas Soome 	time_t t = (time_t)te;
5045ffb0c9bSToomas Soome 	gmtime_r(&t, &tmTime);
5055ffb0c9bSToomas Soome #endif
5065ffb0c9bSToomas Soome     strftime((char *)buf, bufsize, "%Y%m%d%H%M%S", &tmTime);
5075ffb0c9bSToomas Soome }
5085ffb0c9bSToomas Soome 
print_usage(const char * arg0,int print_all)5095ffb0c9bSToomas Soome static void print_usage(const char *arg0, int print_all)
5105ffb0c9bSToomas Soome {
511c65ebfc7SToomas Soome     // Print the commonly used command line options.  These are listed in "the order they have been in historically".
5125ffb0c9bSToomas Soome     fprintf(stderr, "%s -E                              (Enumerate recommended registration domains)\n", arg0);
5135ffb0c9bSToomas Soome     fprintf(stderr, "%s -F                                  (Enumerate recommended browsing domains)\n", arg0);
5145ffb0c9bSToomas Soome     fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...]             (Register a service)\n", arg0);
515c65ebfc7SToomas Soome     fprintf(stderr, "%s -B        <Type> <Domain>                     (Browse for service instances)\n", arg0);
516c65ebfc7SToomas Soome     fprintf(stderr, "%s -L <Name> <Type> <Domain>                       (Resolve a service instance)\n", arg0);
517c65ebfc7SToomas Soome     fprintf(stderr, "%s -Q <name> <rrtype> <rrclass>             (Generic query for any record type)\n", arg0);
5185ffb0c9bSToomas Soome     fprintf(stderr, "%s -Z        <Type> <Domain>               (Output results in Zone File format)\n", arg0);
5195ffb0c9bSToomas Soome     fprintf(stderr, "%s -G     v4/v6/v4v6 <name>              (Get address information for hostname)\n", arg0);
520c65ebfc7SToomas Soome     fprintf(stderr, "%s -H                                   (Print usage for complete command list)\n", arg0);
5215ffb0c9bSToomas Soome     fprintf(stderr, "%s -V                (Get version of currently running daemon / system service)\n", arg0);
5225ffb0c9bSToomas Soome 
523c65ebfc7SToomas Soome     if (print_all)  // Print all available options for dns-sd tool.  Keep these in alphabetical order for easier maintenance.
5245ffb0c9bSToomas Soome     {
525c65ebfc7SToomas Soome         fprintf(stderr, "\n");
5265ffb0c9bSToomas Soome         fprintf(stderr, "%s -A                                  (Test Adding/Updating/Deleting a record)\n", arg0);
527c65ebfc7SToomas Soome         fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass>               (Query; reconfirming each result)\n", arg0);
528c65ebfc7SToomas Soome         fprintf(stderr, "%s -D <name> <rrtype> <rrclass>(Validate query for any record type with DNSSEC)\n", arg0);
529c65ebfc7SToomas Soome         fprintf(stderr, "%s -I               (Test registering and then immediately updating TXT record)\n", arg0);
5305ffb0c9bSToomas Soome         fprintf(stderr, "%s -N                                         (Test adding a large NULL record)\n", arg0);
5315ffb0c9bSToomas Soome         fprintf(stderr, "%s -M                  (Test creating a registration with multiple TXT records)\n", arg0);
532c65ebfc7SToomas Soome         fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]              (Proxy)\n", arg0);
5335ffb0c9bSToomas Soome         fprintf(stderr, "%s -S                             (Test multiple operations on a shared socket)\n", arg0);
534c65ebfc7SToomas Soome         fprintf(stderr, "%s -T                                        (Test creating a large TXT record)\n", arg0);
535c65ebfc7SToomas Soome         fprintf(stderr, "%s -U                                              (Test updating a TXT record)\n", arg0);
536c65ebfc7SToomas Soome         fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL>               (NAT Port Mapping)\n", arg0);
537c65ebfc7SToomas Soome         fprintf(stderr, "%s -ble                                      (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
538c65ebfc7SToomas Soome         fprintf(stderr, "%s -g v4/v6/v4v6 <name>        (Validate address info for hostname with DNSSEC)\n", arg0);
5395ffb0c9bSToomas Soome         fprintf(stderr, "%s -i <Interface>             (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
5405ffb0c9bSToomas Soome         fprintf(stderr, "%s -includep2p                            (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
5415ffb0c9bSToomas Soome         fprintf(stderr, "%s -includeAWDL                          (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
542c65ebfc7SToomas Soome         fprintf(stderr, "%s -intermediates                (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
543c65ebfc7SToomas Soome         fprintf(stderr, "%s -ku                                   (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
544c65ebfc7SToomas Soome         fprintf(stderr, "%s -lo                              (Run dns-sd cmd using local only interface)\n", arg0);
5455ffb0c9bSToomas Soome         fprintf(stderr, "%s -optional                        (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
546c65ebfc7SToomas Soome         fprintf(stderr, "%s -p2p                                      (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
547c65ebfc7SToomas Soome         fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Equivalent to -Q with kDNSServiceFlagsSuppressUnusable set)\n", arg0);
5485ffb0c9bSToomas Soome         fprintf(stderr, "%s -tc                        (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
549c65ebfc7SToomas Soome         fprintf(stderr, "%s -test                                      (Run basic API input range tests)\n", arg0);
5505ffb0c9bSToomas Soome         fprintf(stderr, "%s -t1                                  (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
5515ffb0c9bSToomas Soome         fprintf(stderr, "%s -tFinder                          (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
5525ffb0c9bSToomas Soome         fprintf(stderr, "%s -timeout                                  (Set kDNSServiceFlagsTimeout flag)\n", arg0);
553c65ebfc7SToomas Soome         fprintf(stderr, "%s -unicastResponse                  (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
554c65ebfc7SToomas Soome         fprintf(stderr, "%s -autoTrigger                          (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
5555ffb0c9bSToomas Soome     }
5565ffb0c9bSToomas Soome }
5575ffb0c9bSToomas Soome 
5585ffb0c9bSToomas Soome #define DomainMsg(X) (((X) &kDNSServiceFlagsDefault) ? "(Default)" : \
5595ffb0c9bSToomas Soome                       ((X) &kDNSServiceFlagsAdd)     ? "Added"     : "Removed")
5605ffb0c9bSToomas Soome 
5615ffb0c9bSToomas Soome #define MAX_LABELS 128
5625ffb0c9bSToomas Soome 
enum_reply(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * replyDomain,void * context)5635ffb0c9bSToomas Soome static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex,
5645ffb0c9bSToomas Soome                                  DNSServiceErrorType errorCode, const char *replyDomain, void *context)
5655ffb0c9bSToomas Soome {
5665ffb0c9bSToomas Soome     DNSServiceFlags partialflags = flags & ~(kDNSServiceFlagsMoreComing | kDNSServiceFlagsAdd | kDNSServiceFlagsDefault);
5675ffb0c9bSToomas Soome     int labels = 0, depth = 0, i, initial = 0;
5685ffb0c9bSToomas Soome     char text[64];
5695ffb0c9bSToomas Soome     const char *label[MAX_LABELS];
5705ffb0c9bSToomas Soome 
5715ffb0c9bSToomas Soome     (void)sdref;        // Unused
5725ffb0c9bSToomas Soome     (void)ifIndex;      // Unused
5735ffb0c9bSToomas Soome     (void)context;      // Unused
5745ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
5755ffb0c9bSToomas Soome 
5765ffb0c9bSToomas Soome     // 1. Print the header
5775ffb0c9bSToomas Soome     if (num_printed++ == 0) printf("Timestamp     Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
5785ffb0c9bSToomas Soome     printtimestamp();
5795ffb0c9bSToomas Soome     if (errorCode)
5805ffb0c9bSToomas Soome         printf("Error code %d\n", errorCode);
5815ffb0c9bSToomas Soome     else if (!*replyDomain)
5825ffb0c9bSToomas Soome         printf("Error: No reply domain\n");
5835ffb0c9bSToomas Soome     else
5845ffb0c9bSToomas Soome     {
5855ffb0c9bSToomas Soome         printf("%-10s", DomainMsg(flags));
5865ffb0c9bSToomas Soome         printf("%-8s", (flags & kDNSServiceFlagsMoreComing) ? "(More)" : "");
5875ffb0c9bSToomas Soome         if (partialflags) printf("Flags: %4X  ", partialflags);
5885ffb0c9bSToomas Soome         else printf("             ");
5895ffb0c9bSToomas Soome 
5905ffb0c9bSToomas Soome         // 2. Count the labels
5915ffb0c9bSToomas Soome         while (replyDomain && *replyDomain && labels < MAX_LABELS)
5925ffb0c9bSToomas Soome         {
5935ffb0c9bSToomas Soome             label[labels++] = replyDomain;
5945ffb0c9bSToomas Soome             replyDomain = GetNextLabel(replyDomain, text);
5955ffb0c9bSToomas Soome         }
5965ffb0c9bSToomas Soome 
5975ffb0c9bSToomas Soome         // 3. Decide if we're going to clump the last two or three labels (e.g. "apple.com", or "nicta.com.au")
5985ffb0c9bSToomas Soome         if      (labels >= 3 && replyDomain - label[labels-1] <= 3 && label[labels-1] - label[labels-2] <= 4) initial = 3;
5995ffb0c9bSToomas Soome         else if (labels >= 2 && replyDomain - label[labels-1] <= 4) initial = 2;
6005ffb0c9bSToomas Soome         else initial = 1;
6015ffb0c9bSToomas Soome         labels -= initial;
6025ffb0c9bSToomas Soome 
6035ffb0c9bSToomas Soome         // 4. Print the initial one-, two- or three-label clump
6045ffb0c9bSToomas Soome         for (i=0; i<initial; i++)
6055ffb0c9bSToomas Soome         {
6065ffb0c9bSToomas Soome             GetNextLabel(label[labels+i], text);
6075ffb0c9bSToomas Soome             if (i>0) printf(".");
6085ffb0c9bSToomas Soome             printf("%s", text);
6095ffb0c9bSToomas Soome         }
6105ffb0c9bSToomas Soome         printf("\n");
6115ffb0c9bSToomas Soome 
6125ffb0c9bSToomas Soome         // 5. Print the remainder of the hierarchy
6135ffb0c9bSToomas Soome         for (depth=0; depth<labels; depth++)
6145ffb0c9bSToomas Soome         {
6155ffb0c9bSToomas Soome             printf("                                             ");
6165ffb0c9bSToomas Soome             for (i=0; i<=depth; i++) printf("- ");
6175ffb0c9bSToomas Soome             GetNextLabel(label[labels-1-depth], text);
6185ffb0c9bSToomas Soome             printf("> %s\n", text);
6195ffb0c9bSToomas Soome         }
6205ffb0c9bSToomas Soome     }
6215ffb0c9bSToomas Soome 
6225ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
6235ffb0c9bSToomas Soome }
6245ffb0c9bSToomas Soome 
CopyLabels(char * dst,const char * lim,const char ** srcp,int labels)6255ffb0c9bSToomas Soome static int CopyLabels(char *dst, const char *lim, const char **srcp, int labels)
6265ffb0c9bSToomas Soome {
6275ffb0c9bSToomas Soome     const char *src = *srcp;
6285ffb0c9bSToomas Soome     while (*src != '.' || --labels > 0)
6295ffb0c9bSToomas Soome     {
6305ffb0c9bSToomas Soome         if (*src == '\\') *dst++ = *src++;  // Make sure "\." doesn't confuse us
6315ffb0c9bSToomas Soome         if (!*src || dst >= lim) return -1;
6325ffb0c9bSToomas Soome         *dst++ = *src++;
6335ffb0c9bSToomas Soome         if (!*src || dst >= lim) return -1;
6345ffb0c9bSToomas Soome     }
6355ffb0c9bSToomas Soome     *dst++ = 0;
6365ffb0c9bSToomas Soome     *srcp = src + 1;    // skip over final dot
6375ffb0c9bSToomas Soome     return 0;
6385ffb0c9bSToomas Soome }
6395ffb0c9bSToomas Soome 
zonedata_resolve(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * fullname,const char * hosttarget,uint16_t opaqueport,uint16_t txtLen,const unsigned char * txt,void * context)6405ffb0c9bSToomas Soome static void DNSSD_API zonedata_resolve(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
6415ffb0c9bSToomas Soome                                        const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txt, void *context)
6425ffb0c9bSToomas Soome {
6435ffb0c9bSToomas Soome     union { uint16_t s; u_char b[2]; } port = { opaqueport };
6445ffb0c9bSToomas Soome     uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
6455ffb0c9bSToomas Soome 
6465ffb0c9bSToomas Soome     const char *p = fullname;
6475ffb0c9bSToomas Soome     char n[kDNSServiceMaxDomainName];
6485ffb0c9bSToomas Soome     char t[kDNSServiceMaxDomainName];
6495ffb0c9bSToomas Soome 
6505ffb0c9bSToomas Soome     const unsigned char *max = txt + txtLen;
6515ffb0c9bSToomas Soome 
6525ffb0c9bSToomas Soome     (void)sdref;        // Unused
6535ffb0c9bSToomas Soome     (void)ifIndex;      // Unused
6545ffb0c9bSToomas Soome     (void)context;      // Unused
6555ffb0c9bSToomas Soome 
6565ffb0c9bSToomas Soome     //if (!(flags & kDNSServiceFlagsAdd)) return;
6575ffb0c9bSToomas Soome     if (errorCode) { printf("Error code %d\n", errorCode); return; }
6585ffb0c9bSToomas Soome 
6595ffb0c9bSToomas Soome     if (CopyLabels(n, n + kDNSServiceMaxDomainName, &p, 3)) return;     // Fetch name+type
6605ffb0c9bSToomas Soome     p = fullname;
6615ffb0c9bSToomas Soome     if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 1)) return;     // Skip first label
6625ffb0c9bSToomas Soome     if (CopyLabels(t, t + kDNSServiceMaxDomainName, &p, 2)) return;     // Fetch next two labels (service type)
6635ffb0c9bSToomas Soome 
6645ffb0c9bSToomas Soome     if (num_printed++ == 0)
6655ffb0c9bSToomas Soome     {
6665ffb0c9bSToomas Soome         printf("\n");
6675ffb0c9bSToomas Soome         printf("; To direct clients to browse a different domain, substitute that domain in place of '@'\n");
6685ffb0c9bSToomas Soome         printf("%-47s PTR     %s\n", "lb._dns-sd._udp", "@");
6695ffb0c9bSToomas Soome         printf("\n");
6705ffb0c9bSToomas Soome         printf("; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.\n");
6715ffb0c9bSToomas Soome         printf("; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local\n");
6725ffb0c9bSToomas Soome         printf("; names with the correct fully-qualified (unicast) domain name of the target host offering the service.\n");
6735ffb0c9bSToomas Soome     }
6745ffb0c9bSToomas Soome 
6755ffb0c9bSToomas Soome     printf("\n");
6765ffb0c9bSToomas Soome     printf("%-47s PTR     %s\n", t, n);
6775ffb0c9bSToomas Soome     printf("%-47s SRV     0 0 %d %s ; Replace with unicast FQDN of target host\n", n, PortAsNumber, hosttarget);
6785ffb0c9bSToomas Soome     printf("%-47s TXT    ", n);
6795ffb0c9bSToomas Soome 
6805ffb0c9bSToomas Soome     while (txt < max)
6815ffb0c9bSToomas Soome     {
6825ffb0c9bSToomas Soome         const unsigned char *const end = txt + 1 + txt[0];
6835ffb0c9bSToomas Soome         txt++;      // Skip over length byte
6845ffb0c9bSToomas Soome         printf(" \"");
6855ffb0c9bSToomas Soome         while (txt<end)
6865ffb0c9bSToomas Soome         {
6875ffb0c9bSToomas Soome             if (*txt == '\\' || *txt == '\"') printf("\\");
6885ffb0c9bSToomas Soome             printf("%c", *txt++);
6895ffb0c9bSToomas Soome         }
6905ffb0c9bSToomas Soome         printf("\"");
6915ffb0c9bSToomas Soome     }
6925ffb0c9bSToomas Soome     printf("\n");
6935ffb0c9bSToomas Soome 
6945ffb0c9bSToomas Soome     DNSServiceRefDeallocate(sdref);
6955ffb0c9bSToomas Soome     free(context);
6965ffb0c9bSToomas Soome 
6975ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
6985ffb0c9bSToomas Soome }
6995ffb0c9bSToomas Soome 
zonedata_browse(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * replyName,const char * replyType,const char * replyDomain,void * context)7005ffb0c9bSToomas Soome static void DNSSD_API zonedata_browse(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
7015ffb0c9bSToomas Soome                                       const char *replyName, const char *replyType, const char *replyDomain, void *context)
7025ffb0c9bSToomas Soome {
7035ffb0c9bSToomas Soome     DNSServiceRef *newref;
7045ffb0c9bSToomas Soome 
7055ffb0c9bSToomas Soome     (void)sdref;        // Unused
7065ffb0c9bSToomas Soome     (void)context;      // Unused
7075ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
7085ffb0c9bSToomas Soome 
7095ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsAdd)) return;
7105ffb0c9bSToomas Soome     if (errorCode) { printf("Error code %d\n", errorCode); return; }
7115ffb0c9bSToomas Soome 
7125ffb0c9bSToomas Soome     newref = malloc(sizeof(*newref));
7135ffb0c9bSToomas Soome     *newref = client;
7145ffb0c9bSToomas Soome     DNSServiceResolve(newref, kDNSServiceFlagsShareConnection, ifIndex, replyName, replyType, replyDomain, zonedata_resolve, newref);
7155ffb0c9bSToomas Soome }
7165ffb0c9bSToomas Soome 
browse_reply(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * replyName,const char * replyType,const char * replyDomain,void * context)7175ffb0c9bSToomas Soome static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
7185ffb0c9bSToomas Soome                                    const char *replyName, const char *replyType, const char *replyDomain, void *context)
7195ffb0c9bSToomas Soome {
7205ffb0c9bSToomas Soome     char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
7215ffb0c9bSToomas Soome     (void)sdref;        // Unused
7225ffb0c9bSToomas Soome     (void)context;      // Unused
7235ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
7245ffb0c9bSToomas Soome 
7255ffb0c9bSToomas Soome     if (num_printed++ == 0) printf("Timestamp     A/R    Flags  if %-20s %-20s %s\n", "Domain", "Service Type", "Instance Name");
7265ffb0c9bSToomas Soome     printtimestamp();
727c1de7575SRichard Lowe     if (errorCode)
7285ffb0c9bSToomas Soome         printf("Error code %d\n", errorCode);
729c1de7575SRichard Lowe     else
730c1de7575SRichard Lowe         printf("%s %8X %3d %-20s %-20s %s\n",
7315ffb0c9bSToomas Soome                 op, flags, ifIndex, replyDomain, replyType, replyName);
7325ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
7335ffb0c9bSToomas Soome 
7345ffb0c9bSToomas Soome     // To test selective cancellation of operations of shared sockets,
7355ffb0c9bSToomas Soome     // cancel the current operation when we've got a multiple of five results
7365ffb0c9bSToomas Soome     //if (operation == 'S' && num_printed % 5 == 0) DNSServiceRefDeallocate(sdref);
7375ffb0c9bSToomas Soome }
7385ffb0c9bSToomas Soome 
ShowTXTRecord(uint16_t txtLen,const unsigned char * txtRecord)7395ffb0c9bSToomas Soome static void ShowTXTRecord(uint16_t txtLen, const unsigned char *txtRecord)
7405ffb0c9bSToomas Soome {
7415ffb0c9bSToomas Soome     const unsigned char *ptr = txtRecord;
7425ffb0c9bSToomas Soome     const unsigned char *max = txtRecord + txtLen;
7435ffb0c9bSToomas Soome     while (ptr < max)
7445ffb0c9bSToomas Soome     {
7455ffb0c9bSToomas Soome         const unsigned char *const end = ptr + 1 + ptr[0];
7465ffb0c9bSToomas Soome         if (end > max) { printf("<< invalid data >>"); break; }
7475ffb0c9bSToomas Soome         if (++ptr < end) printf(" ");   // As long as string is non-empty, begin with a space
7485ffb0c9bSToomas Soome         while (ptr<end)
7495ffb0c9bSToomas Soome         {
7505ffb0c9bSToomas Soome             // We'd like the output to be shell-friendly, so that it can be copied and pasted unchanged into a "dns-sd -R" command.
7515ffb0c9bSToomas Soome             // However, this is trickier than it seems. Enclosing a string in double quotes doesn't necessarily make it
7525ffb0c9bSToomas Soome             // shell-safe, because shells still expand variables like $foo even when they appear inside quoted strings.
7535ffb0c9bSToomas Soome             // Enclosing a string in single quotes is better, but when using single quotes even backslash escapes are ignored,
7545ffb0c9bSToomas Soome             // meaning there's simply no way to represent a single quote (or apostrophe) inside a single-quoted string.
7555ffb0c9bSToomas Soome             // The only remaining solution is not to surround the string with quotes at all, but instead to use backslash
7565ffb0c9bSToomas Soome             // escapes to encode spaces and all other known shell metacharacters.
7575ffb0c9bSToomas Soome             // (If we've missed any known shell metacharacters, please let us know.)
7585ffb0c9bSToomas Soome             // In addition, non-printing ascii codes (0-31) are displayed as \xHH, using a two-digit hex value.
7595ffb0c9bSToomas Soome             // Because '\' is itself a shell metacharacter (the shell escape character), it has to be escaped as "\\" to survive
7605ffb0c9bSToomas Soome             // the round-trip to the shell and back. This means that a single '\' is represented here as EIGHT backslashes:
7615ffb0c9bSToomas Soome             // The C compiler eats half of them, resulting in four appearing in the output.
7625ffb0c9bSToomas Soome             // The shell parses those four as a pair of "\\" sequences, passing two backslashes to the "dns-sd -R" command.
7635ffb0c9bSToomas Soome             // The "dns-sd -R" command interprets this single "\\" pair as an escaped literal backslash. Sigh.
7645ffb0c9bSToomas Soome             if (strchr(" &;`'\"|*?~<>^()[]{}$", *ptr)) printf("\\");
7655ffb0c9bSToomas Soome             if      (*ptr == '\\') printf("\\\\\\\\");
7665ffb0c9bSToomas Soome             else if (*ptr >= ' ' ) printf("%c",        *ptr);
7675ffb0c9bSToomas Soome             else printf("\\\\x%02X", *ptr);
7685ffb0c9bSToomas Soome             ptr++;
7695ffb0c9bSToomas Soome         }
7705ffb0c9bSToomas Soome     }
7715ffb0c9bSToomas Soome }
7725ffb0c9bSToomas Soome 
resolve_reply(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * fullname,const char * hosttarget,uint16_t opaqueport,uint16_t txtLen,const unsigned char * txtRecord,void * context)7735ffb0c9bSToomas Soome static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
7745ffb0c9bSToomas Soome                                     const char *fullname, const char *hosttarget, uint16_t opaqueport, uint16_t txtLen, const unsigned char *txtRecord, void *context)
7755ffb0c9bSToomas Soome {
7765ffb0c9bSToomas Soome     union { uint16_t s; u_char b[2]; } port = { opaqueport };
7775ffb0c9bSToomas Soome     uint16_t PortAsNumber = ((uint16_t)port.b[0]) << 8 | port.b[1];
7785ffb0c9bSToomas Soome 
7795ffb0c9bSToomas Soome     (void)sdref;        // Unused
7805ffb0c9bSToomas Soome     (void)ifIndex;      // Unused
7815ffb0c9bSToomas Soome     (void)context;      // Unused
7825ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
7835ffb0c9bSToomas Soome 
784c65ebfc7SToomas Soome     printtimestamp();
785c65ebfc7SToomas Soome 
786c65ebfc7SToomas Soome     printf("%s ", fullname);
787c65ebfc7SToomas Soome 
788c65ebfc7SToomas Soome     if (errorCode == kDNSServiceErr_NoSuchRecord) printf("No Such Record");
789c65ebfc7SToomas Soome     else if (errorCode) printf("error code %d\n", errorCode);
790c65ebfc7SToomas Soome     else printf("can be reached at %s:%u (interface %d)", hosttarget, PortAsNumber, ifIndex);
791c65ebfc7SToomas Soome 
792c65ebfc7SToomas Soome     if (flags) printf(" Flags: %X", flags);
793c65ebfc7SToomas Soome 
794c65ebfc7SToomas Soome     // Don't show degenerate TXT records containing nothing but a single empty string
795c65ebfc7SToomas Soome     if (!errorCode && txtLen > 1) { printf("\n"); ShowTXTRecord(txtLen, txtRecord); }
796c65ebfc7SToomas Soome 
797c65ebfc7SToomas Soome     printf("\n");
7985ffb0c9bSToomas Soome 
7995ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
8005ffb0c9bSToomas Soome }
8015ffb0c9bSToomas Soome 
myTimerCallBack(void)8025ffb0c9bSToomas Soome static void myTimerCallBack(void)
8035ffb0c9bSToomas Soome {
8045ffb0c9bSToomas Soome     DNSServiceErrorType err = kDNSServiceErr_Unknown;
8055ffb0c9bSToomas Soome 
8065ffb0c9bSToomas Soome     switch (operation)
8075ffb0c9bSToomas Soome     {
8085ffb0c9bSToomas Soome     case 'A':
8095ffb0c9bSToomas Soome     {
8105ffb0c9bSToomas Soome         switch (addtest)
8115ffb0c9bSToomas Soome         {
8125ffb0c9bSToomas Soome         case 0: printf("Adding Test HINFO record\n");
8135ffb0c9bSToomas Soome             err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_HINFO, sizeof(myhinfoW), &myhinfoW[0], 0);
8145ffb0c9bSToomas Soome             addtest = 1;
8155ffb0c9bSToomas Soome             break;
8165ffb0c9bSToomas Soome         case 1: printf("Updating Test HINFO record\n");
8175ffb0c9bSToomas Soome             err = DNSServiceUpdateRecord(client, record, 0, sizeof(myhinfoX), &myhinfoX[0], 0);
8185ffb0c9bSToomas Soome             addtest = 2;
8195ffb0c9bSToomas Soome             break;
8205ffb0c9bSToomas Soome         case 2: printf("Removing Test HINFO record\n");
8215ffb0c9bSToomas Soome             err = DNSServiceRemoveRecord(client, record, 0);
8225ffb0c9bSToomas Soome             addtest = 0;
8235ffb0c9bSToomas Soome             break;
8245ffb0c9bSToomas Soome         }
8255ffb0c9bSToomas Soome     }
8265ffb0c9bSToomas Soome     break;
8275ffb0c9bSToomas Soome 
8285ffb0c9bSToomas Soome     case 'U':
8295ffb0c9bSToomas Soome     {
8305ffb0c9bSToomas Soome         if (updatetest[1] != 'Z') updatetest[1]++;
8315ffb0c9bSToomas Soome         else updatetest[1] = 'A';
832c65ebfc7SToomas Soome         // The following line toggles the string length between 1 and 2 characters.
8335ffb0c9bSToomas Soome         updatetest[0] = 3 - updatetest[0];
8345ffb0c9bSToomas Soome         updatetest[2] = updatetest[1];
8355ffb0c9bSToomas Soome         printtimestamp();
8365ffb0c9bSToomas Soome         printf("Updating Test TXT record to %c\n", updatetest[1]);
8375ffb0c9bSToomas Soome         err = DNSServiceUpdateRecord(client, NULL, 0, 1+updatetest[0], &updatetest[0], 0);
8385ffb0c9bSToomas Soome     }
8395ffb0c9bSToomas Soome     break;
8405ffb0c9bSToomas Soome 
8415ffb0c9bSToomas Soome     case 'N':
8425ffb0c9bSToomas Soome     {
8435ffb0c9bSToomas Soome         printf("Adding big NULL record\n");
8445ffb0c9bSToomas Soome         err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
8455ffb0c9bSToomas Soome         if (err) printf("Failed: %d\n", err);else printf("Succeeded\n");
8465ffb0c9bSToomas Soome         timeOut = LONG_TIME;
8475ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
8485ffb0c9bSToomas Soome         if (timer_source)
8495ffb0c9bSToomas Soome             dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
8505ffb0c9bSToomas Soome                                       (uint64_t)timeOut * NSEC_PER_SEC, 0);
8515ffb0c9bSToomas Soome #endif
8525ffb0c9bSToomas Soome     }
8535ffb0c9bSToomas Soome     break;
8545ffb0c9bSToomas Soome     }
8555ffb0c9bSToomas Soome 
8565ffb0c9bSToomas Soome     if (err != kDNSServiceErr_NoError)
8575ffb0c9bSToomas Soome     {
8585ffb0c9bSToomas Soome         fprintf(stderr, "DNSService add/update/remove failed %ld\n", (long int)err);
8595ffb0c9bSToomas Soome         stopNow = 1;
8605ffb0c9bSToomas Soome     }
8615ffb0c9bSToomas Soome }
8625ffb0c9bSToomas Soome 
reg_reply(DNSServiceRef sdref,const DNSServiceFlags flags,DNSServiceErrorType errorCode,const char * name,const char * regtype,const char * domain,void * context)8635ffb0c9bSToomas Soome static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags, DNSServiceErrorType errorCode,
8645ffb0c9bSToomas Soome                                 const char *name, const char *regtype, const char *domain, void *context)
8655ffb0c9bSToomas Soome {
8665ffb0c9bSToomas Soome     (void)sdref;    // Unused
8675ffb0c9bSToomas Soome     (void)flags;    // Unused
8685ffb0c9bSToomas Soome     (void)context;  // Unused
8695ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
8705ffb0c9bSToomas Soome 
8715ffb0c9bSToomas Soome     printtimestamp();
8725ffb0c9bSToomas Soome     printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
8735ffb0c9bSToomas Soome 
8745ffb0c9bSToomas Soome     if (errorCode == kDNSServiceErr_NoError)
8755ffb0c9bSToomas Soome     {
8765ffb0c9bSToomas Soome         if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n");
8775ffb0c9bSToomas Soome         else printf("Name registration removed\n");
8785ffb0c9bSToomas Soome         if (operation == 'A' || operation == 'U' || operation == 'N')
8795ffb0c9bSToomas Soome         {
8805ffb0c9bSToomas Soome             timeOut = 5;
8815ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
8825ffb0c9bSToomas Soome             if (timer_source)
8835ffb0c9bSToomas Soome                 dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
8845ffb0c9bSToomas Soome                                           (uint64_t)timeOut * NSEC_PER_SEC, 0);
8855ffb0c9bSToomas Soome #endif
8865ffb0c9bSToomas Soome         }
8875ffb0c9bSToomas Soome     }
8885ffb0c9bSToomas Soome     else if (errorCode == kDNSServiceErr_NameConflict)
8895ffb0c9bSToomas Soome     {
8905ffb0c9bSToomas Soome         printf("Name in use, please choose another\n");
8915ffb0c9bSToomas Soome         exit(-1);
8925ffb0c9bSToomas Soome     }
8935ffb0c9bSToomas Soome     else
8945ffb0c9bSToomas Soome         printf("Error %d\n", errorCode);
8955ffb0c9bSToomas Soome 
8965ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
8975ffb0c9bSToomas Soome }
8985ffb0c9bSToomas Soome 
8995ffb0c9bSToomas Soome // Output the wire-format domainname pointed to by rd
snprintd(char * p,int max,const unsigned char ** rd)9005ffb0c9bSToomas Soome static int snprintd(char *p, int max, const unsigned char **rd)
9015ffb0c9bSToomas Soome {
9025ffb0c9bSToomas Soome     const char *const buf = p;
9035ffb0c9bSToomas Soome     const char *const end = p + max;
904c1de7575SRichard Lowe     while (**rd)
905c1de7575SRichard Lowe     {
906c1de7575SRichard Lowe         p += snprintf(p, end-p, "%.*s.", **rd, *rd+1);
907c1de7575SRichard Lowe         *rd += 1 + **rd;
9085ffb0c9bSToomas Soome     }
9095ffb0c9bSToomas Soome     *rd += 1;   // Advance over the final zero byte
9105ffb0c9bSToomas Soome     return(p-buf);
9115ffb0c9bSToomas Soome }
9125ffb0c9bSToomas Soome 
ParseDNSSECRecords(uint16_t rrtype,char * rdb,size_t rdb_size,unsigned const char * rd,uint16_t rdlen)913*3b436d06SToomas Soome static void ParseDNSSECRecords(uint16_t rrtype, char *rdb, size_t rdb_size, unsigned const char *rd, uint16_t rdlen)
9145ffb0c9bSToomas Soome {
915*3b436d06SToomas Soome     char *p = rdb;
916*3b436d06SToomas Soome     switch (rrtype)
9175ffb0c9bSToomas Soome     {
9185ffb0c9bSToomas Soome         case kDNSServiceType_DS:
9195ffb0c9bSToomas Soome         {
9205ffb0c9bSToomas Soome             unsigned char *ptr;
9215ffb0c9bSToomas Soome             int i;
9225ffb0c9bSToomas Soome             rdataDS *rrds = (rdataDS *)rd;
9235ffb0c9bSToomas Soome             p += snprintf(p, rdb + rdb_size - p, "%d  %d  %d  ",
9245ffb0c9bSToomas Soome                           rrds->alg, swap16(rrds->keyTag), rrds->digestType);
9255ffb0c9bSToomas Soome             ptr = (unsigned char *)(rd + DS_FIXED_SIZE);
9265ffb0c9bSToomas Soome             for (i = 0; i < (rdlen - DS_FIXED_SIZE); i++)
927c1de7575SRichard Lowe                 p += snprintf(p, rdb + rdb_size - p, "%x", ptr[i]);
928c1de7575SRichard Lowe             break;
929c1de7575SRichard Lowe         }
930c1de7575SRichard Lowe 
9315ffb0c9bSToomas Soome         case kDNSServiceType_DNSKEY:
9325ffb0c9bSToomas Soome         {
9335ffb0c9bSToomas Soome             rdataDNSKey *rrkey = (rdataDNSKey *)rd;
934*3b436d06SToomas Soome             p += snprintf(p, rdb + rdb_size - p, "%d  %d  %d  %u ", swap16(rrkey->flags), rrkey->proto,
9355ffb0c9bSToomas Soome                           rrkey->alg, (unsigned int)keytag((unsigned char *)rrkey, rdlen));
9365ffb0c9bSToomas Soome             base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + DNSKEY_FIXED_SIZE), rdlen - DNSKEY_FIXED_SIZE);
9375ffb0c9bSToomas Soome             break;
9385ffb0c9bSToomas Soome         }
939c1de7575SRichard Lowe 
940c1de7575SRichard Lowe         case kDNSServiceType_NSEC:
9415ffb0c9bSToomas Soome         {
9425ffb0c9bSToomas Soome             unsigned char *next = (unsigned char *)rd;
9435ffb0c9bSToomas Soome             int len, bitmaplen;
9445ffb0c9bSToomas Soome             int win, wlen, type;
9455ffb0c9bSToomas Soome             unsigned char *bmap;
9465ffb0c9bSToomas Soome             char *l = NULL;
947c1de7575SRichard Lowe 
9485ffb0c9bSToomas Soome             l = p;
9495ffb0c9bSToomas Soome             p += snprintd(p, rdb + rdb_size - p, &rd);
9505ffb0c9bSToomas Soome             len = p - l + 1;
951c1de7575SRichard Lowe 
9525ffb0c9bSToomas Soome             bitmaplen = rdlen - len;
9535ffb0c9bSToomas Soome             bmap = (unsigned char *)((unsigned char *)next + len);
954c1de7575SRichard Lowe 
9555ffb0c9bSToomas Soome             while (bitmaplen > 0)
9565ffb0c9bSToomas Soome             {
9575ffb0c9bSToomas Soome                 int i;
958c1de7575SRichard Lowe 
9595ffb0c9bSToomas Soome                 if (bitmaplen < 3)
9605ffb0c9bSToomas Soome                 {
9615ffb0c9bSToomas Soome                     printf("Case NSEC: malformed nsec, bitmaplen %d short\n", bitmaplen);
9625ffb0c9bSToomas Soome                     break;
963c1de7575SRichard Lowe                 }
964c1de7575SRichard Lowe 
9655ffb0c9bSToomas Soome                 win = *bmap++;
9665ffb0c9bSToomas Soome                 wlen = *bmap++;
9675ffb0c9bSToomas Soome                 bitmaplen -= 2;
9685ffb0c9bSToomas Soome                 if (bitmaplen < wlen || wlen < 1 || wlen > 32)
9695ffb0c9bSToomas Soome                 {
9705ffb0c9bSToomas Soome                     printf("Case NSEC: malformed nsec, bitmaplen %d wlen %d\n", bitmaplen, wlen);
9715ffb0c9bSToomas Soome                     break;
9725ffb0c9bSToomas Soome                 }
9735ffb0c9bSToomas Soome                 if (win < 0 || win >= 256)
9745ffb0c9bSToomas Soome                 {
9755ffb0c9bSToomas Soome                     printf("Case NSEC: malformed nsec, bad window win %d\n", win);
9765ffb0c9bSToomas Soome                     break;
9775ffb0c9bSToomas Soome                 }
9785ffb0c9bSToomas Soome                 type = win * 256;
9795ffb0c9bSToomas Soome                 for (i = 0; i < wlen * 8; i++)
9805ffb0c9bSToomas Soome                 {
9815ffb0c9bSToomas Soome                     if (bmap[i>>3] & (128 >> (i&7)))
9825ffb0c9bSToomas Soome                         p += snprintf(p, rdb + rdb_size - p, " %s ", DNSTypeName(type + i));
9835ffb0c9bSToomas Soome                 }
9845ffb0c9bSToomas Soome                 bmap += wlen;
9855ffb0c9bSToomas Soome                 bitmaplen -= wlen;
9865ffb0c9bSToomas Soome             }
9875ffb0c9bSToomas Soome             break;
9885ffb0c9bSToomas Soome         }
989c1de7575SRichard Lowe 
990c1de7575SRichard Lowe         case kDNSServiceType_RRSIG:
9915ffb0c9bSToomas Soome         {
9925ffb0c9bSToomas Soome             rdataRRSig *rrsig = (rdataRRSig *)rd;
9935ffb0c9bSToomas Soome             unsigned char expTimeBuf[64];
9945ffb0c9bSToomas Soome             unsigned char inceptTimeBuf[64];
9955ffb0c9bSToomas Soome             unsigned long inceptClock;
9965ffb0c9bSToomas Soome             unsigned long expClock;
9975ffb0c9bSToomas Soome             const unsigned char *q = NULL;
9985ffb0c9bSToomas Soome             char *k = NULL;
9995ffb0c9bSToomas Soome             int len;
1000c1de7575SRichard Lowe 
10015ffb0c9bSToomas Soome             expClock = (unsigned long)swap32(rrsig->sigExpireTime);
10025ffb0c9bSToomas Soome             FormatTime(expClock, expTimeBuf, sizeof(expTimeBuf));
1003c1de7575SRichard Lowe 
10045ffb0c9bSToomas Soome             inceptClock = (unsigned long)swap32(rrsig->sigInceptTime);
10055ffb0c9bSToomas Soome             FormatTime(inceptClock, inceptTimeBuf, sizeof(inceptTimeBuf));
1006c1de7575SRichard Lowe 
10075ffb0c9bSToomas Soome             p += snprintf(p, rdb + rdb_size - p, " %-7s  %d  %d  %d  %s  %s  %7d  ",
10085ffb0c9bSToomas Soome                           DNSTypeName(swap16(rrsig->typeCovered)), rrsig->alg, rrsig->labels, swap32(rrsig->origTTL),
10095ffb0c9bSToomas Soome                           expTimeBuf, inceptTimeBuf, swap16(rrsig->keyTag));
1010c1de7575SRichard Lowe 
10115ffb0c9bSToomas Soome             q = (const unsigned char *)&rrsig->signerName;
10125ffb0c9bSToomas Soome             k = p;
10135ffb0c9bSToomas Soome             p += snprintd(p, rdb + rdb_size - p, &q);
10145ffb0c9bSToomas Soome             len = p - k + 1;
1015*3b436d06SToomas Soome 
1016*3b436d06SToomas Soome             if ((&rdb[rdb_size] - p) >= 2)
1017*3b436d06SToomas Soome             {
1018*3b436d06SToomas Soome                 *p++ = ' ';
1019*3b436d06SToomas Soome                 *p   = '\0';
1020*3b436d06SToomas Soome             }
10215ffb0c9bSToomas Soome             base64Encode(p, rdb + rdb_size - p, (unsigned char *)(rd + len + RRSIG_FIXED_SIZE), rdlen - (len + RRSIG_FIXED_SIZE));
10225ffb0c9bSToomas Soome             break;
10235ffb0c9bSToomas Soome         }
10245ffb0c9bSToomas Soome     }
1025c1de7575SRichard Lowe     return;
10265ffb0c9bSToomas Soome }
10275ffb0c9bSToomas Soome 
qr_reply(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t ifIndex,DNSServiceErrorType errorCode,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,void * context)10285ffb0c9bSToomas Soome static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode,
10295ffb0c9bSToomas Soome                                const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
10305ffb0c9bSToomas Soome {
10315ffb0c9bSToomas Soome     char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
10325ffb0c9bSToomas Soome     const unsigned char *rd  = rdata;
10335ffb0c9bSToomas Soome     const unsigned char *end = (const unsigned char *) rdata + rdlen;
10345ffb0c9bSToomas Soome     char rdb[1000] = "", *p = rdb;
10355ffb0c9bSToomas Soome     int unknowntype = 0;
10365ffb0c9bSToomas Soome     char dnssec_status[15] = "Unknown";
10375ffb0c9bSToomas Soome     char rr_type[RR_TYPE_SIZE];
10385ffb0c9bSToomas Soome     char rr_class[3];
10395ffb0c9bSToomas Soome     DNSServiceFlags check_flags = flags;//local flags for dnssec status checking
10405ffb0c9bSToomas Soome 
10415ffb0c9bSToomas Soome     (void)sdref;    // Unused
10425ffb0c9bSToomas Soome     (void)ifIndex;  // Unused
10435ffb0c9bSToomas Soome     (void)ttl;      // Unused
10445ffb0c9bSToomas Soome     (void)context;  // Unused
10455ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
10465ffb0c9bSToomas Soome 
10475ffb0c9bSToomas Soome     if (num_printed++ == 0)
10485ffb0c9bSToomas Soome     {
1049c1de7575SRichard Lowe         if (operation == 'D')
1050*3b436d06SToomas Soome             printf("Timestamp     A/R if %-30s%-6s%-7s%-18s Rdata\n", "Name", "Type", "Class", "DNSSECStatus");
1051c1de7575SRichard Lowe         else
1052*3b436d06SToomas Soome             printf("Timestamp     A/R    Flags if %-30s%-6s%-7s Rdata\n", "Name", "Type", "Class");
10535ffb0c9bSToomas Soome     }
10545ffb0c9bSToomas Soome     printtimestamp();
10555ffb0c9bSToomas Soome 
10565ffb0c9bSToomas Soome     switch (rrclass)
10575ffb0c9bSToomas Soome     {
10585ffb0c9bSToomas Soome         case kDNSServiceClass_IN:
10595ffb0c9bSToomas Soome             strncpy(rr_class, "IN", sizeof(rr_class));
10605ffb0c9bSToomas Soome             break;
10615ffb0c9bSToomas Soome         default:
10625ffb0c9bSToomas Soome             snprintf(rr_class, sizeof(rr_class), "%d", rrclass);
10635ffb0c9bSToomas Soome             break;
10645ffb0c9bSToomas Soome     }
10655ffb0c9bSToomas Soome     strncpy(rr_type, DNSTypeName(rrtype), sizeof(rr_type));
10665ffb0c9bSToomas Soome 
10675ffb0c9bSToomas Soome     if (!errorCode) //to avoid printing garbage in rdata
10685ffb0c9bSToomas Soome     {
10695ffb0c9bSToomas Soome         if (!(check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
10705ffb0c9bSToomas Soome         {
10715ffb0c9bSToomas Soome             switch (rrtype)
10725ffb0c9bSToomas Soome             {
10735ffb0c9bSToomas Soome                 case kDNSServiceType_A:
10745ffb0c9bSToomas Soome                     snprintf(rdb, sizeof(rdb), "%d.%d.%d.%d", rd[0], rd[1], rd[2], rd[3]);
10755ffb0c9bSToomas Soome                     break;
1076c1de7575SRichard Lowe 
10775ffb0c9bSToomas Soome                 case kDNSServiceType_NS:
10785ffb0c9bSToomas Soome                 case kDNSServiceType_CNAME:
10795ffb0c9bSToomas Soome                 case kDNSServiceType_PTR:
10805ffb0c9bSToomas Soome                 case kDNSServiceType_DNAME:
1081cda73f64SToomas Soome                     snprintd(p, sizeof(rdb), &rd);
10825ffb0c9bSToomas Soome                     break;
10835ffb0c9bSToomas Soome 
10845ffb0c9bSToomas Soome                 case kDNSServiceType_SOA:
10855ffb0c9bSToomas Soome                     p += snprintd(p, rdb + sizeof(rdb) - p, &rd);           // mname
10865ffb0c9bSToomas Soome                     p += snprintf(p, rdb + sizeof(rdb) - p, " ");
10875ffb0c9bSToomas Soome                     p += snprintd(p, rdb + sizeof(rdb) - p, &rd);           // rname
1088cda73f64SToomas Soome                          snprintf(p, rdb + sizeof(rdb) - p, " Ser %d Ref %d Ret %d Exp %d Min %d",
1089cda73f64SToomas Soome                              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]));
10905ffb0c9bSToomas Soome                     break;
10915ffb0c9bSToomas Soome 
10925ffb0c9bSToomas Soome                 case kDNSServiceType_AAAA:
10935ffb0c9bSToomas Soome                     snprintf(rdb, sizeof(rdb), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
10945ffb0c9bSToomas Soome                         rd[0x0], rd[0x1], rd[0x2], rd[0x3], rd[0x4], rd[0x5], rd[0x6], rd[0x7],
10955ffb0c9bSToomas Soome                         rd[0x8], rd[0x9], rd[0xA], rd[0xB], rd[0xC], rd[0xD], rd[0xE], rd[0xF]);
10965ffb0c9bSToomas Soome                     break;
10975ffb0c9bSToomas Soome 
10985ffb0c9bSToomas Soome                 case kDNSServiceType_SRV:
10995ffb0c9bSToomas Soome                     p += snprintf(p, rdb + sizeof(rdb) - p, "%d %d %d ",        // priority, weight, port
1100cda73f64SToomas Soome                              ntohs(*(unsigned short*)rd), ntohs(*(unsigned short*)(rd+2)), ntohs(*(unsigned short*)(rd+4)));
11015ffb0c9bSToomas Soome                     rd += 6;
1102cda73f64SToomas Soome                          snprintd(p, rdb + sizeof(rdb) - p, &rd);               // target host
11035ffb0c9bSToomas Soome                     break;
11045ffb0c9bSToomas Soome 
11055ffb0c9bSToomas Soome                 case kDNSServiceType_DS:
11065ffb0c9bSToomas Soome                 case kDNSServiceType_DNSKEY:
11075ffb0c9bSToomas Soome                 case kDNSServiceType_NSEC:
11085ffb0c9bSToomas Soome                 case kDNSServiceType_RRSIG:
1109*3b436d06SToomas Soome                     ParseDNSSECRecords(rrtype, rdb, sizeof(rdb), rd, rdlen);
11105ffb0c9bSToomas Soome                     break;
11115ffb0c9bSToomas Soome 
1112c1de7575SRichard Lowe                 default:
1113c1de7575SRichard Lowe                     snprintf(rdb, sizeof(rdb), "%d bytes%s", rdlen, rdlen ? ":" : "");
11145ffb0c9bSToomas Soome                     unknowntype = 1;
11155ffb0c9bSToomas Soome                     break;
1116c1de7575SRichard Lowe             }
1117c1de7575SRichard Lowe         }
1118c1de7575SRichard Lowe         else
11195ffb0c9bSToomas Soome         {
11205ffb0c9bSToomas Soome             strncpy(rdb, "----", sizeof(rdb));
11215ffb0c9bSToomas Soome             //Clear all o/p bits, and then check for dnssec status
11225ffb0c9bSToomas Soome             check_flags &= ~kDNSServiceOutputFlags;
11235ffb0c9bSToomas Soome             if (check_flags & kDNSServiceFlagsSecure)
11245ffb0c9bSToomas Soome                 strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
11255ffb0c9bSToomas Soome             else if (check_flags & kDNSServiceFlagsInsecure)
11265ffb0c9bSToomas Soome                 strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
11275ffb0c9bSToomas Soome             else if (check_flags & kDNSServiceFlagsIndeterminate)
11285ffb0c9bSToomas Soome                 strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
1129c1de7575SRichard Lowe             else if (check_flags & kDNSServiceFlagsBogus)
11305ffb0c9bSToomas Soome                 strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
11315ffb0c9bSToomas Soome         }
11325ffb0c9bSToomas Soome     }
11335ffb0c9bSToomas Soome 
11345ffb0c9bSToomas Soome     if (operation == 'D')
11355ffb0c9bSToomas Soome         printf("%s%3d %-30s%-6s%-7s%-18s %s", op, ifIndex, fullname, rr_type, rr_class, dnssec_status, rdb);
11365ffb0c9bSToomas Soome     else
1137*3b436d06SToomas Soome         printf("%s%9X%3d %-30s%-7s%-6s %s", op, flags, ifIndex, fullname, rr_type, rr_class, rdb);
11385ffb0c9bSToomas Soome     if (unknowntype)
1139c1de7575SRichard Lowe     {
1140c1de7575SRichard Lowe         while (rd < end)
11415ffb0c9bSToomas Soome             printf(" %02X", *rd++);
11425ffb0c9bSToomas Soome     }
11435ffb0c9bSToomas Soome     if (errorCode)
11445ffb0c9bSToomas Soome     {
1145c1de7575SRichard Lowe         if (errorCode == kDNSServiceErr_NoSuchRecord)
11465ffb0c9bSToomas Soome             printf("    No Such Record");
11475ffb0c9bSToomas Soome         else if (errorCode == kDNSServiceErr_Timeout)
11485ffb0c9bSToomas Soome         {
11495ffb0c9bSToomas Soome             printf("    No Such Record\n");
11505ffb0c9bSToomas Soome             printf("Query Timed Out\n");
11515ffb0c9bSToomas Soome             exit(1);
11525ffb0c9bSToomas Soome         }
11535ffb0c9bSToomas Soome     }
11545ffb0c9bSToomas Soome     printf("\n");
11555ffb0c9bSToomas Soome 
11565ffb0c9bSToomas Soome     if (operation == 'C')
11575ffb0c9bSToomas Soome         if (flags & kDNSServiceFlagsAdd)
11585ffb0c9bSToomas Soome             DNSServiceReconfirmRecord(flags, ifIndex, fullname, rrtype, rrclass, rdlen, rdata);
11595ffb0c9bSToomas Soome 
1160c1de7575SRichard Lowe     if (!(flags & kDNSServiceFlagsMoreComing))
11615ffb0c9bSToomas Soome         fflush(stdout);
11625ffb0c9bSToomas Soome }
11635ffb0c9bSToomas Soome 
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)11645ffb0c9bSToomas Soome static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
11655ffb0c9bSToomas Soome {
11665ffb0c9bSToomas Soome     (void)sdref;       // Unused
11675ffb0c9bSToomas Soome     (void)flags;       // Unused
11685ffb0c9bSToomas Soome     (void)context;     // Unused
11695ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
11705ffb0c9bSToomas Soome 
11715ffb0c9bSToomas Soome     if (num_printed++ == 0) printf("Timestamp     if   %-20s %-15s %-15s %-15s %-6s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
11725ffb0c9bSToomas Soome     printtimestamp();
11735ffb0c9bSToomas Soome     if (errorCode && errorCode != kDNSServiceErr_DoubleNAT) printf("Error code %d\n", errorCode);
11745ffb0c9bSToomas Soome     else
11755ffb0c9bSToomas Soome     {
11765ffb0c9bSToomas Soome         const unsigned char *digits = (const unsigned char *)&publicAddress;
11775ffb0c9bSToomas Soome         char addr[256];
11785ffb0c9bSToomas Soome 
11795ffb0c9bSToomas Soome         snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
11805ffb0c9bSToomas Soome         printf("%-4d %-20s %-15d %-15d %-15d %-6d%s\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl, errorCode == kDNSServiceErr_DoubleNAT ? " Double NAT" : "");
11815ffb0c9bSToomas Soome     }
11825ffb0c9bSToomas Soome 
11835ffb0c9bSToomas Soome     if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
11845ffb0c9bSToomas Soome }
11855ffb0c9bSToomas Soome 
addrinfo_reply(DNSServiceRef sdref,const DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceErrorType errorCode,const char * hostname,const struct sockaddr * address,uint32_t ttl,void * context)11865ffb0c9bSToomas Soome static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context)
11875ffb0c9bSToomas Soome {
11885ffb0c9bSToomas Soome     char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
11895ffb0c9bSToomas Soome     char addr[256] = "";
1190c1de7575SRichard Lowe     char dnssec_status[15] = "Unknown";
11915ffb0c9bSToomas Soome     DNSServiceFlags check_flags = flags;
11925ffb0c9bSToomas Soome 	(void) sdref;
11935ffb0c9bSToomas Soome 	(void) context;
11945ffb0c9bSToomas Soome 
11955ffb0c9bSToomas Soome     EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
11965ffb0c9bSToomas Soome 
11975ffb0c9bSToomas Soome     if (num_printed++ == 0)
11985ffb0c9bSToomas Soome     {
1199c1de7575SRichard Lowe         if (operation == 'g')
12005ffb0c9bSToomas Soome             printf("Timestamp     A/R if %-25s %-44s %-18s\n", "Hostname", "Address", "DNSSECStatus");
1201c1de7575SRichard Lowe         else
1202*3b436d06SToomas Soome             printf("Timestamp     A/R    Flags if %-38s %-44s %s\n", "Hostname", "Address", "TTL");
12035ffb0c9bSToomas Soome     }
12045ffb0c9bSToomas Soome     printtimestamp();
1205c1de7575SRichard Lowe 
12065ffb0c9bSToomas Soome     if (address && address->sa_family == AF_INET)
12075ffb0c9bSToomas Soome     {
12085ffb0c9bSToomas Soome         const unsigned char *b = (const unsigned char *) &((struct sockaddr_in *)address)->sin_addr;
12095ffb0c9bSToomas Soome         snprintf(addr, sizeof(addr), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
12105ffb0c9bSToomas Soome     }
12115ffb0c9bSToomas Soome     else if (address && address->sa_family == AF_INET6)
12125ffb0c9bSToomas Soome     {
12135ffb0c9bSToomas Soome         char if_name[IFNAMSIZ];     // Older Linux distributions don't define IF_NAMESIZE
12145ffb0c9bSToomas Soome         const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)address;
12155ffb0c9bSToomas Soome         const unsigned char       *b  = (const unsigned char *      )&s6->sin6_addr;
12165ffb0c9bSToomas Soome         if (!if_indextoname(s6->sin6_scope_id, if_name))
12175ffb0c9bSToomas Soome             snprintf(if_name, sizeof(if_name), "<%d>", s6->sin6_scope_id);
1218985cc36cSToomas Soome         snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
12195ffb0c9bSToomas Soome             b[0x0], b[0x1], b[0x2], b[0x3], b[0x4], b[0x5], b[0x6], b[0x7],
12205ffb0c9bSToomas Soome             b[0x8], b[0x9], b[0xA], b[0xB], b[0xC], b[0xD], b[0xE], b[0xF], if_name);
12215ffb0c9bSToomas Soome     }
12225ffb0c9bSToomas Soome 
12235ffb0c9bSToomas Soome     //go through this only if you have a dnssec validation status
12245ffb0c9bSToomas Soome     if (!errorCode && (check_flags & (kDNSServiceFlagsValidate | kDNSServiceFlagsValidateOptional)))
12255ffb0c9bSToomas Soome     {
12265ffb0c9bSToomas Soome         strncpy(addr, "----", sizeof(addr));
12275ffb0c9bSToomas Soome         //Clear all o/p bits, and then check for dnssec status
12285ffb0c9bSToomas Soome         check_flags &= ~kDNSServiceOutputFlags;
12295ffb0c9bSToomas Soome         if (check_flags & kDNSServiceFlagsSecure)
12305ffb0c9bSToomas Soome             strncpy(dnssec_status, "Secure", sizeof(dnssec_status));
12315ffb0c9bSToomas Soome         else if (check_flags & kDNSServiceFlagsInsecure)
12325ffb0c9bSToomas Soome             strncpy(dnssec_status, "Insecure", sizeof(dnssec_status));
12335ffb0c9bSToomas Soome         else if (check_flags & kDNSServiceFlagsIndeterminate)
12345ffb0c9bSToomas Soome             strncpy(dnssec_status, "Indeterminate", sizeof(dnssec_status));
1235c1de7575SRichard Lowe         else if (check_flags & kDNSServiceFlagsBogus)
12365ffb0c9bSToomas Soome             strncpy(dnssec_status, "Bogus", sizeof(dnssec_status));
12375ffb0c9bSToomas Soome     }
1238c1de7575SRichard Lowe 
12395ffb0c9bSToomas Soome     if (operation == 'g')
12405ffb0c9bSToomas Soome         printf("%s%3d %-25s %-44s %-18s", op, interfaceIndex, hostname, addr, dnssec_status);
12415ffb0c9bSToomas Soome     else
1242*3b436d06SToomas Soome         printf("%s%9X%3d %-38s %-44s %d", op, flags, interfaceIndex, hostname, addr, ttl);
12435ffb0c9bSToomas Soome     if (errorCode)
12445ffb0c9bSToomas Soome     {
1245c1de7575SRichard Lowe         if (errorCode == kDNSServiceErr_NoSuchRecord)
12465ffb0c9bSToomas Soome             printf("   No Such Record");
1247c1de7575SRichard Lowe         else
12485ffb0c9bSToomas Soome             printf("   Error code %d", errorCode);
12495ffb0c9bSToomas Soome     }
12505ffb0c9bSToomas Soome     printf("\n");
12515ffb0c9bSToomas Soome 
1252c1de7575SRichard Lowe     if (!(flags & kDNSServiceFlagsMoreComing))
12535ffb0c9bSToomas Soome         fflush(stdout);
12545ffb0c9bSToomas Soome }
12555ffb0c9bSToomas Soome 
12565ffb0c9bSToomas Soome //*************************************************************************************************************
12575ffb0c9bSToomas Soome // The main test function
12585ffb0c9bSToomas Soome 
HandleEvents(void)12595ffb0c9bSToomas Soome static void HandleEvents(void)
12605ffb0c9bSToomas Soome #if _DNS_SD_LIBDISPATCH
12615ffb0c9bSToomas Soome {
12625ffb0c9bSToomas Soome     main_queue = dispatch_get_main_queue();
12635ffb0c9bSToomas Soome     if (client) DNSServiceSetDispatchQueue(client, main_queue);
12645ffb0c9bSToomas Soome     if (client_pa) DNSServiceSetDispatchQueue(client_pa, main_queue);
12655ffb0c9bSToomas Soome     if (operation == 'A' || operation == 'U' || operation == 'N')
12665ffb0c9bSToomas Soome     {
12675ffb0c9bSToomas Soome         timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_queue);
12685ffb0c9bSToomas Soome         if (timer_source)
12695ffb0c9bSToomas Soome         {
12705ffb0c9bSToomas Soome             // Start the timer "timeout" seconds into the future and repeat it every "timeout" seconds
12715ffb0c9bSToomas Soome             dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
12725ffb0c9bSToomas Soome                                       (uint64_t)timeOut * NSEC_PER_SEC, 0);
12735ffb0c9bSToomas Soome             dispatch_source_set_event_handler(timer_source, ^{myTimerCallBack();});
12745ffb0c9bSToomas Soome             dispatch_resume(timer_source);
12755ffb0c9bSToomas Soome         }
12765ffb0c9bSToomas Soome     }
12775ffb0c9bSToomas Soome     dispatch_main();
12785ffb0c9bSToomas Soome }
12795ffb0c9bSToomas Soome #else
12805ffb0c9bSToomas Soome {
12815ffb0c9bSToomas Soome     int dns_sd_fd  = client    ? DNSServiceRefSockFD(client   ) : -1;
12825ffb0c9bSToomas Soome     int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
12835ffb0c9bSToomas Soome     int nfds = dns_sd_fd + 1;
12845ffb0c9bSToomas Soome     fd_set readfds;
12855ffb0c9bSToomas Soome     struct timeval tv;
12865ffb0c9bSToomas Soome     int result;
12875ffb0c9bSToomas Soome 
12885ffb0c9bSToomas Soome     if (dns_sd_fd2 > dns_sd_fd) nfds = dns_sd_fd2 + 1;
12895ffb0c9bSToomas Soome 
12905ffb0c9bSToomas Soome     while (!stopNow)
12915ffb0c9bSToomas Soome     {
12925ffb0c9bSToomas Soome         // 1. Set up the fd_set as usual here.
12935ffb0c9bSToomas Soome         // This example client has no file descriptors of its own,
12945ffb0c9bSToomas Soome         // but a real application would call FD_SET to add them to the set here
12955ffb0c9bSToomas Soome         FD_ZERO(&readfds);
12965ffb0c9bSToomas Soome 
12975ffb0c9bSToomas Soome         // 2. Add the fd for our client(s) to the fd_set
12985ffb0c9bSToomas Soome         if (client   ) FD_SET(dns_sd_fd, &readfds);
12995ffb0c9bSToomas Soome         if (client_pa) FD_SET(dns_sd_fd2, &readfds);
13005ffb0c9bSToomas Soome 
13015ffb0c9bSToomas Soome         // 3. Set up the timeout.
13025ffb0c9bSToomas Soome         tv.tv_sec  = timeOut;
13035ffb0c9bSToomas Soome         tv.tv_usec = 0;
13045ffb0c9bSToomas Soome 
13055ffb0c9bSToomas Soome         result = select(nfds, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv);
13065ffb0c9bSToomas Soome         if (result > 0)
13075ffb0c9bSToomas Soome         {
13085ffb0c9bSToomas Soome             DNSServiceErrorType err = kDNSServiceErr_NoError;
13095ffb0c9bSToomas Soome             if      (client    && FD_ISSET(dns_sd_fd, &readfds)) err = DNSServiceProcessResult(client   );
13105ffb0c9bSToomas Soome             else if (client_pa && FD_ISSET(dns_sd_fd2, &readfds)) err = DNSServiceProcessResult(client_pa);
1311c65ebfc7SToomas Soome             if (err) { printtimestamp_F(stderr); fprintf(stderr, "DNSServiceProcessResult returned %d\n", err); stopNow = 1; }
13125ffb0c9bSToomas Soome         }
13135ffb0c9bSToomas Soome         else if (result == 0)
13145ffb0c9bSToomas Soome             myTimerCallBack();
13155ffb0c9bSToomas Soome         else
13165ffb0c9bSToomas Soome         {
13175ffb0c9bSToomas Soome