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