1 /* -*- Mode: C; tab-width: 4 -*-
2 *
3 * Copyright (c) 2003-2024 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "dnssd_clientstub.h"
30
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <stdbool.h>
34
35 #include "dnssd_ipc.h"
36
37
38 #ifndef DEBUG_64BIT_SCM_RIGHTS
39 #define DEBUG_64BIT_SCM_RIGHTS 0
40 #endif
41
42 #if defined(_WIN32)
43
44 #define _SSIZE_T
45 #include <CommonServices.h>
46 #include <DebugServices.h>
47 #include <winsock2.h>
48 #include <ws2tcpip.h>
49 #include <windows.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdint.h>
53
54 #define sockaddr_mdns sockaddr_in
55 #define AF_MDNS AF_INET
56
57 // Disable warning: "'type cast' : from data pointer 'void *' to function pointer"
58 #pragma warning(disable:4055)
59
60 // Disable warning: "nonstandard extension, function/data pointer conversion in expression"
61 #pragma warning(disable:4152)
62
63 extern BOOL IsSystemServiceDisabled();
64
65 #define sleep(X) Sleep((X) * 1000)
66
67 static int g_initWinsock = 0;
68 #define LOG_WARNING kDebugLevelWarning
69 #define LOG_INFO kDebugLevelInfo
syslog(int priority,const char * message,...)70 static void syslog( int priority, const char * message, ...)
71 {
72 va_list args;
73 int len;
74 char * buffer;
75 DWORD err = WSAGetLastError();
76 (void) priority;
77 va_start( args, message );
78 len = _vscprintf( message, args ) + 1;
79 buffer = mdns_malloc( len * sizeof(char) );
80 if ( buffer ) { vsnprintf( buffer, len, message, args ); OutputDebugString( buffer ); mdns_free( buffer ); }
81 WSASetLastError( err );
82 }
83 #else
84
85 #include <fcntl.h> // For O_RDWR etc.
86 #include <sys/time.h>
87 #include <sys/socket.h>
88 #include <syslog.h>
89 #include <sys/uio.h>
90
91 #endif
92
93 #include "mdns_strict.h"
94
95 #if !defined(SETIOV)
96 #if defined(_WIN32)
97 #define iovec_t WSABUF
98 #define iov_len len
99 #define iov_base buf
100
101 #define SETIOV(IOV, PTR, LEN) \
102 do \
103 { \
104 (IOV)->iov_base = (char *)(PTR); \
105 (IOV)->iov_len = (LEN); \
106 } while(0)
107
108 static
writev(SocketRef inSock,const iovec_t * inArray,int inCount)109 ssize_t writev(SocketRef inSock, const iovec_t *inArray, int inCount)
110 {
111 int err;
112 DWORD n;
113
114 err = WSASend(inSock, (iovec_t *)inArray, inCount, &n, 0, NULL, NULL);
115 return(err ? err : n);
116 }
117
118 #else
119 typedef struct iovec iovec_t;
120
121 #define SETIOV(IOV, PTR, LEN) \
122 do \
123 { \
124 (IOV)->iov_base = (void *)(PTR); \
125 (IOV)->iov_len = (LEN); \
126 } while(0)
127 #endif
128 #endif
129
130 #if defined(_WIN32)
131 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
132
133 #define DNSSD_CLIENT_MAXTRIES 4
134 #endif // _WIN32
135
136 // Uncomment the line below to use the old error return mechanism of creating a temporary named socket (e.g. in /var/tmp)
137 //#define USE_NAMED_ERROR_RETURN_SOCKET 1
138
139 // If the UDS client has not received a response from the daemon in 60 secs, it is unlikely to get one
140 // Note: Timeout of 3 secs should be sufficient in normal scenarios, but 60 secs is chosen as a safeguard since
141 // some clients may come up before mDNSResponder itself after a BOOT and on rare ocassions IOPM/Keychain/D2D calls
142 // in mDNSResponder's INIT may take a much longer time to return
143 #define DNSSD_CLIENT_TIMEOUT 60
144
145 #ifdef USE_NAMED_ERROR_RETURN_SOCKET
146 #ifndef CTL_PATH_PREFIX
147 #define CTL_PATH_PREFIX "/var/tmp/dnssd_result_socket."
148 #endif
149 #endif
150
151 typedef struct
152 {
153 ipc_msg_hdr ipc_hdr;
154 DNSServiceFlags cb_flags;
155 uint32_t cb_interface;
156 DNSServiceErrorType cb_err;
157 } CallbackHeader;
158
159 typedef struct _DNSServiceRef_t DNSServiceOp;
160 typedef struct _DNSRecordRef_t DNSRecord;
161
162 #if !defined(_WIN32)
163 typedef struct
164 {
165 void *AppCallback; // Client callback function and context
166 void *AppContext;
167 } SleepKAContext;
168 #endif
169
170 // client stub callback to process message from server and deliver results to client application
171 typedef void (*ProcessReplyFn)(DNSServiceOp *sdr, const CallbackHeader *cbh, const uint8_t *msg, const uint8_t *end);
172
173 #define ValidatorBits 0x12345678
174 #define DNSServiceRefValid(X) (dnssd_SocketValid((X)->sockfd) && (((X)->sockfd ^ (X)->validator) == ValidatorBits))
175
176 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
177 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
178 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
179 //
180 // _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
181 // DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
182 struct _DNSServiceRef_t
183 {
184 DNSServiceOp *next; // When sharing a connection, this is the next subordinate DNSServiceRef in
185 // the list. The connection being shared is the first in the list.
186 DNSServiceOp *primary; // When sharing a connection, the primary pointer of each subordinate
187 // DNSServiceRef points to the head of the list. If primary is null, and next is
188 // null, this is not a shared connection. If primary is null and next is
189 // non-null, this is the primary DNSServiceRef of the shared connection. If
190 // primary is non-null, this is a subordinate DNSServiceRef for the connection
191 // that is managed by the DNSServiceRef pointed to by primary.
192 dnssd_sock_t sockfd; // Connected socket between client and daemon
193 dnssd_sock_t validator; // Used to detect memory corruption, double disposals, etc.
194 client_context_t uid; // For shared connection requests, each subordinate DNSServiceRef has its own ID,
195 // unique within the scope of the same shared parent DNSServiceRef. On the
196 // primary DNSServiceRef, uid matches the uid of the most recently allocated
197 // subordinate DNSServiceRef. Each time a new subordinate DNSServiceRef is
198 // allocated, uid on the primary is incremented by one and copied to the
199 // subordinate.
200 uint32_t op; // request_op_t or reply_op_t
201 uint32_t max_index; // Largest assigned record index - 0 if no additional records registered
202 uint32_t logcounter; // Counter used to control number of syslog messages we write
203 int *moreptr; // Set while DNSServiceProcessResult working on this particular DNSServiceRef
204 ProcessReplyFn ProcessReply; // Function pointer to the code to handle received messages
205 void *AppCallback; // Client callback function and context
206 void *AppContext;
207 DNSRecord *rec;
208 #if _DNS_SD_LIBDISPATCH
209 dispatch_source_t disp_source;
210 dispatch_queue_t disp_queue;
211 #endif
212 void *kacontext;
213 };
214
215 // Any DNSServiceRef can have a list of one or more DNSRecordRefs. These DNSRecordRefs either come from
216 // DNSServiceRegisterRecord calls on a DNSServiceRef allocated using DNSServiceCreateConnection, or else
217 // they come from DNSServiceAddRecord calls on a DNSServiceRef allocated using DNSServiceRegisterRecord.
218 // A connection created using DNSServiceCreateConnection can also be used as a shared connection for registering
219 // services using DNSServiceRegister. Or a connection can have both records registered with
220 // DNSServiceRegisterRecord and services registered with DNSServiceRegister. A shared connection can also have
221 // browses, resolves, and so on, each of which will have a subordinate DNSServiceRef.
222 // This data structure is mirrored in the server daemon. To summarize:
223 // For any given DNSServiceRef created by DNSServiceCreateConnection,
224 // - there may be zero or more subordinate DNSServiceRefs.
225 // - there may be zero or more DNSRecordRefs
226 // Any DNSServiceRef created by DNSServiceRegister may
227 // - be a subordinate DNSServiceRef of a DNSServiceRef created by DNSServiceCreateConnection, or not
228 // - be a standalone DNSServiceRef with its own connection
229 // - may have zero or more records registered with DNSServiceAddRecord
230 // - may not have any records registered with DNSServiceRegisterRecord
231 // - may not be used as a shared connection
232
233 struct _DNSRecordRef_t
234 {
235 DNSRecord *recnext;
236 void *AppContext;
237 DNSServiceRegisterRecordReply AppCallback;
238 DNSRecordRef recref;
239 uint32_t record_index; // index is unique within the set of DNSRecordRefs owned by its parent (sdr).
240 client_context_t uid; // a copy of sdr->uid made when the recordref is created. if sdr is a shared
241 // connection, this may not match sdr->uid later on. If it is a subordinate
242 // connection or a non-shared connection, then sdr->uid should always match
243 // uid.
244 DNSServiceOp *sdr;
245 ipc_msg_hdr *msg;
246 };
247
248 struct DNSServiceAttribute_s {
249 DNSServiceAAAAPolicy aaaa_policy;
250 uint32_t hostkeyhash;
251 uint32_t timestamp; //Timestamp in seconds since epoch time to indicate when the service/record is registered.
252 bool hostkeyhash_is_set;
253 bool timestamp_is_set;
254 };
255
256 const DNSServiceAttribute kDNSServiceAttributeAAAAFallback = {
257 .aaaa_policy = kDNSServiceAAAAPolicyFallback
258 };
259
260
DNSServiceQueryRecordWithAttribute(DNSServiceRef * const sdRef,const DNSServiceFlags flags,const uint32_t ifindex,const char * const name,const uint16_t rrtype,const uint16_t rrclass,const DNSServiceAttribute * const attr,const DNSServiceQueryRecordReply callback,void * const context)261 DNSServiceErrorType DNSSD_API DNSServiceQueryRecordWithAttribute
262 (
263 DNSServiceRef * const sdRef,
264 const DNSServiceFlags flags,
265 const uint32_t ifindex,
266 const char * const name,
267 const uint16_t rrtype,
268 const uint16_t rrclass,
269 const DNSServiceAttribute * const attr,
270 const DNSServiceQueryRecordReply callback,
271 void * const context
272 )
273 {
274 return DNSServiceQueryRecordInternal(sdRef, flags, ifindex, name, rrtype, rrclass, attr, callback, context);
275 }
276
277 // send out all the linked requets in sdr->rec
DNSServiceSendQueuedRequests(DNSServiceRef sdr)278 DNSServiceErrorType DNSSD_API DNSServiceSendQueuedRequests
279 (
280 DNSServiceRef sdr
281 )
282 {
283 return DNSServiceSendQueuedRequestsInternal(sdr);
284 }
285
DNSServiceAttributeCreate(void)286 DNSServiceAttributeRef DNSSD_API DNSServiceAttributeCreate
287 (
288 void
289 )
290 {
291 #ifdef MEMORY_OBJECT_TRACKING
292 extern int saref_created;
293 saref_created++;
294 #endif
295 DNSServiceAttributeRef attr = (DNSServiceAttributeRef)mdns_calloc(1, sizeof(*attr));
296 return attr;
297 }
298
DNSServiceAttributeSetAAAAPolicy(const DNSServiceAttributeRef attr,const DNSServiceAAAAPolicy policy)299 DNSServiceErrorType DNSSD_API DNSServiceAttributeSetAAAAPolicy
300 (
301 const DNSServiceAttributeRef attr,
302 const DNSServiceAAAAPolicy policy
303 )
304 {
305 attr->aaaa_policy = policy;
306 return kDNSServiceErr_NoError;
307 }
308
309
DNSServiceAttributeSetHostKeyHash(const DNSServiceAttributeRef attr,uint32_t host_key)310 DNSServiceErrorType DNSSD_API DNSServiceAttributeSetHostKeyHash
311 (
312 const DNSServiceAttributeRef attr,
313 uint32_t host_key
314 )
315 {
316 attr->hostkeyhash_is_set = true;
317 attr->hostkeyhash = host_key;
318 return kDNSServiceErr_NoError;
319 }
320
DNSServiceAttributeSetTimestamp(const DNSServiceAttributeRef attr,const uint32_t timestamp)321 DNSServiceErrorType DNSSD_API DNSServiceAttributeSetTimestamp
322 (
323 const DNSServiceAttributeRef attr,
324 const uint32_t timestamp
325 )
326 {
327 attr->timestamp_is_set = true;
328 attr->timestamp = timestamp;
329 return kDNSServiceErr_NoError;
330 }
331
DNSServiceAttributeDeallocate(DNSServiceAttributeRef attr)332 void DNSSD_API DNSServiceAttributeDeallocate(DNSServiceAttributeRef attr)
333 {
334 #ifdef MEMORY_OBJECT_TRACKING
335 extern int saref_finalized;
336 saref_finalized++;
337 #endif
338 DNSServiceAttributeRef tmp = attr;
339 mdns_free(tmp);
340 }
341
342 static bool
validate_attribute_tlvs(const DNSServiceAttribute * const attr)343 validate_attribute_tlvs(const DNSServiceAttribute * const attr)
344 {
345 if (!attr)
346 {
347 return true;
348 }
349 // If either is set, require both
350 if ((attr->timestamp_is_set || attr->hostkeyhash_is_set) &&
351 (!attr->timestamp_is_set || !attr->hostkeyhash_is_set))
352 {
353 return false;
354 }
355 return true;
356 }
357
358 static size_t
put_attribute_tlvs(const DNSServiceAttribute * const attr,ipc_msg_hdr * const hdr,uint8_t ** const ptr,const uint8_t * const limit)359 put_attribute_tlvs(const DNSServiceAttribute * const attr, ipc_msg_hdr * const hdr, uint8_t ** const ptr,
360 const uint8_t * const limit)
361 {
362 size_t required_len = 0;
363 required_len += put_tlv_uint32(IPC_TLV_TYPE_SERVICE_ATTR_AAAA_POLICY, attr->aaaa_policy, ptr, limit);
364 if (attr->timestamp_is_set)
365 {
366 required_len += put_tlv_uint32(IPC_TLV_TYPE_SERVICE_ATTR_TIMESTAMP, attr->timestamp, ptr, limit);
367 }
368 if (attr->hostkeyhash_is_set)
369 {
370 required_len += put_tlv_uint32(IPC_TLV_TYPE_SERVICE_ATTR_HOST_KEY_HASH, attr->hostkeyhash, ptr, limit);
371 }
372 if (hdr)
373 {
374 hdr->ipc_flags |= IPC_FLAGS_TRAILING_TLVS;
375 }
376 return required_len;
377 }
378
379 static size_t
get_required_length_for_attribute_tlvs(const DNSServiceAttribute * const attr)380 get_required_length_for_attribute_tlvs(const DNSServiceAttribute * const attr)
381 {
382 return put_attribute_tlvs(attr, NULL, NULL, NULL);
383 }
384
_should_return_noauth_error(void)385 static bool _should_return_noauth_error(void)
386 {
387 static bool s_should = false;
388 return s_should;
389 }
390
391 #if !defined(USE_TCP_LOOPBACK)
SetUDSPath(struct sockaddr_un * saddr,const char * path)392 static void SetUDSPath(struct sockaddr_un *saddr, const char *path)
393 {
394 size_t pathLen;
395
396 pathLen = strlen(path);
397 if (pathLen < sizeof(saddr->sun_path))
398 memcpy(saddr->sun_path, path, pathLen + 1);
399 else
400 saddr->sun_path[0] = '\0';
401 }
402 #endif
403
404 enum { write_all_success = 0, write_all_fail = -1, write_all_defunct = -2 };
405
406 // Write len bytes. Return 0 on success, -1 on error
write_all(dnssd_sock_t sd,char * buf,size_t len)407 static int write_all(dnssd_sock_t sd, char *buf, size_t len)
408 {
409 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
410 //if (send(sd, buf, len, MSG_WAITALL) != len) return write_all_fail;
411 while (len)
412 {
413 ssize_t num_written = send(sd, buf, (long)len, 0);
414 if (num_written < 0 || (size_t)num_written > len)
415 {
416 // Check whether socket has gone defunct,
417 // otherwise, an error here indicates some OS bug
418 // or that the mDNSResponder daemon crashed (which should never happen).
419 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
420 int defunct = 0;
421 socklen_t dlen = sizeof (defunct);
422 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
423 syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
424 if (!defunct)
425 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
426 (long)num_written, (long)len,
427 (num_written < 0) ? dnssd_errno : 0,
428 (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
429 else
430 syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
431 return defunct ? write_all_defunct : write_all_fail;
432 #else
433 syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
434 (long)num_written, (long)len,
435 (num_written < 0) ? dnssd_errno : 0,
436 (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
437 return write_all_fail;
438 #endif
439 }
440 buf += num_written;
441 len -= num_written;
442 }
443 return write_all_success;
444 }
445
446 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2, read_all_defunct = -3 };
447
448 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
read_all(const dnssd_sock_t sd,uint8_t * buf,size_t len)449 static int read_all(const dnssd_sock_t sd, uint8_t *buf, size_t len)
450 {
451 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
452 //if (recv(sd, buf, len, MSG_WAITALL) != len) return -1;
453
454 while (len)
455 {
456 ssize_t num_read = recv(sd, buf, len, 0);
457 // It is valid to get an interrupted system call error e.g., somebody attaching
458 // in a debugger, retry without failing
459 if ((num_read < 0) && (errno == EINTR))
460 {
461 syslog(LOG_INFO, "dnssd_clientstub read_all: EINTR continue");
462 continue;
463 }
464 if ((num_read == 0) || (num_read < 0) || (((size_t)num_read) > len))
465 {
466 int printWarn = 0;
467 int defunct = 0;
468
469 // Check whether socket has gone defunct,
470 // otherwise, an error here indicates some OS bug
471 // or that the mDNSResponder daemon crashed (which should never happen).
472 #if defined(WIN32)
473 // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
474 // could not be completed immediately"
475 if (WSAGetLastError() != WSAEWOULDBLOCK)
476 printWarn = 1;
477 #endif
478 #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
479 {
480 socklen_t dlen = sizeof (defunct);
481 if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
482 syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
483 }
484 if (!defunct)
485 printWarn = 1;
486 #endif
487 if (printWarn)
488 syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
489 (long)num_read, (long)len,
490 (num_read < 0) ? dnssd_errno : 0,
491 (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
492 else if (defunct)
493 syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
494 return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : (defunct ? read_all_defunct : read_all_fail);
495 }
496 buf += num_read;
497 len -= num_read;
498 }
499 return read_all_success;
500 }
501
502 // Returns 1 if more bytes remain to be read on socket descriptor sd, 0 otherwise
more_bytes(dnssd_sock_t sd)503 static int more_bytes(dnssd_sock_t sd)
504 {
505 struct timeval tv = { 0, 0 };
506 fd_set readfds;
507 fd_set *fs;
508 int ret;
509
510 #if defined(_WIN32)
511 fs = &readfds;
512 FD_ZERO(fs);
513 FD_SET(sd, fs);
514 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
515 #else
516 // This whole thing would probably be better done using kevent() instead of select()
517 if (sd < FD_SETSIZE)
518 {
519 fs = &readfds;
520 FD_ZERO(fs);
521 }
522 else
523 {
524 // Compute the number of integers needed for storing "sd". Internally fd_set is stored
525 // as an array of ints with one bit for each fd and hence we need to compute
526 // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
527 // two ints and not just one.
528 int nfdbits = sizeof (int) * 8;
529 int nints = (sd/nfdbits) + 1;
530 fs = (fd_set *)mdns_calloc(nints, (size_t)sizeof(int));
531 if (fs == NULL)
532 {
533 syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed");
534 return 0;
535 }
536 }
537 FD_SET(sd, fs);
538 ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
539 if (fs != &readfds)
540 mdns_free(fs);
541 #endif
542 return (ret > 0);
543 }
544
545 // set_waitlimit() implements a timeout using select. It is called from deliver_request() before recv() OR accept()
546 // to ensure the UDS clients are not blocked in these system calls indefinitely.
547 // Note: Ideally one should never be blocked here, because it indicates either mDNSResponder daemon is not yet up/hung/
548 // superbusy/crashed or some other OS bug. For eg: On Windows which suffers from 3rd party software
549 // (primarily 3rd party firewall software) interfering with proper functioning of the TCP protocol stack it is possible
550 // the next operation on this socket(recv/accept) is blocked since we depend on TCP to communicate with the system service.
set_waitlimit(dnssd_sock_t sock,int timeout)551 static int set_waitlimit(dnssd_sock_t sock, int timeout)
552 {
553 int gDaemonErr = kDNSServiceErr_NoError;
554
555 // The comment below is wrong. The select() routine does not cause stack corruption.
556 // The use of FD_SET out of range for the bitmap is what causes stack corruption.
557 // For how to do this correctly, see the example using calloc() in more_bytes() above.
558 // Even better, both should be changed to use kevent() instead of select().
559 // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
560 if (!gDaemonErr && sock < FD_SETSIZE)
561 {
562 struct timeval tv;
563 fd_set set;
564
565 FD_ZERO(&set);
566 FD_SET(sock, &set);
567 tv.tv_sec = timeout;
568 tv.tv_usec = 0;
569 if (!select((int)(sock + 1), &set, NULL, NULL, &tv))
570 {
571 // Ideally one should never hit this case: See comments before set_waitlimit()
572 syslog(LOG_WARNING, "dnssd_clientstub set_waitlimit:_daemon timed out (%d secs) without any response: Socket %d", timeout, sock);
573 gDaemonErr = kDNSServiceErr_Timeout;
574 }
575 }
576 return gDaemonErr;
577 }
578
579 /* create_hdr
580 *
581 * allocate and initialize an ipc message header. Value of len should initially be the
582 * length of the data, and is set to the value of the data plus the header. data_start
583 * is set to point to the beginning of the data section. SeparateReturnSocket should be
584 * non-zero for calls that can't receive an immediate error return value on their primary
585 * socket, and therefore require a separate return path for the error code result.
586 * if zero, the path to a control socket is appended at the beginning of the message buffer.
587 * data_start is set past this string.
588 */
create_hdr(uint32_t op,size_t * len,uint8_t ** data_start,int SeparateReturnSocket,DNSServiceOp * ref)589 static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, uint8_t **data_start, int SeparateReturnSocket, DNSServiceOp *ref)
590 {
591 uint8_t *msg = NULL;
592 ipc_msg_hdr *hdr;
593 int datalen;
594 #if !defined(USE_TCP_LOOPBACK)
595 char ctrl_path[64] = ""; // "/var/tmp/dnssd_result_socket.xxxxxxxxxx-xxx-xxxxxx"
596 #endif
597
598 if (SeparateReturnSocket)
599 {
600 #if defined(USE_TCP_LOOPBACK)
601 *len += 2; // Allocate space for two-byte port number
602 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
603 struct timeval tv;
604 if (gettimeofday(&tv, NULL) < 0)
605 { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
606 snprintf(ctrl_path, sizeof(ctrl_path), "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
607 (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
608 *len += strlen(ctrl_path) + 1;
609 #else
610 *len += 1; // Allocate space for single zero byte (empty C string)
611 #endif
612 }
613
614 datalen = (int) *len;
615 *len += sizeof(ipc_msg_hdr);
616
617 // Write message to buffer
618 msg = (uint8_t *)mdns_malloc(*len);
619 if (!msg) { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: malloc failed"); return NULL; }
620
621 memset(msg, 0, *len);
622 hdr = (ipc_msg_hdr *)msg;
623 hdr->version = VERSION;
624 hdr->datalen = datalen;
625 hdr->ipc_flags = 0;
626 hdr->op = op;
627 hdr->client_context = ref->uid;
628 hdr->reg_index = 0;
629 *data_start = msg + sizeof(ipc_msg_hdr);
630 #if defined(USE_TCP_LOOPBACK)
631 // Put dummy data in for the port, since we don't know what it is yet.
632 // The data will get filled in before we send the message. This happens in deliver_request().
633 if (SeparateReturnSocket) put_uint16(0, data_start);
634 #else
635 if (SeparateReturnSocket) put_string(ctrl_path, data_start);
636 #endif
637 return hdr;
638 }
639
FreeDNSRecords(DNSServiceOp * sdRef)640 static void FreeDNSRecords(DNSServiceOp *sdRef)
641 {
642 DNSRecord *rec = sdRef->rec;
643 while (rec)
644 {
645 DNSRecord *next = rec->recnext;
646 #ifdef MEMORY_OBJECT_TRACKING
647 extern int rref_finalized;
648 rref_finalized++;
649 #endif
650 mdns_free(rec->msg);
651 mdns_free(rec);
652 rec = next;
653 }
654 }
655
FreeDNSServiceOp(DNSServiceOp * x)656 static void FreeDNSServiceOp(DNSServiceOp *x)
657 {
658 #ifdef MEMORY_OBJECT_TRACKING
659 extern void *dns_service_op_not_to_be_freed;
660 if (x != NULL && x == dns_service_op_not_to_be_freed) {
661 syslog(LOG_ERR, "dnssd_clientstub attempt to dispose protected DNSServiceRef %p", x);
662 abort();
663 }
664 #endif
665 // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
666 // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
667 if ((x->sockfd ^ x->validator) != ValidatorBits)
668 {
669 }
670 else
671 {
672 x->next = NULL;
673 x->primary = NULL;
674 x->sockfd = dnssd_InvalidSocket;
675 x->validator = 0xDDDDDDDD;
676 x->op = request_op_none;
677 x->max_index = 0;
678 x->logcounter = 0;
679 x->moreptr = NULL;
680 x->ProcessReply = NULL;
681 x->AppCallback = NULL;
682 x->AppContext = NULL;
683 #if _DNS_SD_LIBDISPATCH
684 MDNS_DISPOSE_DISPATCH(x->disp_source);
685 x->disp_queue = NULL;
686 #endif
687 // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
688 // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiceRegisterRecord.
689 // DNSRecords may have been freed if the application called DNSRemoveRecord.
690 FreeDNSRecords(x);
691 if (x->kacontext)
692 {
693 mdns_free(x->kacontext);
694 x->kacontext = NULL;
695 }
696 mdns_free(x);
697 #ifdef MEMORY_OBJECT_TRACKING
698 extern int sdref_finalized;
699 sdref_finalized++;
700 #endif
701 }
702 }
703
704 // Return a connected service ref (deallocate with DNSServiceRefDeallocate)
ConnectToServer(DNSServiceRef * ref,DNSServiceFlags flags,uint32_t op,ProcessReplyFn ProcessReply,void * AppCallback,void * AppContext)705 static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags flags, uint32_t op, ProcessReplyFn ProcessReply, void *AppCallback, void *AppContext)
706 {
707 #if defined(_WIN32)
708 int NumTries = 0;
709 #endif // _WIN32
710
711 dnssd_sockaddr_t saddr;
712 DNSServiceOp *sdr;
713
714 if (!ref)
715 {
716 syslog(LOG_WARNING, "dnssd_clientstub DNSService operation with NULL DNSServiceRef");
717 return kDNSServiceErr_BadParam;
718 }
719
720 if (flags & kDNSServiceFlagsShareConnection)
721 {
722 if (!*ref)
723 {
724 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with NULL DNSServiceRef");
725 return kDNSServiceErr_BadParam;
726 }
727 if (!DNSServiceRefValid(*ref) || ((*ref)->op != connection_request && (*ref)->op != connection_delegate_request) || (*ref)->primary)
728 {
729 syslog(LOG_WARNING, "dnssd_clientstub kDNSServiceFlagsShareConnection used with invalid DNSServiceRef %p %08X %08X op %d",
730 (*ref), (*ref)->sockfd, (*ref)->validator, (*ref)->op);
731 *ref = NULL;
732 return kDNSServiceErr_BadReference;
733 }
734 }
735
736 #if defined(_WIN32)
737 if (!g_initWinsock)
738 {
739 WSADATA wsaData;
740 g_initWinsock = 1;
741 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { *ref = NULL; return kDNSServiceErr_ServiceNotRunning; }
742 }
743
744 #ifndef WIN32_CENTENNIAL
745 // <rdar://problem/4096913> If the system service is disabled, we only want to try to connect once
746 if (IsSystemServiceDisabled())
747 NumTries = DNSSD_CLIENT_MAXTRIES;
748 #endif
749 #endif
750
751 sdr = mdns_malloc(sizeof(DNSServiceOp));
752 if (!sdr)
753 {
754 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: malloc failed");
755 *ref = NULL;
756 return kDNSServiceErr_NoMemory;
757 }
758 sdr->next = NULL;
759 sdr->primary = NULL;
760 sdr->sockfd = dnssd_InvalidSocket;
761 sdr->validator = sdr->sockfd ^ ValidatorBits;
762 sdr->op = op;
763 sdr->max_index = 0;
764 sdr->logcounter = 0;
765 sdr->moreptr = NULL;
766 sdr->uid.u32[0] = 0;
767 sdr->uid.u32[1] = 0;
768 sdr->ProcessReply = ProcessReply;
769 sdr->AppCallback = AppCallback;
770 sdr->AppContext = AppContext;
771 sdr->rec = NULL;
772 #if _DNS_SD_LIBDISPATCH
773 sdr->disp_source = NULL;
774 sdr->disp_queue = NULL;
775 #endif
776 sdr->kacontext = NULL;
777 #ifdef MEMORY_OBJECT_TRACKING
778 extern int sdref_created;
779 sdref_created++;
780 #endif
781
782 if (flags & kDNSServiceFlagsShareConnection)
783 {
784 DNSServiceOp **p = &(*ref)->next; // Append ourselves to end of primary's list
785 while (*p)
786 p = &(*p)->next;
787 *p = sdr;
788 // Preincrement counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
789 if (++(*ref)->uid.u32[0] == 0)
790 ++(*ref)->uid.u32[1]; // In parent DNSServiceOp increment UID counter
791 sdr->primary = *ref; // Set our primary pointer
792 sdr->sockfd = (*ref)->sockfd; // Inherit primary's socket
793 sdr->validator = (*ref)->validator;
794 sdr->uid = (*ref)->uid;
795 //printf("ConnectToServer sharing socket %d\n", sdr->sockfd);
796 }
797 else
798 {
799 #ifdef SO_NOSIGPIPE
800 const unsigned int optval = 1;
801 #endif
802 #ifndef USE_TCP_LOOPBACK
803 char* uds_serverpath = getenv(MDNS_UDS_SERVERPATH_ENVVAR);
804 if (uds_serverpath == NULL)
805 uds_serverpath = MDNS_UDS_SERVERPATH;
806 else if (strlen(uds_serverpath) >= MAX_CTLPATH)
807 {
808 uds_serverpath = MDNS_UDS_SERVERPATH;
809 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: using default path since env len is invalid");
810 }
811 #endif
812 *ref = NULL;
813 sdr->sockfd = socket(AF_DNSSD, SOCK_STREAM, 0);
814 sdr->validator = sdr->sockfd ^ ValidatorBits;
815 if (!dnssd_SocketValid(sdr->sockfd))
816 {
817 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: socket failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
818 FreeDNSServiceOp(sdr);
819 return kDNSServiceErr_NoMemory;
820 }
821 #if !defined(_WIN32)
822 int fcntl_flags = fcntl(sdr->sockfd, F_GETFD);
823 if (fcntl_flags != -1)
824 {
825 fcntl_flags |= FD_CLOEXEC;
826 int ret = fcntl(sdr->sockfd, F_SETFD, fcntl_flags);
827 if (ret == -1)
828 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to set FD_CLOEXEC on socket %d %s",
829 dnssd_errno, dnssd_strerror(dnssd_errno));
830 }
831 else
832 {
833 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to get the file descriptor flags of socket %d %s",
834 dnssd_errno, dnssd_strerror(dnssd_errno));
835 }
836 #endif // !defined(_WIN32)
837 #ifdef SO_NOSIGPIPE
838 // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
839 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
840 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_NOSIGPIPE failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
841 #endif
842 #if defined(USE_TCP_LOOPBACK)
843 saddr.sin_family = AF_INET;
844 saddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
845 saddr.sin_port = IsSystemServiceDisabled() ? htons(MDNS_TCP_SERVERPORT_CENTENNIAL) : htons(MDNS_TCP_SERVERPORT);
846 #else
847 saddr.sun_family = AF_LOCAL;
848 SetUDSPath(&saddr, uds_serverpath);
849 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
850 {
851 int defunct = 1;
852 if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
853 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
854 }
855 #endif
856 #endif
857
858 #if defined(_WIN32)
859 while (1)
860 {
861 #ifdef WIN32_CENTENNIAL
862 char port[128];
863 // Access to the process environment block is thread-safe
864 if (GetEnvironmentVariableA("MDNS_TCP_SERVERPORT_CENTENNIAL", port, sizeof(port)))
865 {
866 saddr.sin_port = htons((u_short)atoi(port));
867 }
868 #endif
869 int err = connect(sdr->sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
870 if (!err)
871 break; // If we succeeded, return sdr
872
873 // If we failed, then it may be because the daemon is still launching.
874 // This can happen for processes that launch early in the boot process, while the
875 // daemon is still coming up. Rather than fail here, we wait 1 sec and try again.
876 // If, after DNSSD_CLIENT_MAXTRIES, we still can't connect to the daemon,
877 // then we give up and return a failure code.
878 if (++NumTries < DNSSD_CLIENT_MAXTRIES)
879 {
880 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
881 sleep(1); // Sleep a bit, then try again
882 }
883 else
884 {
885 #if !defined(USE_TCP_LOOPBACK)
886 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
887 uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
888 #endif
889 dnssd_close(sdr->sockfd);
890 FreeDNSServiceOp(sdr);
891 return kDNSServiceErr_ServiceNotRunning;
892 }
893 }
894 #else
895 int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
896 if (err)
897 {
898 #if !defined(USE_TCP_LOOPBACK)
899 syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
900 uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
901 #endif
902 dnssd_close(sdr->sockfd);
903 FreeDNSServiceOp(sdr);
904 return kDNSServiceErr_ServiceNotRunning;
905 }
906 #endif
907 }
908
909 *ref = sdr;
910 return kDNSServiceErr_NoError;
911 }
912
913 #define deliver_request_bailout(MSG) \
914 do { syslog(LOG_WARNING, "dnssd_clientstub deliver_request: %s failed %d (%s)", (MSG), dnssd_errno, dnssd_strerror(dnssd_errno)); goto cleanup; } while(0)
915
deliver_request(ipc_msg_hdr * hdr,DNSServiceOp * sdr)916 static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
917 {
918 uint32_t datalen;
919 dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
920 DNSServiceErrorType err = kDNSServiceErr_Unknown; // Default for the "goto cleanup" cases
921 int MakeSeparateReturnSocket;
922 int ioresult;
923 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
924 char *data;
925 #endif
926
927 if (!hdr)
928 {
929 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: !hdr");
930 return kDNSServiceErr_Unknown;
931 }
932
933 datalen = hdr->datalen; // We take a copy here because we're going to convert hdr->datalen to network byte order
934 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
935 data = (char *)hdr + sizeof(ipc_msg_hdr);
936 #endif
937
938 // Note: need to check hdr->op, not sdr->op.
939 // hdr->op contains the code for the specific operation we're currently doing, whereas sdr->op
940 // contains the original parent DNSServiceOp (e.g. for an add_record_request, hdr->op will be
941 // add_record_request but the parent sdr->op will be connection_request or reg_service_request)
942 MakeSeparateReturnSocket = (sdr->primary ||
943 hdr->op == reg_record_request || hdr->op == add_record_request || hdr->op == update_record_request || hdr->op == remove_record_request);
944
945 if (!DNSServiceRefValid(sdr))
946 {
947 if (hdr)
948 mdns_free(hdr);
949 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: invalid DNSServiceRef %p %08X %08X", sdr, sdr->sockfd, sdr->validator);
950 return kDNSServiceErr_BadReference;
951 }
952
953 if (MakeSeparateReturnSocket)
954 {
955 #if defined(USE_TCP_LOOPBACK)
956 {
957 union { uint16_t s; u_char b[2]; } port;
958 dnssd_sockaddr_t caddr;
959 dnssd_socklen_t len = (dnssd_socklen_t) sizeof(caddr);
960 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
961 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("TCP socket");
962
963 caddr.sin_family = AF_INET;
964 caddr.sin_port = 0;
965 caddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
966 if (bind(listenfd, (struct sockaddr*) &caddr, sizeof(caddr)) < 0) deliver_request_bailout("TCP bind");
967 if (getsockname(listenfd, (struct sockaddr*) &caddr, &len) < 0) deliver_request_bailout("TCP getsockname");
968 if (listen(listenfd, 1) < 0) deliver_request_bailout("TCP listen");
969 port.s = caddr.sin_port;
970 data[0] = port.b[0]; // don't switch the byte order, as the
971 data[1] = port.b[1]; // daemon expects it in network byte order
972 }
973 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
974 {
975 mode_t mask;
976 int bindresult;
977 dnssd_sockaddr_t caddr;
978 listenfd = socket(AF_DNSSD, SOCK_STREAM, 0);
979 if (!dnssd_SocketValid(listenfd)) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET socket");
980
981 caddr.sun_family = AF_LOCAL;
982 // According to Stevens (section 3.2), there is no portable way to
983 // determine whether sa_len is defined on a particular platform.
984 #ifndef NOT_HAVE_SA_LEN
985 caddr.sun_len = sizeof(struct sockaddr_un);
986 #endif
987 SetUDSPath(&caddr, data);
988 mask = umask(0);
989 bindresult = bind(listenfd, (struct sockaddr *)&caddr, sizeof(caddr));
990 umask(mask);
991 if (bindresult < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET bind");
992 if (listen(listenfd, 1) < 0) deliver_request_bailout("USE_NAMED_ERROR_RETURN_SOCKET listen");
993 }
994 #else
995 {
996 dnssd_sock_t sp[2];
997 if (socketpair(AF_DNSSD, SOCK_STREAM, 0, sp) < 0) deliver_request_bailout("socketpair");
998 else
999 {
1000 errsd = sp[0]; // We'll read our four-byte error code from sp[0]
1001 listenfd = sp[1]; // We'll send sp[1] to the daemon
1002 #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
1003 {
1004 int defunct = 1;
1005 if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
1006 syslog(LOG_WARNING, "dnssd_clientstub deliver_request: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
1007 }
1008 #endif
1009 }
1010 }
1011 #endif
1012 }
1013
1014 #if !defined(USE_TCP_LOOPBACK) && !defined(USE_NAMED_ERROR_RETURN_SOCKET)
1015 // If we're going to make a separate error return socket, and pass it to the daemon
1016 // using sendmsg, then we'll hold back one data byte to go with it.
1017 // On some versions of Unix (including Leopard) sending a control message without
1018 // any associated data does not work reliably -- e.g. one particular issue we ran
1019 // into is that if the receiving program is in a kqueue loop waiting to be notified
1020 // of the received message, it doesn't get woken up when the control message arrives.
1021 if (MakeSeparateReturnSocket)
1022 {
1023 datalen--;
1024 }
1025 #endif
1026
1027 // At this point, our listening socket is set up and waiting, if necessary, for the daemon to connect back to
1028 ConvertHeaderBytes(hdr);
1029 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %lu bytes", (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
1030 //if (MakeSeparateReturnSocket) syslog(LOG_WARNING, "dnssd_clientstub deliver_request name is %s", data);
1031 #if defined(TEST_SENDING_ONE_BYTE_AT_A_TIME) && TEST_SENDING_ONE_BYTE_AT_A_TIME
1032 unsigned int i;
1033 for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
1034 {
1035 syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
1036 ioresult = write_all(sdr->sockfd, ((char *)hdr)+i, 1);
1037 if (ioresult < write_all_success)
1038 {
1039 syslog(LOG_WARNING, "dnssd_clientstub deliver_request write_all (byte %u) failed", i);
1040 err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
1041 goto cleanup;
1042 }
1043 usleep(10000);
1044 }
1045 #else
1046 ioresult = write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr));
1047 if (ioresult < write_all_success)
1048 {
1049 // write_all already prints an error message if there is an error writing to
1050 // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
1051 // in the case of DEFUNCT sockets
1052 syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
1053 sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
1054 err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
1055 goto cleanup;
1056 }
1057 #endif
1058
1059 if (!MakeSeparateReturnSocket)
1060 errsd = sdr->sockfd;
1061 if (MakeSeparateReturnSocket)
1062 {
1063 #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
1064 // At this point we may wait in accept for a few milliseconds waiting for the daemon to connect back to us,
1065 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
1066 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
1067 dnssd_sockaddr_t daddr;
1068 dnssd_socklen_t len = sizeof(daddr);
1069 if ((err = set_waitlimit(listenfd, DNSSD_CLIENT_TIMEOUT)) != kDNSServiceErr_NoError)
1070 goto cleanup;
1071 errsd = accept(listenfd, (struct sockaddr *)&daddr, &len);
1072 if (!dnssd_SocketValid(errsd))
1073 deliver_request_bailout("accept");
1074 #else
1075
1076 struct iovec vec = { ((char *)hdr) + sizeof(ipc_msg_hdr) + datalen, 1 }; // Send the last byte along with the SCM_RIGHTS
1077 struct msghdr msg;
1078 struct cmsghdr *cmsg;
1079 char cbuf[CMSG_SPACE(4 * sizeof(dnssd_sock_t))];
1080
1081 msg.msg_name = 0;
1082 msg.msg_namelen = 0;
1083 msg.msg_iov = &vec;
1084 msg.msg_iovlen = 1;
1085 msg.msg_flags = 0;
1086 msg.msg_control = cbuf;
1087 msg.msg_controllen = CMSG_LEN(sizeof(dnssd_sock_t));
1088
1089 cmsg = CMSG_FIRSTHDR(&msg);
1090 cmsg->cmsg_len = CMSG_LEN(sizeof(dnssd_sock_t));
1091 cmsg->cmsg_level = SOL_SOCKET;
1092 cmsg->cmsg_type = SCM_RIGHTS;
1093 *((dnssd_sock_t *)CMSG_DATA(cmsg)) = listenfd;
1094
1095 #if defined(TEST_KQUEUE_CONTROL_MESSAGE_BUG) && TEST_KQUEUE_CONTROL_MESSAGE_BUG
1096 sleep(1);
1097 #endif
1098
1099 #if DEBUG_64BIT_SCM_RIGHTS
1100 syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
1101 errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
1102 sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
1103 CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
1104 (long)((char*)CMSG_DATA(cmsg) + 4 - cbuf));
1105 #endif // DEBUG_64BIT_SCM_RIGHTS
1106
1107 if (sendmsg(sdr->sockfd, &msg, 0) < 0)
1108 {
1109 syslog(LOG_WARNING, "dnssd_clientstub deliver_request ERROR: sendmsg failed read sd=%d write sd=%d errno %d (%s)",
1110 errsd, listenfd, dnssd_errno, dnssd_strerror(dnssd_errno));
1111 err = kDNSServiceErr_Incompatible;
1112 goto cleanup;
1113 }
1114
1115 #if DEBUG_64BIT_SCM_RIGHTS
1116 syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
1117 #endif // DEBUG_64BIT_SCM_RIGHTS
1118
1119 #endif
1120 // Close our end of the socketpair *before* calling read_all() to get the four-byte error code.
1121 // Otherwise, if the daemon closes our socket (or crashes), we will have to wait for a timeout
1122 // in read_all() because the socket is not closed (we still have an open reference to it)
1123 dnssd_close(listenfd);
1124 listenfd = dnssd_InvalidSocket; // Make sure we don't close it a second time in the cleanup handling below
1125 }
1126
1127 // At this point we may wait in read_all for a few milliseconds waiting for the daemon to send us the error code,
1128 // but that's okay -- the daemon should not take more than a few milliseconds to respond.
1129 // set_waitlimit() ensures we do not block indefinitely just in case something is wrong
1130 if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
1131 {
1132 ioresult = read_all(errsd, (uint8_t *)&err, (int)sizeof(err));
1133 if (ioresult < read_all_success)
1134 err = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
1135 else
1136 err = ntohl(err);
1137 }
1138 //syslog(LOG_WARNING, "dnssd_clientstub deliver_request: retrieved error code %d", err);
1139
1140 cleanup:
1141 if (MakeSeparateReturnSocket)
1142 {
1143 if (dnssd_SocketValid(listenfd)) dnssd_close(listenfd);
1144 if (dnssd_SocketValid(errsd)) dnssd_close(errsd);
1145 #if defined(USE_NAMED_ERROR_RETURN_SOCKET)
1146 // syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removing UDS: %s", data);
1147 if (unlink(data) != 0)
1148 syslog(LOG_WARNING, "dnssd_clientstub WARNING: unlink(\"%s\") failed errno %d (%s)", data, dnssd_errno, dnssd_strerror(dnssd_errno));
1149 // else syslog(LOG_WARNING, "dnssd_clientstub deliver_request: removed UDS: %s", data);
1150 #endif
1151 }
1152
1153 mdns_free(hdr);
1154 return err;
1155 }
1156
DNSServiceRefSockFD(DNSServiceRef sdRef)1157 dnssd_sock_t DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
1158 {
1159 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with NULL DNSServiceRef"); return dnssd_InvalidSocket; }
1160
1161 if (!DNSServiceRefValid(sdRef))
1162 {
1163 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD called with invalid DNSServiceRef %p %08X %08X",
1164 sdRef, sdRef->sockfd, sdRef->validator);
1165 return dnssd_InvalidSocket;
1166 }
1167
1168 if (sdRef->primary)
1169 {
1170 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefSockFD undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
1171 return dnssd_InvalidSocket;
1172 }
1173
1174 return sdRef->sockfd;
1175 }
1176
1177 #if _DNS_SD_LIBDISPATCH
CallbackWithError(DNSServiceRef sdRef,DNSServiceErrorType error)1178 static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
1179 {
1180 DNSServiceOp *sdr = sdRef;
1181 DNSServiceOp *sdrNext;
1182 DNSRecord *rec;
1183 DNSRecord *recnext;
1184 int morebytes;
1185
1186 while (sdr)
1187 {
1188 // We can't touch the sdr after the callback as it can be deallocated in the callback
1189 sdrNext = sdr->next;
1190 morebytes = 1;
1191 sdr->moreptr = &morebytes;
1192 switch (sdr->op)
1193 {
1194 case resolve_request:
1195 if (sdr->AppCallback) ((DNSServiceResolveReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, sdr->AppContext);
1196 break;
1197 case query_request:
1198 if (sdr->AppCallback) ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
1199 break;
1200 case addrinfo_request:
1201 if (sdr->AppCallback) ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0, sdr->AppContext);
1202 break;
1203 case browse_request:
1204 if (sdr->AppCallback) ((DNSServiceBrowseReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL, sdr->AppContext);
1205 break;
1206 case reg_service_request:
1207 if (sdr->AppCallback) ((DNSServiceRegisterReply) sdr->AppCallback)(sdr, 0, error, NULL, 0, NULL, sdr->AppContext);
1208 break;
1209 case enumeration_request:
1210 if (sdr->AppCallback) ((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL, sdr->AppContext);
1211 break;
1212 case connection_request:
1213 case connection_delegate_request:
1214 // This means Register Record, walk the list of DNSRecords to do the callback
1215 rec = sdr->rec;
1216 while (rec)
1217 {
1218 recnext = rec->recnext;
1219 if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
1220 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
1221 // Detect that and return early
1222 if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:Record: CallbackwithError morebytes zero"); return; }
1223 rec = recnext;
1224 }
1225 break;
1226 case port_mapping_request:
1227 if (sdr->AppCallback) ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
1228 break;
1229 default:
1230 syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
1231 }
1232 // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. As the sdRef
1233 // (and its subordinates) have been freed, we should not proceed further. Note that when we
1234 // call the callback with a subordinate sdRef the application can call DNSServiceRefDeallocate
1235 // on the main sdRef and DNSServiceRefDeallocate handles this case by walking all the sdRefs and
1236 // clears the moreptr so that we can terminate here.
1237 //
1238 // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
1239 // we don't access the stack variable after we return from this function.
1240 if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return; }
1241 else {sdr->moreptr = NULL;}
1242 sdr = sdrNext;
1243 }
1244 }
1245 #endif // _DNS_SD_LIBDISPATCH
1246
1247 // Handle reply from server, calling application client callback. If there is no reply
1248 // from the daemon on the socket contained in sdRef, the call will block.
DNSServiceProcessResult(DNSServiceRef sdRef)1249 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
1250 {
1251 int morebytes = 0;
1252 int ioresult;
1253 DNSServiceErrorType error;
1254
1255 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
1256
1257 if (!DNSServiceRefValid(sdRef))
1258 {
1259 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1260 return kDNSServiceErr_BadReference;
1261 }
1262
1263 if (sdRef->primary)
1264 {
1265 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult undefined for kDNSServiceFlagsShareConnection subordinate DNSServiceRef %p", sdRef);
1266 return kDNSServiceErr_BadReference;
1267 }
1268
1269 if (!sdRef->ProcessReply)
1270 {
1271 static int num_logs = 0;
1272 if (num_logs < 10) syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function");
1273 if (num_logs < 1000) num_logs++;else sleep(1);
1274 return kDNSServiceErr_BadReference;
1275 }
1276
1277 do
1278 {
1279 CallbackHeader cbh;
1280 uint8_t *data;
1281
1282 // return NoError on EWOULDBLOCK. This will handle the case
1283 // where a non-blocking socket is told there is data, but it was a false positive.
1284 // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
1285 // Note: If we want to properly support using non-blocking sockets in the future
1286 ioresult = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
1287 if (ioresult == read_all_fail || ioresult == read_all_defunct)
1288 {
1289 error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
1290
1291 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1292 // in the callback.
1293 sdRef->ProcessReply = NULL;
1294 #if _DNS_SD_LIBDISPATCH
1295 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1296 // is not called by the application and hence need to communicate the error. Cancel the
1297 // source so that we don't get any more events
1298 // Note: read_all fails if we could not read from the daemon which can happen if the
1299 // daemon dies or the file descriptor is disconnected (defunct).
1300 if (sdRef->disp_source)
1301 {
1302 dispatch_source_cancel(sdRef->disp_source);
1303 MDNS_DISPOSE_DISPATCH(sdRef->disp_source);
1304 CallbackWithError(sdRef, error);
1305 }
1306 #endif
1307 // Don't touch sdRef anymore as it might have been deallocated
1308 return error;
1309 }
1310 else if (ioresult == read_all_wouldblock)
1311 {
1312 if (morebytes && sdRef->logcounter < 100)
1313 {
1314 sdRef->logcounter++;
1315 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult error: select indicated data was waiting but read_all returned EWOULDBLOCK");
1316 }
1317 return kDNSServiceErr_NoError;
1318 }
1319
1320 ConvertHeaderBytes(&cbh.ipc_hdr);
1321 if (cbh.ipc_hdr.version != VERSION)
1322 {
1323 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult daemon version %d does not match client version %d", cbh.ipc_hdr.version, VERSION);
1324 sdRef->ProcessReply = NULL;
1325 return kDNSServiceErr_Incompatible;
1326 }
1327
1328 data = mdns_malloc(cbh.ipc_hdr.datalen);
1329 if (!data) return kDNSServiceErr_NoMemory;
1330 ioresult = read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen);
1331 if (ioresult < read_all_success) // On error, read_all will write a message to syslog for us
1332 {
1333 error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
1334
1335 // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
1336 // in the callback.
1337 sdRef->ProcessReply = NULL;
1338 #if _DNS_SD_LIBDISPATCH
1339 // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
1340 // is not called by the application and hence need to communicate the error. Cancel the
1341 // source so that we don't get any more events
1342 if (sdRef->disp_source)
1343 {
1344 dispatch_source_cancel(sdRef->disp_source);
1345 MDNS_DISPOSE_DISPATCH(sdRef->disp_source);
1346 CallbackWithError(sdRef, error);
1347 }
1348 #endif
1349 // Don't touch sdRef anymore as it might have been deallocated
1350 mdns_free(data);
1351 return error;
1352 }
1353 else
1354 {
1355 const uint8_t *ptr = data;
1356 cbh.cb_flags = get_flags (&ptr, data + cbh.ipc_hdr.datalen);
1357 cbh.cb_interface = get_uint32 (&ptr, data + cbh.ipc_hdr.datalen);
1358 cbh.cb_err = get_error_code(&ptr, data + cbh.ipc_hdr.datalen);
1359
1360 // CAUTION: We have to handle the case where the client calls DNSServiceRefDeallocate from within the callback function.
1361 // To do this we set moreptr to point to morebytes. If the client does call DNSServiceRefDeallocate(),
1362 // then that routine will clear morebytes for us, and cause us to exit our loop.
1363 morebytes = more_bytes(sdRef->sockfd);
1364 if (morebytes)
1365 {
1366 cbh.cb_flags |= kDNSServiceFlagsMoreComing;
1367 sdRef->moreptr = &morebytes;
1368 }
1369 if (ptr) sdRef->ProcessReply(sdRef, &cbh, ptr, data + cbh.ipc_hdr.datalen);
1370 // Careful code here:
1371 // If morebytes is non-zero, that means we set sdRef->moreptr above, and the operation was not
1372 // cancelled out from under us, so now we need to clear sdRef->moreptr so we don't leave a stray
1373 // dangling pointer pointing to a long-gone stack variable.
1374 // If morebytes is zero, then one of two thing happened:
1375 // (a) morebytes was 0 above, so we didn't set sdRef->moreptr, so we don't need to clear it
1376 // (b) morebytes was 1 above, and we set sdRef->moreptr, but the operation was cancelled (with DNSServiceRefDeallocate()),
1377 // so we MUST NOT try to dereference our stale sdRef pointer.
1378 if (morebytes) sdRef->moreptr = NULL;
1379 }
1380 mdns_free(data);
1381 } while (morebytes);
1382
1383 return kDNSServiceErr_NoError;
1384 }
1385
DNSServiceRefDeallocate(DNSServiceRef sdRef)1386 void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
1387 {
1388 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef"); return; }
1389
1390 if (!DNSServiceRefValid(sdRef)) // Also verifies dnssd_SocketValid(sdRef->sockfd) for us too
1391 {
1392 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRefDeallocate called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
1393 return;
1394 }
1395
1396 // If we're in the middle of a DNSServiceProcessResult() invocation for this DNSServiceRef, clear its morebytes flag to break it out of its while loop
1397 if (sdRef->moreptr) *(sdRef->moreptr) = 0;
1398
1399 if (sdRef->primary) // If this is a subordinate DNSServiceOp, just send a 'stop' command
1400 {
1401 DNSServiceOp **p = &sdRef->primary->next;
1402 while (*p && *p != sdRef) p = &(*p)->next;
1403 if (*p)
1404 {
1405 uint8_t *ptr;
1406 size_t len = 0;
1407 ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
1408 if (hdr)
1409 {
1410 ConvertHeaderBytes(hdr);
1411 write_all(sdRef->sockfd, (char *)hdr, len);
1412 mdns_free(hdr);
1413 }
1414 *p = sdRef->next;
1415 FreeDNSServiceOp(sdRef);
1416 }
1417 }
1418 else // else, make sure to terminate all subordinates as well
1419 {
1420 #if _DNS_SD_LIBDISPATCH
1421 // The cancel handler will close the fd if a dispatch source has been set
1422 if (sdRef->disp_source)
1423 {
1424 // By setting the ProcessReply to NULL, we make sure that we never call
1425 // the application callbacks ever, after returning from this function. We
1426 // assume that DNSServiceRefDeallocate is called from the serial queue
1427 // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
1428 // should cancel all the blocks on the queue and hence there should be no more
1429 // callbacks when we return from this function. Setting ProcessReply to NULL
1430 // provides extra protection.
1431 sdRef->ProcessReply = NULL;
1432 shutdown(sdRef->sockfd, SHUT_WR);
1433 dispatch_source_cancel(sdRef->disp_source);
1434 MDNS_DISPOSE_DISPATCH(sdRef->disp_source);
1435 }
1436 // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
1437 // when the source was cancelled, the fd was closed in the handler. Currently the source
1438 // is cancelled only when the mDNSResponder daemon dies
1439 else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
1440 #else
1441 dnssd_close(sdRef->sockfd);
1442 #endif
1443 // Free DNSRecords added in DNSRegisterRecord if they have not
1444 // been freed in DNSRemoveRecord
1445 while (sdRef)
1446 {
1447 DNSServiceOp *p = sdRef;
1448 sdRef = sdRef->next;
1449 // When there is an error reading from the daemon e.g., bad fd, CallbackWithError
1450 // is called which sets moreptr. It might set the moreptr on a subordinate sdRef
1451 // but the application might call DNSServiceRefDeallocate with the main sdRef from
1452 // the callback. Hence, when we loop through the subordinate sdRefs, we need
1453 // to clear the moreptr so that CallbackWithError can terminate itself instead of
1454 // walking through the freed sdRefs.
1455 if (p->moreptr) *(p->moreptr) = 0;
1456 FreeDNSServiceOp(p);
1457 }
1458 }
1459 }
1460
DNSServiceGetProperty(const char * property,void * result,uint32_t * size)1461 DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *result, uint32_t *size)
1462 {
1463 DNSServiceErrorType err;
1464 uint8_t *ptr;
1465 size_t len;
1466 ipc_msg_hdr *hdr;
1467 DNSServiceOp *tmp;
1468 uint32_t actualsize;
1469 int ioresult;
1470
1471 if (!property || !result || !size)
1472 return kDNSServiceErr_BadParam;
1473
1474 len = strlen(property) + 1;
1475 err = ConnectToServer(&tmp, 0, getproperty_request, NULL, NULL, NULL);
1476 if (err) return err;
1477
1478 hdr = create_hdr(getproperty_request, &len, &ptr, 0, tmp);
1479 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1480
1481 put_string(property, &ptr);
1482 err = deliver_request(hdr, tmp); // Will free hdr for us
1483 if (err) { DNSServiceRefDeallocate(tmp); return err; }
1484
1485 ioresult = read_all(tmp->sockfd, (uint8_t *)&actualsize, sizeof(actualsize));
1486 if (ioresult < read_all_success)
1487 { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
1488
1489 actualsize = ntohl(actualsize);
1490 ioresult = read_all(tmp->sockfd, (uint8_t *)result, actualsize < *size ? actualsize : *size);
1491 if (ioresult < read_all_success)
1492 { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
1493 DNSServiceRefDeallocate(tmp);
1494
1495 // Swap version result back to local process byte order
1496 if (!strcmp(property, kDNSServiceProperty_DaemonVersion) && *size >= 4)
1497 *(uint32_t*)result = ntohl(*(uint32_t*)result);
1498
1499 *size = actualsize;
1500 return kDNSServiceErr_NoError;
1501 }
1502
DNSServiceGetPID(const uint16_t srcport,int32_t * pid)1503 DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *pid)
1504 {
1505 uint8_t *ptr;
1506 ipc_msg_hdr *hdr;
1507 DNSServiceOp *tmp = NULL;
1508 size_t len = sizeof(int32_t);
1509 int ioresult;
1510
1511 DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
1512 if (err) return err;
1513
1514 hdr = create_hdr(getpid_request, &len, &ptr, 0, tmp);
1515 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1516
1517 put_uint16(srcport, &ptr);
1518 err = deliver_request(hdr, tmp); // Will free hdr for us
1519 if (err) { DNSServiceRefDeallocate(tmp); return err; }
1520
1521 ioresult = read_all(tmp->sockfd, (uint8_t *)pid, sizeof(int32_t));
1522 if (ioresult < read_all_success)
1523 { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
1524
1525 DNSServiceRefDeallocate(tmp);
1526 return kDNSServiceErr_NoError;
1527 }
1528
handle_resolve_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)1529 static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
1530 {
1531 char fullname[kDNSServiceMaxDomainName];
1532 char target[kDNSServiceMaxDomainName];
1533 uint16_t txtlen;
1534 union { uint16_t s; u_char b[2]; } port;
1535 const unsigned char *txtrecord;
1536
1537 get_string(&data, end, fullname, kDNSServiceMaxDomainName);
1538 get_string(&data, end, target, kDNSServiceMaxDomainName);
1539 if (!data || data + 2 > end) goto fail;
1540
1541 port.b[0] = *data++;
1542 port.b[1] = *data++;
1543 txtlen = get_uint16(&data, end);
1544 txtrecord = (const unsigned char *)get_rdata(&data, end, txtlen);
1545
1546 if (!data) goto fail;
1547 ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
1548 return;
1549 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1550 fail:
1551 syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
1552 }
1553
DNSServiceResolve(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,DNSServiceResolveReply callBack,void * context)1554 DNSServiceErrorType DNSSD_API DNSServiceResolve
1555 (
1556 DNSServiceRef *sdRef,
1557 DNSServiceFlags flags,
1558 uint32_t interfaceIndex,
1559 const char *name,
1560 const char *regtype,
1561 const char *domain,
1562 DNSServiceResolveReply callBack,
1563 void *context
1564 )
1565 {
1566 return DNSServiceResolveInternal(sdRef, flags, interfaceIndex, name, regtype, domain, NULL, callBack, context);
1567 }
1568
DNSServiceResolveInternal(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const DNSServiceAttribute * attr,DNSServiceResolveReply callBack,void * context)1569 DNSServiceErrorType DNSServiceResolveInternal
1570 (
1571 DNSServiceRef *sdRef,
1572 DNSServiceFlags flags,
1573 uint32_t interfaceIndex,
1574 const char *name,
1575 const char *regtype,
1576 const char *domain,
1577 const DNSServiceAttribute *attr,
1578 DNSServiceResolveReply callBack,
1579 void *context
1580 )
1581 {
1582 uint8_t *ptr;
1583 size_t len;
1584 ipc_msg_hdr *hdr;
1585 DNSServiceErrorType err;
1586
1587 if (!sdRef || !name || !regtype || !domain || !callBack) return kDNSServiceErr_BadParam;
1588
1589 // Need a real InterfaceID for WakeOnResolve
1590 if ((flags & kDNSServiceFlagsWakeOnResolve) != 0 &&
1591 ((interfaceIndex == kDNSServiceInterfaceIndexAny) ||
1592 (interfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
1593 (interfaceIndex == kDNSServiceInterfaceIndexUnicast) ||
1594 (interfaceIndex == kDNSServiceInterfaceIndexP2P) ||
1595 (interfaceIndex == kDNSServiceInterfaceIndexBLE)))
1596 {
1597 return kDNSServiceErr_BadParam;
1598 }
1599
1600 err = ConnectToServer(sdRef, flags, resolve_request, handle_resolve_response, (void *)callBack, context);
1601 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1602
1603 // Calculate total message length
1604 len = sizeof(flags);
1605 len += sizeof(interfaceIndex);
1606 len += strlen(name) + 1;
1607 len += strlen(regtype) + 1;
1608 len += strlen(domain) + 1;
1609
1610 (void)attr;
1611
1612 hdr = create_hdr(resolve_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1613 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1614
1615 put_flags(flags, &ptr);
1616 put_uint32(interfaceIndex, &ptr);
1617 put_string(name, &ptr);
1618 put_string(regtype, &ptr);
1619 put_string(domain, &ptr);
1620
1621 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1622 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1623 {
1624 err = kDNSServiceErr_NoError;
1625 }
1626 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1627 return err;
1628 }
1629
handle_query_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)1630 static void handle_query_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
1631 {
1632 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1633 {
1634 return;
1635 }
1636 uint32_t ttl;
1637 char name[kDNSServiceMaxDomainName];
1638 uint16_t rrtype, rrclass, rdlen;
1639 const uint8_t *rdata;
1640
1641 get_string(&data, end, name, kDNSServiceMaxDomainName);
1642 rrtype = get_uint16(&data, end);
1643 rrclass = get_uint16(&data, end);
1644 rdlen = get_uint16(&data, end);
1645 rdata = get_rdata(&data, end, rdlen);
1646 ttl = get_uint32(&data, end);
1647
1648 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_query_response: error reading result from daemon");
1649 else ((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, name, rrtype, rrclass, rdlen, rdata, ttl, sdr->AppContext);
1650 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1651 }
1652
DNSServiceQueryRecord(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,uint16_t rrtype,uint16_t rrclass,DNSServiceQueryRecordReply callBack,void * context)1653 DNSServiceErrorType DNSSD_API DNSServiceQueryRecord
1654 (
1655 DNSServiceRef *sdRef,
1656 DNSServiceFlags flags,
1657 uint32_t interfaceIndex,
1658 const char *name,
1659 uint16_t rrtype,
1660 uint16_t rrclass,
1661 DNSServiceQueryRecordReply callBack,
1662 void *context
1663 )
1664 {
1665 return DNSServiceQueryRecordInternal(sdRef, flags, interfaceIndex, name, rrtype, rrclass, NULL, callBack, context);
1666 }
1667
DNSServiceQueryRecordInternal(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,uint16_t rrtype,uint16_t rrclass,const DNSServiceAttribute * attr,DNSServiceQueryRecordReply callBack,void * context)1668 DNSServiceErrorType DNSServiceQueryRecordInternal
1669 (
1670 DNSServiceRef *sdRef,
1671 DNSServiceFlags flags,
1672 uint32_t interfaceIndex,
1673 const char *name,
1674 uint16_t rrtype,
1675 uint16_t rrclass,
1676 const DNSServiceAttribute *attr,
1677 DNSServiceQueryRecordReply callBack,
1678 void *context
1679 )
1680 {
1681 uint8_t *ptr;
1682 size_t len;
1683 ipc_msg_hdr *hdr;
1684 DNSServiceErrorType err;
1685 // NULL name handled below.
1686 if (!sdRef || !callBack) return kDNSServiceErr_BadParam;
1687
1688 err = ConnectToServer(sdRef, flags, query_request, handle_query_response, (void *)callBack, context);
1689 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1690
1691 if (!name) name = "\0";
1692
1693 // Calculate total message length
1694 len = sizeof(flags);
1695 len += sizeof(uint32_t); // interfaceIndex
1696 len += strlen(name) + 1;
1697 len += 2 * sizeof(uint16_t); // rrtype, rrclass
1698 (void)attr;
1699 hdr = create_hdr(query_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1700 if (!hdr)
1701 {
1702 DNSServiceRefDeallocate(*sdRef);
1703 *sdRef = NULL;
1704 return kDNSServiceErr_NoMemory;
1705 }
1706 put_flags(flags, &ptr);
1707 put_uint32(interfaceIndex, &ptr);
1708 put_string(name, &ptr);
1709 put_uint16(rrtype, &ptr);
1710 put_uint16(rrclass, &ptr);
1711 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1712 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1713 {
1714 err = kDNSServiceErr_NoError;
1715 }
1716 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1717 return err;
1718 }
1719
handle_addrinfo_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)1720 static void handle_addrinfo_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
1721 {
1722 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1723 {
1724 return;
1725 }
1726 char hostname[kDNSServiceMaxDomainName];
1727 uint16_t rrtype, rrclass, rdlen;
1728 const uint8_t *rdata;
1729 uint32_t ttl;
1730
1731 get_string(&data, end, hostname, kDNSServiceMaxDomainName);
1732 rrtype = get_uint16(&data, end);
1733 rrclass = get_uint16(&data, end);
1734 rdlen = get_uint16(&data, end);
1735 rdata = get_rdata (&data, end, rdlen);
1736 ttl = get_uint32(&data, end);
1737 (void)rrclass; // Unused
1738 // We only generate client callbacks for A and AAAA results (including NXDOMAIN results for
1739 // those types, if the client has requested those with the kDNSServiceFlagsReturnIntermediates).
1740 // Other result types, specifically CNAME referrals, are not communicated to the client, because
1741 // the DNSServiceGetAddrInfoReply interface doesn't have any meaningful way to communiate CNAME referrals.
1742 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_addrinfo_response: error reading result from daemon");
1743 else if (rrtype == kDNSServiceType_A || rrtype == kDNSServiceType_AAAA)
1744 {
1745 struct sockaddr_in sa4;
1746 struct sockaddr_in6 sa6;
1747 const struct sockaddr *const sa = (rrtype == kDNSServiceType_A) ? (struct sockaddr*)&sa4 : (struct sockaddr*)&sa6;
1748 if (rrtype == kDNSServiceType_A)
1749 {
1750 memset(&sa4, 0, sizeof(sa4));
1751 #ifndef NOT_HAVE_SA_LEN
1752 sa4.sin_len = sizeof(struct sockaddr_in);
1753 #endif
1754 sa4.sin_family = AF_INET;
1755 // sin_port = 0;
1756 if (!cbh->cb_err) memcpy(&sa4.sin_addr, rdata, rdlen);
1757 }
1758 else
1759 {
1760 memset(&sa6, 0, sizeof(sa6));
1761 #ifndef NOT_HAVE_SA_LEN
1762 sa6.sin6_len = sizeof(struct sockaddr_in6);
1763 #endif
1764 sa6.sin6_family = AF_INET6;
1765 // sin6_port = 0;
1766 // sin6_flowinfo = 0;
1767 // sin6_scope_id = 0;
1768 if (!cbh->cb_err)
1769 {
1770 memcpy(&sa6.sin6_addr, rdata, rdlen);
1771 if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) sa6.sin6_scope_id = cbh->cb_interface;
1772 }
1773 }
1774
1775 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, sa, ttl, sdr->AppContext);
1776 }
1777 else if (cbh->cb_err == kDNSServiceErr_PolicyDenied)
1778 {
1779 ((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, hostname, NULL, ttl, sdr->AppContext);
1780 }
1781 }
1782
DNSServiceGetAddrInfo(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,uint32_t protocol,const char * hostname,DNSServiceGetAddrInfoReply callBack,void * context)1783 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
1784 (
1785 DNSServiceRef *sdRef,
1786 DNSServiceFlags flags,
1787 uint32_t interfaceIndex,
1788 uint32_t protocol,
1789 const char *hostname,
1790 DNSServiceGetAddrInfoReply callBack,
1791 void *context /* may be NULL */
1792 )
1793 {
1794 return DNSServiceGetAddrInfoInternal(sdRef, flags, interfaceIndex, protocol, hostname, NULL, callBack, context);
1795 }
1796
DNSServiceGetAddrInfoInternal(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,uint32_t protocol,const char * hostname,const DNSServiceAttribute * attr,DNSServiceGetAddrInfoReply callBack,void * context)1797 DNSServiceErrorType DNSServiceGetAddrInfoInternal
1798 (
1799 DNSServiceRef *sdRef,
1800 DNSServiceFlags flags,
1801 uint32_t interfaceIndex,
1802 uint32_t protocol,
1803 const char *hostname,
1804 const DNSServiceAttribute *attr,
1805 DNSServiceGetAddrInfoReply callBack,
1806 void *context
1807 )
1808 {
1809 uint8_t *ptr;
1810 size_t len;
1811 ipc_msg_hdr *hdr;
1812 DNSServiceErrorType err;
1813
1814 if (!sdRef || !hostname || !callBack) return kDNSServiceErr_BadParam;
1815
1816 err = ConnectToServer(sdRef, flags, addrinfo_request, handle_addrinfo_response, (void *)callBack, context);
1817 if (err)
1818 {
1819 return err; // On error ConnectToServer leaves *sdRef set to NULL
1820 }
1821
1822 // Calculate total message length
1823 len = sizeof(flags);
1824 len += sizeof(uint32_t); // interfaceIndex
1825 len += sizeof(uint32_t); // protocol
1826 len += strlen(hostname) + 1;
1827 (void)attr;
1828 hdr = create_hdr(addrinfo_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1829 if (!hdr)
1830 {
1831 DNSServiceRefDeallocate(*sdRef);
1832 *sdRef = NULL;
1833 return kDNSServiceErr_NoMemory;
1834 }
1835 put_flags(flags, &ptr);
1836 put_uint32(interfaceIndex, &ptr);
1837 put_uint32(protocol, &ptr);
1838 put_string(hostname, &ptr);
1839 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1840 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1841 {
1842 err = kDNSServiceErr_NoError;
1843 }
1844 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1845 return err;
1846 }
1847
handle_browse_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)1848 static void handle_browse_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
1849 {
1850 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1851 {
1852 return;
1853 }
1854 char replyName[256], replyType[kDNSServiceMaxDomainName], replyDomain[kDNSServiceMaxDomainName];
1855 get_string(&data, end, replyName, 256);
1856 get_string(&data, end, replyType, kDNSServiceMaxDomainName);
1857 get_string(&data, end, replyDomain, kDNSServiceMaxDomainName);
1858 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_browse_response: error reading result from daemon");
1859 else ((DNSServiceBrowseReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, replyName, replyType, replyDomain, sdr->AppContext);
1860 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1861 }
1862
DNSServiceBrowse(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,DNSServiceBrowseReply callBack,void * context)1863 DNSServiceErrorType DNSSD_API DNSServiceBrowse
1864 (
1865 DNSServiceRef *sdRef,
1866 DNSServiceFlags flags,
1867 uint32_t interfaceIndex,
1868 const char *regtype,
1869 const char *domain,
1870 DNSServiceBrowseReply callBack,
1871 void *context
1872 )
1873 {
1874 return DNSServiceBrowseInternal(sdRef, flags, interfaceIndex, regtype, domain, NULL, callBack, context);
1875 }
1876
DNSServiceBrowseInternal(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * regtype,const char * domain,const DNSServiceAttribute * attr,DNSServiceBrowseReply callBack,void * context)1877 DNSServiceErrorType DNSServiceBrowseInternal
1878 (
1879 DNSServiceRef *sdRef,
1880 DNSServiceFlags flags,
1881 uint32_t interfaceIndex,
1882 const char *regtype,
1883 const char *domain,
1884 const DNSServiceAttribute *attr,
1885 DNSServiceBrowseReply callBack,
1886 void *context
1887 )
1888 {
1889 uint8_t *ptr;
1890 size_t len;
1891 ipc_msg_hdr *hdr;
1892 DNSServiceErrorType err;
1893
1894 // NULL domain handled below
1895 if (!sdRef || !regtype || !callBack) return kDNSServiceErr_BadParam;
1896
1897 err = ConnectToServer(sdRef, flags, browse_request, handle_browse_response, (void *)callBack, context);
1898 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
1899
1900 if (!domain) domain = "";
1901 len = sizeof(flags);
1902 len += sizeof(interfaceIndex);
1903 len += strlen(regtype) + 1;
1904 len += strlen(domain) + 1;
1905
1906 (void)attr;
1907
1908 hdr = create_hdr(browse_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
1909 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
1910
1911 put_flags(flags, &ptr);
1912 put_uint32(interfaceIndex, &ptr);
1913 put_string(regtype, &ptr);
1914 put_string(domain, &ptr);
1915
1916 err = deliver_request(hdr, *sdRef); // Will free hdr for us
1917 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
1918 {
1919 err = kDNSServiceErr_NoError;
1920 }
1921 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
1922 return err;
1923 }
1924
DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags,const char * domain)1925 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
1926 {
1927 DNSServiceErrorType err;
1928 DNSServiceOp *tmp;
1929 uint8_t *ptr;
1930 size_t len;
1931 ipc_msg_hdr *hdr;
1932
1933 if (!domain) return kDNSServiceErr_BadParam;
1934 len = sizeof(flags) + strlen(domain) + 1;
1935
1936 err = ConnectToServer(&tmp, 0, setdomain_request, NULL, NULL, NULL);
1937 if (err) return err;
1938
1939 hdr = create_hdr(setdomain_request, &len, &ptr, 0, tmp);
1940 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
1941
1942 put_flags(flags, &ptr);
1943 put_string(domain, &ptr);
1944 err = deliver_request(hdr, tmp); // Will free hdr for us
1945 DNSServiceRefDeallocate(tmp);
1946 return err;
1947 }
1948
handle_regservice_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)1949 static void handle_regservice_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
1950 {
1951 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
1952 {
1953 return;
1954 }
1955 char name[256], regtype[kDNSServiceMaxDomainName], domain[kDNSServiceMaxDomainName];
1956 get_string(&data, end, name, 256);
1957 get_string(&data, end, regtype, kDNSServiceMaxDomainName);
1958 get_string(&data, end, domain, kDNSServiceMaxDomainName);
1959 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_regservice_response: error reading result from daemon");
1960 else ((DNSServiceRegisterReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_err, name, regtype, domain, sdr->AppContext);
1961 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
1962 }
1963
DNSServiceRegister(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t PortInNetworkByteOrder,uint16_t txtLen,const void * txtRecord,DNSServiceRegisterReply callBack,void * context)1964 DNSServiceErrorType DNSSD_API DNSServiceRegister
1965 (
1966 DNSServiceRef *sdRef,
1967 DNSServiceFlags flags,
1968 uint32_t interfaceIndex,
1969 const char *name,
1970 const char *regtype,
1971 const char *domain,
1972 const char *host,
1973 uint16_t PortInNetworkByteOrder,
1974 uint16_t txtLen,
1975 const void *txtRecord,
1976 DNSServiceRegisterReply callBack,
1977 void *context
1978 )
1979 {
1980 return DNSServiceRegisterInternal(sdRef, flags, interfaceIndex, name, regtype, domain, host, PortInNetworkByteOrder, txtLen, txtRecord, NULL, callBack, context);
1981 }
1982
DNSServiceRegisterWithAttribute(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t portInNetworkByteOrder,uint16_t txtLen,const void * txtRecord,const DNSServiceAttributeRef attr,DNSServiceRegisterReply callBack,void * context)1983 DNSServiceErrorType DNSSD_API DNSServiceRegisterWithAttribute
1984 (
1985 DNSServiceRef *sdRef,
1986 DNSServiceFlags flags,
1987 uint32_t interfaceIndex,
1988 const char *name,
1989 const char *regtype,
1990 const char *domain,
1991 const char *host,
1992 uint16_t portInNetworkByteOrder,
1993 uint16_t txtLen,
1994 const void *txtRecord,
1995 const DNSServiceAttributeRef attr,
1996 DNSServiceRegisterReply callBack,
1997 void *context
1998 )
1999 {
2000 return DNSServiceRegisterInternal(sdRef, flags, interfaceIndex, name, regtype, domain, host, portInNetworkByteOrder, txtLen, txtRecord, attr, callBack, context);
2001 }
2002
DNSServiceRegisterInternal(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * name,const char * regtype,const char * domain,const char * host,uint16_t portInNetworkByteOrder,uint16_t txtLen,const void * txtRecord,const DNSServiceAttribute * attr,DNSServiceRegisterReply callBack,void * context)2003 DNSServiceErrorType DNSServiceRegisterInternal
2004 (
2005 DNSServiceRef *sdRef,
2006 DNSServiceFlags flags,
2007 uint32_t interfaceIndex,
2008 const char *name,
2009 const char *regtype,
2010 const char *domain,
2011 const char *host,
2012 uint16_t portInNetworkByteOrder,
2013 uint16_t txtLen,
2014 const void *txtRecord,
2015 const DNSServiceAttribute *attr,
2016 DNSServiceRegisterReply callBack,
2017 void *context
2018 )
2019 {
2020 uint8_t *ptr;
2021 const uint8_t *limit;
2022 size_t len;
2023 ipc_msg_hdr *hdr;
2024 DNSServiceErrorType err;
2025 union { uint16_t s; u_char b[2]; } port = { portInNetworkByteOrder };
2026 (void)attr;
2027
2028 if (!sdRef || !regtype) return kDNSServiceErr_BadParam;
2029 if (!name) name = "";
2030 if (!domain) domain = "";
2031 if (!host) host = "";
2032 if (!txtRecord) txtRecord = (void*)"";
2033
2034 // No callback must have auto-rename
2035 if (!callBack && (flags & kDNSServiceFlagsNoAutoRename)) return kDNSServiceErr_BadParam;
2036
2037 err = ConnectToServer(sdRef, flags, reg_service_request, callBack ? handle_regservice_response : NULL, (void *)callBack, context);
2038 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2039
2040 len = sizeof(DNSServiceFlags);
2041 len += sizeof(uint32_t); // interfaceIndex
2042 len += strlen(name) + strlen(regtype) + strlen(domain) + strlen(host) + 4;
2043 len += 2 * sizeof(uint16_t); // port, txtLen
2044 len += txtLen;
2045 if (attr)
2046 {
2047 if (!validate_attribute_tlvs(attr))
2048 {
2049 return kDNSServiceErr_BadParam;
2050 }
2051 len += get_required_length_for_attribute_tlvs(attr);
2052 }
2053
2054 hdr = create_hdr(reg_service_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2055 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2056 if (!callBack) hdr->ipc_flags |= IPC_FLAGS_NOREPLY;
2057
2058 limit = ptr + len;
2059 put_flags(flags, &ptr);
2060 put_uint32(interfaceIndex, &ptr);
2061 put_string(name, &ptr);
2062 put_string(regtype, &ptr);
2063 put_string(domain, &ptr);
2064 put_string(host, &ptr);
2065 *ptr++ = port.b[0];
2066 *ptr++ = port.b[1];
2067 put_uint16(txtLen, &ptr);
2068 put_rdata(txtLen, txtRecord, &ptr);
2069 if (attr)
2070 {
2071 put_attribute_tlvs(attr, hdr, &ptr, limit);
2072 }
2073
2074 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2075 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
2076 {
2077 err = kDNSServiceErr_NoError;
2078 }
2079 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2080 return err;
2081 }
2082
handle_enumeration_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)2083 static void handle_enumeration_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
2084 {
2085 char domain[kDNSServiceMaxDomainName];
2086 get_string(&data, end, domain, kDNSServiceMaxDomainName);
2087 if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_enumeration_response: error reading result from daemon");
2088 else ((DNSServiceDomainEnumReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, domain, sdr->AppContext);
2089 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2090 }
2091
DNSServiceEnumerateDomains(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,DNSServiceDomainEnumReply callBack,void * context)2092 DNSServiceErrorType DNSSD_API DNSServiceEnumerateDomains
2093 (
2094 DNSServiceRef *sdRef,
2095 DNSServiceFlags flags,
2096 uint32_t interfaceIndex,
2097 DNSServiceDomainEnumReply callBack,
2098 void *context
2099 )
2100 {
2101 uint8_t *ptr;
2102 size_t len;
2103 ipc_msg_hdr *hdr;
2104 DNSServiceErrorType err;
2105 int f1;
2106 int f2;
2107
2108 if (!sdRef || !callBack) return kDNSServiceErr_BadParam;
2109
2110 f1 = (flags & kDNSServiceFlagsBrowseDomains) != 0;
2111 f2 = (flags & kDNSServiceFlagsRegistrationDomains) != 0;
2112 if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
2113
2114 err = ConnectToServer(sdRef, flags, enumeration_request, handle_enumeration_response, (void *)callBack, context);
2115 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2116
2117 len = sizeof(DNSServiceFlags);
2118 len += sizeof(uint32_t);
2119
2120 hdr = create_hdr(enumeration_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2121 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2122
2123 put_flags(flags, &ptr);
2124 put_uint32(interfaceIndex, &ptr);
2125
2126 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2127 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2128 return err;
2129 }
2130
ConnectionResponse(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * const data,const uint8_t * const end)2131 static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *const data, const uint8_t *const end)
2132 {
2133 (void)data; // Unused
2134
2135 //printf("ConnectionResponse got %d\n", cbh->ipc_hdr.op);
2136 if (cbh->ipc_hdr.op != reg_record_reply_op && cbh->ipc_hdr.op != async_error_op)
2137 {
2138 // When using kDNSServiceFlagsShareConnection, need to search the list of associated DNSServiceOps
2139 // to find the one this response is intended for, and then call through to its ProcessReply handler.
2140 // We start with our first subordinate DNSServiceRef -- don't want to accidentally match the parent DNSServiceRef.
2141 DNSServiceOp *op = sdr->next;
2142 while (op && (op->uid.u32[0] != cbh->ipc_hdr.client_context.u32[0] || op->uid.u32[1] != cbh->ipc_hdr.client_context.u32[1]))
2143 op = op->next;
2144 // Note: We may sometimes not find a matching DNSServiceOp, in the case where the client has
2145 // cancelled the subordinate DNSServiceOp, but there are still messages in the pipeline from the daemon
2146 if (op && op->ProcessReply) op->ProcessReply(op, cbh, data, end);
2147 // WARNING: Don't touch op or sdr after this -- client may have called DNSServiceRefDeallocate
2148 return;
2149 }
2150 else
2151 {
2152 if (cbh->cb_err == kDNSServiceErr_PolicyDenied && !_should_return_noauth_error())
2153 {
2154 return;
2155 }
2156 DNSRecordRef rec;
2157 for (rec = sdr->rec; rec; rec = rec->recnext)
2158 {
2159 if (rec->uid.u32[0] == cbh->ipc_hdr.client_context.u32[0] && rec->uid.u32[1] == cbh->ipc_hdr.client_context.u32[1])
2160 break;
2161 }
2162 // The record might have been freed already and hence not an
2163 // error if the record is not found.
2164 if (!rec)
2165 {
2166 syslog(LOG_INFO, "dnssd_clientstub ConnectionResponse: Record not found");
2167 return;
2168 }
2169 if (rec->sdr != sdr)
2170 {
2171 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
2172 return;
2173 }
2174
2175 if (sdr->op == connection_request || sdr->op == connection_delegate_request)
2176 {
2177 rec->AppCallback(rec->sdr, rec, cbh->cb_flags, cbh->cb_err, rec->AppContext);
2178 }
2179 else
2180 {
2181 syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: sdr->op != connection_request");
2182 rec->AppCallback(rec->sdr, rec, 0, kDNSServiceErr_Unknown, rec->AppContext);
2183 }
2184 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2185 }
2186 }
2187
DNSServiceCreateConnection(DNSServiceRef * sdRef)2188 DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
2189 {
2190 DNSServiceErrorType err;
2191 uint8_t *ptr;
2192 size_t len = 0;
2193 ipc_msg_hdr *hdr;
2194
2195 if (!sdRef) return kDNSServiceErr_BadParam;
2196 err = ConnectToServer(sdRef, 0, connection_request, ConnectionResponse, NULL, NULL);
2197 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2198
2199 hdr = create_hdr(connection_request, &len, &ptr, 0, *sdRef);
2200 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2201
2202 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2203 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2204 return err;
2205 }
2206
2207 #if TARGET_OS_SIMULATOR // This hack is for Simulator platform only
DNSServiceCreateDelegateConnection(DNSServiceRef * sdRef,int32_t pid,uuid_t uuid)2208 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
2209 {
2210 (void) pid;
2211 (void) uuid;
2212 return DNSServiceCreateConnection(sdRef);
2213 }
2214 #endif
2215
DNSServiceSendQueuedRequestsInternal(DNSServiceRef sdr)2216 DNSServiceErrorType DNSServiceSendQueuedRequestsInternal(DNSServiceRef sdr)
2217 {
2218 iovec_t *iov;
2219 ssize_t totalLength = 0, bytesWritten;
2220 uint32_t numMsg, i;
2221 DNSRecordRef rref;
2222 DNSServiceErrorType err = kDNSServiceErr_NoError;
2223
2224 if (!sdr)
2225 {
2226 syslog(LOG_WARNING, "DNSServiceSendQueuedRequestsInternal: !sdr");
2227 return kDNSServiceErr_BadParam;
2228 }
2229 for (rref = sdr->rec, numMsg = 0; rref != NULL; rref = rref->recnext)
2230 {
2231 if(rref->msg)
2232 {
2233 numMsg++;
2234 totalLength += rref->msg->datalen + sizeof(ipc_msg_hdr);
2235 }
2236 }
2237 if (numMsg == 0)
2238 {
2239 syslog(LOG_INFO, "DNSServiceSendQueuedRequestsInternal: numMsg is 0");
2240 return kDNSServiceErr_Invalid;
2241 }
2242 iov = mdns_malloc(numMsg * sizeof(*iov));
2243 if (!iov)
2244 {
2245 return kDNSServiceErr_NoMemory;
2246 }
2247 for (rref = sdr->rec, i = 0; rref != NULL; rref = rref->recnext)
2248 {
2249 if(rref->msg)
2250 {
2251 uint32_t datalen = rref->msg->datalen;
2252 ConvertHeaderBytes(rref->msg);
2253 SETIOV(&iov[i], rref->msg, datalen + sizeof(ipc_msg_hdr));
2254 i++;
2255 }
2256 }
2257 bytesWritten = writev(sdr->sockfd, iov, numMsg);
2258 if (bytesWritten != totalLength)
2259 {
2260 syslog(LOG_WARNING,"DNSServiceSendQueuedRequestsInternal ERROR: writev(fd:%d, written:%zu, total:%zu bytes) failed, errno[%d]:%s",
2261 sdr->sockfd, bytesWritten, totalLength, errno, strerror(errno));
2262 err = kDNSServiceErr_Unknown;
2263 }
2264 else
2265 {
2266 syslog(LOG_INFO, "DNSServiceSendQueuedRequestsInternal: writev(fd:%d, numMsg:%d, %zu bytes) succeed",
2267 sdr->sockfd, numMsg, totalLength);
2268 }
2269 for (rref = sdr->rec; rref != NULL; rref = rref->recnext)
2270 {
2271 mdns_free(rref->msg);
2272 }
2273 mdns_free(iov);
2274 return err;
2275 }
2276
DNSServiceRegisterRecord(DNSServiceRef sdRef,DNSRecordRef * recordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,DNSServiceRegisterRecordReply callBack,void * context)2277 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
2278 (
2279 DNSServiceRef sdRef,
2280 DNSRecordRef *recordRef,
2281 DNSServiceFlags flags,
2282 uint32_t interfaceIndex,
2283 const char *fullname,
2284 uint16_t rrtype,
2285 uint16_t rrclass,
2286 uint16_t rdlen,
2287 const void *rdata,
2288 uint32_t ttl,
2289 DNSServiceRegisterRecordReply callBack,
2290 void *context
2291 )
2292 {
2293 return DNSServiceRegisterRecordInternal(sdRef, recordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, NULL, callBack, context);
2294 }
2295
DNSServiceRegisterRecordWithAttribute(DNSServiceRef sdRef,DNSRecordRef * recordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,const DNSServiceAttributeRef attr,DNSServiceRegisterRecordReply callBack,void * context)2296 DNSServiceErrorType DNSSD_API DNSServiceRegisterRecordWithAttribute
2297 (
2298 DNSServiceRef sdRef,
2299 DNSRecordRef *recordRef,
2300 DNSServiceFlags flags,
2301 uint32_t interfaceIndex,
2302 const char *fullname,
2303 uint16_t rrtype,
2304 uint16_t rrclass,
2305 uint16_t rdlen,
2306 const void *rdata,
2307 uint32_t ttl,
2308 const DNSServiceAttributeRef attr,
2309 DNSServiceRegisterRecordReply callBack,
2310 void *context
2311 )
2312 {
2313 return DNSServiceRegisterRecordInternal(sdRef, recordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, attr, callBack, context);
2314 }
2315
DNSServiceRegisterRecordInternal(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata,uint32_t ttl,const DNSServiceAttribute * attr,DNSServiceRegisterRecordReply callBack,void * context)2316 DNSServiceErrorType DNSServiceRegisterRecordInternal
2317 (
2318 DNSServiceRef sdRef,
2319 DNSRecordRef *RecordRef,
2320 DNSServiceFlags flags,
2321 uint32_t interfaceIndex,
2322 const char *fullname,
2323 uint16_t rrtype,
2324 uint16_t rrclass,
2325 uint16_t rdlen,
2326 const void *rdata,
2327 uint32_t ttl,
2328 const DNSServiceAttribute *attr,
2329 DNSServiceRegisterRecordReply callBack,
2330 void *context
2331 )
2332 {
2333 DNSServiceErrorType err;
2334 uint8_t *ptr;
2335 const uint8_t *limit;
2336 size_t len;
2337 ipc_msg_hdr *hdr = NULL;
2338 DNSRecordRef rref = NULL;
2339 DNSRecord **p;
2340 (void)attr;
2341
2342 // Verify that only one of the following flags is set.
2343 int f1 = (flags & kDNSServiceFlagsShared) != 0;
2344 int f2 = (flags & kDNSServiceFlagsUnique) != 0;
2345 int f3 = (flags & kDNSServiceFlagsKnownUnique) != 0;
2346 if (f1 + f2 + f3 != 1) return kDNSServiceErr_BadParam;
2347
2348 if (!sdRef || !RecordRef || !fullname || (!rdata && rdlen) || !callBack)
2349 {
2350 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with NULL parameter");
2351 return kDNSServiceErr_BadParam;
2352 }
2353
2354 if (!DNSServiceRefValid(sdRef))
2355 {
2356 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2357 return kDNSServiceErr_BadReference;
2358 }
2359
2360 if (sdRef->op != connection_request && sdRef->op != connection_delegate_request)
2361 {
2362 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRegisterRecord called with non-DNSServiceCreateConnection DNSServiceRef %p %d", sdRef, sdRef->op);
2363 return kDNSServiceErr_BadReference;
2364 }
2365
2366 *RecordRef = NULL;
2367
2368 len = sizeof(DNSServiceFlags);
2369 len += 2 * sizeof(uint32_t); // interfaceIndex, ttl
2370 len += 3 * sizeof(uint16_t); // rrtype, rrclass, rdlen
2371 len += strlen(fullname) + 1;
2372 len += rdlen;
2373 if (attr)
2374 {
2375 if (!validate_attribute_tlvs(attr))
2376 {
2377 return kDNSServiceErr_BadParam;
2378 }
2379 len += get_required_length_for_attribute_tlvs(attr);
2380 }
2381
2382 // Bump up the uid. Normally for shared operations (kDNSServiceFlagsShareConnection), this
2383 // is done in ConnectToServer. For DNSServiceRegisterRecord, ConnectToServer has already
2384 // been called. As multiple DNSServiceRegisterRecords can be multiplexed over a single
2385 // connection, we need a way to demultiplex the response so that the callback corresponding
2386 // to the right DNSServiceRegisterRecord instance can be called. Use the same mechanism that
2387 // is used by kDNSServiceFlagsShareConnection. create_hdr copies the uid value to ipc
2388 // hdr->client_context which will be returned in the ipc response.
2389 if (++sdRef->uid.u32[0] == 0)
2390 ++sdRef->uid.u32[1];
2391 //If kDNSServiceFlagsQueueRequest flag is set, do not make separate return socket.
2392 hdr = create_hdr(reg_record_request, &len, &ptr, !(flags & kDNSServiceFlagsQueueRequest), sdRef);
2393 if (!hdr) return kDNSServiceErr_NoMemory;
2394
2395 limit = ptr + len;
2396 put_flags(flags, &ptr);
2397 put_uint32(interfaceIndex, &ptr);
2398 put_string(fullname, &ptr);
2399 put_uint16(rrtype, &ptr);
2400 put_uint16(rrclass, &ptr);
2401 put_uint16(rdlen, &ptr);
2402 put_rdata(rdlen, rdata, &ptr);
2403 put_uint32(ttl, &ptr);
2404 if (attr)
2405 {
2406 put_attribute_tlvs(attr, hdr, &ptr, limit);
2407 }
2408 if (flags & kDNSServiceFlagsQueueRequest)
2409 {
2410 hdr->ipc_flags |= IPC_FLAGS_NOERRSD;
2411 }
2412 rref = mdns_calloc(1, sizeof(*rref));
2413 if (!rref) { mdns_free(hdr); return kDNSServiceErr_NoMemory; }
2414 #ifdef MEMORY_OBJECT_TRACKING
2415 extern int rref_created;
2416 rref_created++;
2417 #endif
2418 rref->AppContext = context;
2419 rref->AppCallback = callBack;
2420 rref->record_index = sdRef->max_index++;
2421 rref->sdr = sdRef;
2422 *RecordRef = rref;
2423 // Remember the uid that we are sending across so that we can match
2424 // when the response comes back.
2425 rref->uid = sdRef->uid;
2426 hdr->reg_index = rref->record_index;
2427
2428 p = &(sdRef)->rec;
2429 while (*p) p = &(*p)->recnext;
2430 *p = rref;
2431 // If kDNSServiceFlagsQueueRequest flag is set, put the hdr in linked records
2432 if (flags & kDNSServiceFlagsQueueRequest)
2433 {
2434 rref->msg = hdr;
2435 err = kDNSServiceErr_NoError;
2436 }
2437 else
2438 {
2439 err = deliver_request(hdr, sdRef); // Will free hdr for us
2440 if (err == kDNSServiceErr_NoAuth && !_should_return_noauth_error())
2441 {
2442 err = kDNSServiceErr_NoError;
2443 }
2444 }
2445 return err;
2446 }
2447
2448 // sdRef returned by DNSServiceRegister()
DNSServiceAddRecord(DNSServiceRef sdRef,DNSRecordRef * RecordRef,DNSServiceFlags flags,uint16_t rrtype,uint16_t rdlen,const void * rdata,uint32_t ttl)2449 DNSServiceErrorType DNSSD_API DNSServiceAddRecord
2450 (
2451 DNSServiceRef sdRef,
2452 DNSRecordRef *RecordRef,
2453 DNSServiceFlags flags,
2454 uint16_t rrtype,
2455 uint16_t rdlen,
2456 const void *rdata,
2457 uint32_t ttl
2458 )
2459 {
2460 ipc_msg_hdr *hdr;
2461 size_t len = 0;
2462 uint8_t *ptr;
2463 DNSRecordRef rref;
2464 DNSRecord **p;
2465
2466 if (!sdRef || !RecordRef || (!rdata && rdlen))
2467 {
2468 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL parameter");
2469 return kDNSServiceErr_BadParam;
2470 }
2471 if (sdRef->op != reg_service_request)
2472 {
2473 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with non-DNSServiceRegister DNSServiceRef %p %d", sdRef, sdRef->op);
2474 return kDNSServiceErr_BadReference;
2475 }
2476
2477 if (!DNSServiceRefValid(sdRef))
2478 {
2479 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2480 return kDNSServiceErr_BadReference;
2481 }
2482
2483 *RecordRef = NULL;
2484
2485 len += 2 * sizeof(uint16_t); // rrtype, rdlen
2486 len += rdlen;
2487 len += sizeof(uint32_t);
2488 len += sizeof(DNSServiceFlags);
2489
2490 hdr = create_hdr(add_record_request, &len, &ptr, 1, sdRef);
2491 if (!hdr) return kDNSServiceErr_NoMemory;
2492 put_flags(flags, &ptr);
2493 put_uint16(rrtype, &ptr);
2494 put_uint16(rdlen, &ptr);
2495 put_rdata(rdlen, rdata, &ptr);
2496 put_uint32(ttl, &ptr);
2497
2498 rref = mdns_calloc(1, sizeof(*rref));
2499 if (!rref) { mdns_free(hdr); return kDNSServiceErr_NoMemory; }
2500 #ifdef MEMORY_OBJECT_TRACKING
2501 extern int rref_created;
2502 rref_created++;
2503 #endif
2504 rref->record_index = sdRef->max_index++;
2505 rref->sdr = sdRef;
2506 *RecordRef = rref;
2507 hdr->reg_index = rref->record_index;
2508
2509 p = &(sdRef)->rec;
2510 while (*p) p = &(*p)->recnext;
2511 *p = rref;
2512
2513 return deliver_request(hdr, sdRef); // Will free hdr for us
2514 }
2515
DNSServiceUpdateRecordInternal(DNSServiceRef sdRef,DNSRecordRef recordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl,const DNSServiceAttributeRef attr)2516 static DNSServiceErrorType DNSServiceUpdateRecordInternal
2517 (
2518 DNSServiceRef sdRef,
2519 DNSRecordRef recordRef,
2520 DNSServiceFlags flags,
2521 uint16_t rdlen,
2522 const void *rdata,
2523 uint32_t ttl,
2524 const DNSServiceAttributeRef attr
2525 )
2526 {
2527 ipc_msg_hdr *hdr;
2528 size_t len = 0;
2529 uint8_t *ptr;
2530 const uint8_t *limit;
2531
2532 if (!sdRef || (!rdata && rdlen))
2533 {
2534 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with NULL parameter");
2535 return kDNSServiceErr_BadParam;
2536 }
2537
2538 if (!DNSServiceRefValid(sdRef))
2539 {
2540 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceUpdateRecord called with invalid DNSServiceRef %p %08X %08X", sdRef, sdRef->sockfd, sdRef->validator);
2541 return kDNSServiceErr_BadReference;
2542 }
2543
2544 // Note: RecordRef is allowed to be NULL
2545
2546 len += sizeof(uint16_t);
2547 len += rdlen;
2548 len += sizeof(uint32_t);
2549 len += sizeof(DNSServiceFlags);
2550 if (attr)
2551 {
2552 if (!validate_attribute_tlvs(attr))
2553 {
2554 return kDNSServiceErr_BadParam;
2555 }
2556 len += get_required_length_for_attribute_tlvs(attr);
2557 }
2558
2559 hdr = create_hdr(update_record_request, &len, &ptr, 1, sdRef);
2560 if (!hdr) return kDNSServiceErr_NoMemory;
2561 // This function can update records added with DNSServiceRegisterRecord or DNSServiceAddRecord. In the
2562 // former case, these records are added on a connection that was created using DNSServiceCreateConnection(), and so
2563 // they don't have a subordinate request. In the latter case, they are added on a connection that was created with
2564 // DNSServiceRegister(); if these are created with the kDNSServiceFlagsSharedConnection flag set, then they will have
2565 // a subordinate operation.
2566 // In the case where there is no subordinate operations, we need to send a UID of zero, to avoid matching any subordinate
2567 // operation that might have the same UID as the primary connection (this will be the case if there is an outstanding
2568 // subordinate request that hasn't been canceled). Failure to send a zero UID can result in this function
2569 // having no effect. Refer to rdar://93274463
2570 if (sdRef->primary == NULL)
2571 {
2572 hdr->client_context.u32[0] = 0;
2573 hdr->client_context.u32[1] = 0;
2574 }
2575 hdr->reg_index = recordRef ? recordRef->record_index : TXT_RECORD_INDEX;
2576 limit = ptr + len;
2577 put_flags(flags, &ptr);
2578 put_uint16(rdlen, &ptr);
2579 put_rdata(rdlen, rdata, &ptr);
2580 put_uint32(ttl, &ptr);
2581 if (attr)
2582 {
2583 put_attribute_tlvs(attr, hdr, &ptr, limit);
2584 }
2585 return deliver_request(hdr, sdRef); // Will free hdr for us
2586 }
2587
2588 // DNSRecordRef returned by DNSServiceRegisterRecord or DNSServiceAddRecord
DNSServiceUpdateRecord(DNSServiceRef sdRef,DNSRecordRef recordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl)2589 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecord
2590 (
2591 DNSServiceRef sdRef,
2592 DNSRecordRef recordRef,
2593 DNSServiceFlags flags,
2594 uint16_t rdlen,
2595 const void *rdata,
2596 uint32_t ttl
2597 )
2598 {
2599 return DNSServiceUpdateRecordInternal(sdRef, recordRef, flags, rdlen, rdata, ttl, NULL);
2600 }
2601
DNSServiceUpdateRecordWithAttribute(DNSServiceRef sdRef,DNSRecordRef recordRef,DNSServiceFlags flags,uint16_t rdlen,const void * rdata,uint32_t ttl,const DNSServiceAttributeRef attr)2602 DNSServiceErrorType DNSSD_API DNSServiceUpdateRecordWithAttribute
2603 (
2604 DNSServiceRef sdRef,
2605 DNSRecordRef recordRef,
2606 DNSServiceFlags flags,
2607 uint16_t rdlen,
2608 const void *rdata,
2609 uint32_t ttl,
2610 const DNSServiceAttributeRef attr
2611 )
2612 {
2613 return DNSServiceUpdateRecordInternal(sdRef, recordRef, flags, rdlen, rdata, ttl, attr);
2614 }
2615
DNSServiceRemoveRecord(DNSServiceRef sdRef,DNSRecordRef RecordRef,DNSServiceFlags flags)2616 DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
2617 (
2618 DNSServiceRef sdRef,
2619 DNSRecordRef RecordRef,
2620 DNSServiceFlags flags
2621 )
2622 {
2623 ipc_msg_hdr *hdr;
2624 size_t len = 0;
2625 uint8_t *ptr;
2626 DNSServiceErrorType err;
2627
2628 if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
2629 if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with NULL DNSRecordRef"); return kDNSServiceErr_BadParam; }
2630 if (!sdRef->max_index) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with bad DNSServiceRef"); return kDNSServiceErr_BadReference; }
2631
2632 if (!DNSServiceRefValid(sdRef))
2633 {
2634 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSServiceRef %p %08X %08X",
2635 sdRef, sdRef->sockfd, sdRef->validator);
2636 return kDNSServiceErr_BadReference;
2637 }
2638
2639 // Ensure that this rref is actually dependent on the sdref. An rref can't not be dependent on an sdref.
2640 DNSRecord **p = &sdRef->rec;
2641 while (*p && *p != RecordRef) p = &(*p)->recnext;
2642 if (*p == NULL)
2643 {
2644 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceRemoveRecord called with invalid DNSRecordRef %p %08X %08X",
2645 RecordRef, sdRef->sockfd, sdRef->validator);
2646 return kDNSServiceErr_BadReference;
2647 }
2648
2649 len += sizeof(flags);
2650 hdr = create_hdr(remove_record_request, &len, &ptr, 1, sdRef);
2651 if (!hdr) return kDNSServiceErr_NoMemory;
2652 // DNSServiceRemoveRecord can remove records added with DNSServiceRegisterRecord or DNSServiceAddRecord. In the
2653 // former case, these records are added on a connection that was created using DNSServiceCreateConnection(), and so
2654 // they don't have a subordinate request. In the latter case, they are added on a connection that was created with
2655 // DNSServiceRegister(); if these are created with the kDNSServiceFlagsSharedConnection flag set, then they will have
2656 // a subordinate operation.
2657 // In the case where there is no subordinate operation, we need to send a UID of zero, to avoid matching any subordinate
2658 // operation that might have the same UID as the primary connection (this will be the case if there is an outstanding
2659 // subordinate request that hasn't been canceled). Failure to send a zero UID can result in the DNSServiceRemoveRecord
2660 // having no effect.
2661 if (sdRef->primary == NULL)
2662 {
2663 hdr->client_context.u32[0] = 0;
2664 hdr->client_context.u32[1] = 0;
2665 }
2666 hdr->reg_index = RecordRef->record_index;
2667 put_flags(flags, &ptr);
2668 err = deliver_request(hdr, sdRef); // Will free hdr for us
2669 if (!err || err == kDNSServiceErr_BadReference)
2670 {
2671 // This RecordRef could only have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
2672 // Delink from the list before freeing
2673 *p = RecordRef->recnext;
2674 #ifdef MEMORY_OBJECT_TRACKING
2675 extern int rref_finalized;
2676 rref_finalized++;
2677 #endif
2678 mdns_free(RecordRef->msg);
2679 mdns_free(RecordRef);
2680
2681 // In the event that we got a BadReference from mDNSResponder, this means that the DNSServiceRegisterRecord
2682 // or DNSServiceAddRecord call that created the rref data structure and added it to the sdref didn't succeed
2683 // in creating a registration in the mDNSResponder process, so when we told mDNSResponder to remove it, it
2684 // didn't find anything to remove. In this case, it doesn't make sense to return an error to the caller, because
2685 // we have successfully removed the rref.
2686 err = kDNSServiceErr_NoError;
2687 }
2688 return err;
2689 }
2690
DNSServiceReconfirmRecord(DNSServiceFlags flags,uint32_t interfaceIndex,const char * fullname,uint16_t rrtype,uint16_t rrclass,uint16_t rdlen,const void * rdata)2691 DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
2692 (
2693 DNSServiceFlags flags,
2694 uint32_t interfaceIndex,
2695 const char *fullname,
2696 uint16_t rrtype,
2697 uint16_t rrclass,
2698 uint16_t rdlen,
2699 const void *rdata
2700 )
2701 {
2702 DNSServiceErrorType err;
2703 uint8_t *ptr;
2704 size_t len;
2705 ipc_msg_hdr *hdr;
2706 DNSServiceOp *tmp = NULL;
2707
2708 if (!fullname || (!rdata && rdlen)) return kDNSServiceErr_BadParam;
2709
2710 err = ConnectToServer(&tmp, flags, reconfirm_record_request, NULL, NULL, NULL);
2711 if (err) return err;
2712
2713 len = sizeof(DNSServiceFlags);
2714 len += sizeof(uint32_t);
2715 len += strlen(fullname) + 1;
2716 len += 3 * sizeof(uint16_t);
2717 len += rdlen;
2718 hdr = create_hdr(reconfirm_record_request, &len, &ptr, 0, tmp);
2719 if (!hdr) { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_NoMemory; }
2720
2721 put_flags(flags, &ptr);
2722 put_uint32(interfaceIndex, &ptr);
2723 put_string(fullname, &ptr);
2724 put_uint16(rrtype, &ptr);
2725 put_uint16(rrclass, &ptr);
2726 put_uint16(rdlen, &ptr);
2727 put_rdata(rdlen, rdata, &ptr);
2728
2729 err = deliver_request(hdr, tmp); // Will free hdr for us
2730 DNSServiceRefDeallocate(tmp);
2731 return err;
2732 }
2733
2734
handle_port_mapping_response(DNSServiceOp * const sdr,const CallbackHeader * const cbh,const uint8_t * data,const uint8_t * const end)2735 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const uint8_t *data, const uint8_t *const end)
2736 {
2737 union { uint32_t l; u_char b[4]; } addr;
2738 uint8_t protocol;
2739 union { uint16_t s; u_char b[2]; } internalPort;
2740 union { uint16_t s; u_char b[2]; } externalPort;
2741 uint32_t ttl;
2742
2743 if (!data || data + 13 > end) goto fail;
2744
2745 addr.b[0] = *data++;
2746 addr.b[1] = *data++;
2747 addr.b[2] = *data++;
2748 addr.b[3] = *data++;
2749 protocol = *data++;
2750 internalPort.b[0] = *data++;
2751 internalPort.b[1] = *data++;
2752 externalPort.b[0] = *data++;
2753 externalPort.b[1] = *data++;
2754 ttl = get_uint32(&data, end);
2755 if (!data) goto fail;
2756
2757 ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
2758 return;
2759 // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
2760
2761 fail :
2762 syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
2763 }
2764
DNSServiceNATPortMappingCreate(DNSServiceRef * sdRef,DNSServiceFlags flags,uint32_t interfaceIndex,uint32_t protocol,uint16_t internalPortInNetworkByteOrder,uint16_t externalPortInNetworkByteOrder,uint32_t ttl,DNSServiceNATPortMappingReply callBack,void * context)2765 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
2766 (
2767 DNSServiceRef *sdRef,
2768 DNSServiceFlags flags,
2769 uint32_t interfaceIndex,
2770 uint32_t protocol, /* TCP and/or UDP */
2771 uint16_t internalPortInNetworkByteOrder,
2772 uint16_t externalPortInNetworkByteOrder,
2773 uint32_t ttl, /* time to live in seconds */
2774 DNSServiceNATPortMappingReply callBack,
2775 void *context /* may be NULL */
2776 )
2777 {
2778 uint8_t *ptr;
2779 size_t len;
2780 ipc_msg_hdr *hdr;
2781 union { uint16_t s; u_char b[2]; } internalPort = { internalPortInNetworkByteOrder };
2782 union { uint16_t s; u_char b[2]; } externalPort = { externalPortInNetworkByteOrder };
2783
2784 DNSServiceErrorType err = ConnectToServer(sdRef, flags, port_mapping_request, handle_port_mapping_response, (void *)callBack, context);
2785 if (err) return err; // On error ConnectToServer leaves *sdRef set to NULL
2786
2787 len = sizeof(flags);
2788 len += sizeof(interfaceIndex);
2789 len += sizeof(protocol);
2790 len += sizeof(internalPort);
2791 len += sizeof(externalPort);
2792 len += sizeof(ttl);
2793
2794 hdr = create_hdr(port_mapping_request, &len, &ptr, (*sdRef)->primary ? 1 : 0, *sdRef);
2795 if (!hdr) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; return kDNSServiceErr_NoMemory; }
2796
2797 put_flags(flags, &ptr);
2798 put_uint32(interfaceIndex, &ptr);
2799 put_uint32(protocol, &ptr);
2800 *ptr++ = internalPort.b[0];
2801 *ptr++ = internalPort.b[1];
2802 *ptr++ = externalPort.b[0];
2803 *ptr++ = externalPort.b[1];
2804 put_uint32(ttl, &ptr);
2805
2806 err = deliver_request(hdr, *sdRef); // Will free hdr for us
2807 if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
2808 return err;
2809 }
2810
2811 #if _DNS_SD_LIBDISPATCH
DNSServiceSetDispatchQueue(DNSServiceRef service,dispatch_queue_t queue)2812 DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
2813 (
2814 DNSServiceRef service,
2815 dispatch_queue_t queue
2816 )
2817 {
2818 int dnssd_fd = DNSServiceRefSockFD(service);
2819 if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
2820 if (!queue)
2821 {
2822 syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
2823 return kDNSServiceErr_BadParam;
2824 }
2825 if (service->disp_queue)
2826 {
2827 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
2828 return kDNSServiceErr_BadParam;
2829 }
2830 if (service->disp_source)
2831 {
2832 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch source set already");
2833 return kDNSServiceErr_BadParam;
2834 }
2835 service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
2836 if (!service->disp_source)
2837 {
2838 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch_source_create failed");
2839 return kDNSServiceErr_NoMemory;
2840 }
2841 service->disp_queue = queue;
2842 dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
2843 dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
2844 dispatch_resume(service->disp_source);
2845 return kDNSServiceErr_NoError;
2846 }
2847 #endif // _DNS_SD_LIBDISPATCH
2848
2849 #if !defined(_WIN32)
2850
SleepKeepaliveCallback(DNSServiceRef sdRef,DNSRecordRef rec,const DNSServiceFlags flags,DNSServiceErrorType errorCode,void * context)2851 static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef rec, const DNSServiceFlags flags,
2852 DNSServiceErrorType errorCode, void *context)
2853 {
2854 SleepKAContext *ka = (SleepKAContext *)context;
2855 (void)rec; // Unused
2856 (void)flags; // Unused
2857
2858 if (sdRef->kacontext != context)
2859 syslog(LOG_WARNING, "dnssd_clientstub SleepKeepaliveCallback context mismatch");
2860
2861 if (ka->AppCallback)
2862 ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
2863 }
2864
2865 static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr
2866 (
2867 DNSServiceRef * sdRef,
2868 DNSServiceFlags flags,
2869 const struct sockaddr * localAddr,
2870 const struct sockaddr * remoteAddr,
2871 unsigned int timeout,
2872 DNSServiceSleepKeepaliveReply callBack,
2873 void * context
2874 );
2875
DNSServiceSleepKeepalive(DNSServiceRef * sdRef,DNSServiceFlags flags,int fd,unsigned int timeout,DNSServiceSleepKeepaliveReply callBack,void * context)2876 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
2877 (
2878 DNSServiceRef *sdRef,
2879 DNSServiceFlags flags,
2880 int fd,
2881 unsigned int timeout,
2882 DNSServiceSleepKeepaliveReply callBack,
2883 void *context
2884 )
2885 {
2886 struct sockaddr_storage lss;
2887 struct sockaddr_storage rss;
2888 socklen_t len1, len2;
2889
2890 len1 = sizeof(lss);
2891 if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
2892 {
2893 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getsockname %d\n", errno);
2894 return kDNSServiceErr_BadParam;
2895 }
2896
2897 len2 = sizeof(rss);
2898 if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
2899 {
2900 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getpeername %d\n", errno);
2901 return kDNSServiceErr_BadParam;
2902 }
2903
2904 if (len1 != len2)
2905 {
2906 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same");
2907 return kDNSServiceErr_Unknown;
2908 }
2909 return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, (const struct sockaddr *)&lss, (const struct sockaddr *)&rss,
2910 timeout, callBack, context);
2911 }
2912
DNSServiceSleepKeepalive_sockaddr(DNSServiceRef * sdRef,DNSServiceFlags flags,const struct sockaddr * localAddr,const struct sockaddr * remoteAddr,unsigned int timeout,DNSServiceSleepKeepaliveReply callBack,void * context)2913 DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive_sockaddr
2914 (
2915 DNSServiceRef * sdRef,
2916 DNSServiceFlags flags,
2917 const struct sockaddr * localAddr,
2918 const struct sockaddr * remoteAddr,
2919 unsigned int timeout,
2920 DNSServiceSleepKeepaliveReply callBack,
2921 void * context
2922 )
2923 {
2924 return _DNSServiceSleepKeepalive_sockaddr(sdRef, flags, localAddr, remoteAddr, timeout, callBack, context );
2925 }
2926
_DNSServiceSleepKeepalive_sockaddr(DNSServiceRef * sdRef,DNSServiceFlags flags,const struct sockaddr * localAddr,const struct sockaddr * remoteAddr,unsigned int timeout,DNSServiceSleepKeepaliveReply callBack,void * context)2927 static DNSServiceErrorType _DNSServiceSleepKeepalive_sockaddr
2928 (
2929 DNSServiceRef * sdRef,
2930 DNSServiceFlags flags,
2931 const struct sockaddr * localAddr,
2932 const struct sockaddr * remoteAddr,
2933 unsigned int timeout,
2934 DNSServiceSleepKeepaliveReply callBack,
2935 void * context
2936 )
2937 {
2938 char source_str[INET6_ADDRSTRLEN];
2939 char target_str[INET6_ADDRSTRLEN];
2940 unsigned int len, proxyreclen;
2941 char buf[256];
2942 DNSServiceErrorType err;
2943 DNSRecordRef record = NULL;
2944 char name[10];
2945 char recname[128];
2946 SleepKAContext *ka;
2947 unsigned int i, unique;
2948
2949 (void) flags; //unused
2950 if (!timeout) return kDNSServiceErr_BadParam;
2951
2952 unique = 0;
2953 if ((localAddr->sa_family == AF_INET) && (remoteAddr->sa_family == AF_INET))
2954 {
2955 const struct sockaddr_in *sl = (const struct sockaddr_in *)localAddr;
2956 const struct sockaddr_in *sr = (const struct sockaddr_in *)remoteAddr;
2957 const unsigned char *ptr = (const unsigned char *)&sl->sin_addr;
2958
2959 if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
2960 {
2961 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote info failed %d", errno);
2962 return kDNSServiceErr_Unknown;
2963 }
2964 if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
2965 {
2966 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local info failed %d", errno);
2967 return kDNSServiceErr_Unknown;
2968 }
2969 // Sum of all bytes in the local address and port should result in a unique
2970 // number in the local network
2971 for (i = 0; i < sizeof(struct in_addr); i++)
2972 unique += ptr[i];
2973 unique += sl->sin_port;
2974 len = snprintf(buf+1, sizeof(buf) - 1, "t=%u h=%s d=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl->sin_port), ntohs(sr->sin_port));
2975 }
2976 else if ((localAddr->sa_family == AF_INET6) && (remoteAddr->sa_family == AF_INET6))
2977 {
2978 const struct sockaddr_in6 *sl6 = (const struct sockaddr_in6 *)localAddr;
2979 const struct sockaddr_in6 *sr6 = (const struct sockaddr_in6 *)remoteAddr;
2980 const unsigned char *ptr = (const unsigned char *)&sl6->sin6_addr;
2981
2982 if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
2983 {
2984 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote6 info failed %d", errno);
2985 return kDNSServiceErr_Unknown;
2986 }
2987 if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
2988 {
2989 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local6 info failed %d", errno);
2990 return kDNSServiceErr_Unknown;
2991 }
2992 for (i = 0; i < sizeof(struct in6_addr); i++)
2993 unique += ptr[i];
2994 unique += sl6->sin6_port;
2995 len = snprintf(buf+1, sizeof(buf) - 1, "t=%u H=%s D=%s l=%u r=%u", timeout, source_str, target_str, ntohs(sl6->sin6_port), ntohs(sr6->sin6_port));
2996 }
2997 else
2998 {
2999 return kDNSServiceErr_BadParam;
3000 }
3001
3002 if (len >= (sizeof(buf) - 1))
3003 {
3004 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit local/remote info");
3005 return kDNSServiceErr_Unknown;
3006 }
3007 // Include the NULL byte also in the first byte. The total length of the record includes the
3008 // first byte also.
3009 buf[0] = len + 1;
3010 proxyreclen = len + 2;
3011
3012 len = snprintf(name, sizeof(name), "%u", unique);
3013 if (len >= sizeof(name))
3014 {
3015 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit unique");
3016 return kDNSServiceErr_Unknown;
3017 }
3018
3019 len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
3020 if (len >= sizeof(recname))
3021 {
3022 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit name");
3023 return kDNSServiceErr_Unknown;
3024 }
3025
3026 ka = mdns_malloc(sizeof(SleepKAContext));
3027 if (!ka) return kDNSServiceErr_NoMemory;
3028 ka->AppCallback = (DNSServiceSleepKeepaliveReply*)callBack;
3029 ka->AppContext = context;
3030
3031 err = DNSServiceCreateConnection(sdRef);
3032 if (err)
3033 {
3034 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
3035 mdns_free(ka);
3036 return err;
3037 }
3038
3039 // we don't care about the "record". When sdRef gets deallocated later, it will be freed too
3040 err = DNSServiceRegisterRecord(*sdRef, &record, kDNSServiceFlagsUnique, 0, recname,
3041 kDNSServiceType_NULL, kDNSServiceClass_IN, proxyreclen, buf, kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
3042 if (err)
3043 {
3044 syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
3045 mdns_free(ka);
3046 return err;
3047 }
3048 (*sdRef)->kacontext = ka;
3049 return kDNSServiceErr_NoError;
3050 }
3051 #endif
3052