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